Beispiel #1
0
/*!
 * Обработка запроса пользователя на создание нового фида.
 *
 * Эта функция вызывается \b post запросом содержащим только имя фида.
 */
FeedReply NodeFeeds::add()
{
  FeedReply reply(Notice::OK);
  const QString &name = m_packet->text();
  if (name.contains(LC('*')) || name.contains(LC('/')) || name.contains(LC(' ')))
    return Notice::BadRequest;

  FeedPtr feed = m_channel->feed(name, false);
  if (!feed) {
    feed = m_channel->feed(name, true, false);
    if (!feed)
      return Notice::InternalError;

    feed->head().acl().add(m_user->id());
    reply.status = FeedStorage::save(feed);
  }
  else
    FeedStorage::clone(feed);

  reply.status = FeedStorage::save(feed);
  if (reply.status == Notice::OK)
    reply.date = feed->head().date();

  return reply;
}
Beispiel #2
0
/*!
 * Определение доступных прав пользователя, для определения какие действия над сообщением возможны.
 */
int HistoryChatView::permissions(const MessageRecord &record) const
{
  if (!record.id)
    return NoPermissions;

  FeedPtr messages = ChatClient::server()->feed(FEED_NAME_MESSAGES, false);
  if (!messages)
    return NoPermissions;

  const QVariantMap data = messages->data();
  const int flags        = data.value(MESSAGES_FEED_EDITABLE_KEY, DefaultEditFlags).toInt();
  const bool timeout     = (qAbs(ChatClient::date() - record.date) / 1000) > data.value(MESSAGES_FEED_TIMEOUT_KEY, DefaultTimeOut).toInt();

  if (record.senderId == ChatClient::id() && (flags & SelfEdit) && !timeout)
    return Remove | Modify;

  if (ChatId(record.destId).type() != ChatId::ChannelId)
    return NoPermissions;

  const int acl = ClientFeeds::match(ChatClient::channels()->get(record.destId), ChatClient::channel());
  if ((acl & Acl::SpecialWrite) || (acl & Acl::Edit)) {
    int out = 0;
    if (flags & ModeratorRemove) out |= Remove;
    if (flags & ModeratorEdit)   out |= Modify;

    return out;
  }

  return NoPermissions;
}
Beispiel #3
0
bool ProfileField::apply(const QVariant &value)
{
  FeedPtr feed = ChatClient::channel()->feed(FEED_NAME_PROFILE, false);
  if (!feed)
    return false;

  if (feed->data().value(m_field) == value)
    return false;

  return ClientFeeds::post(ChatClient::id(), FEED_NAME_PROFILE + LC('/') + m_field, value, Feed::Echo | Feed::Share | Feed::Broadcast);
}
Beispiel #4
0
/*!
 * Переопределение проверки прав доступа.
 *
 * Этот фид использует права доступа фида FEED_ACL.
 */
bool NodeInfoFeed::can(Channel *channel, int acl) const
{
  if (!channel && acl != Acl::Read)
    return false;

  FeedPtr feed = m_header.channel()->feed(FEED_NAME_ACL, false, false);
  if (feed)
    return feed->can(channel, acl);

  return Feed::can(channel, acl);
}
Beispiel #5
0
/*!
 * Служебная функция получения фида.
 *
 * На фид установляется маска прав доступа \p mask и если фид не существует добавляется владелец фида.
 */
FeedPtr Hosts::feed(const QString &name, int mask) const
{
  FeedPtr feed = m_channel->feed(name, false);
  if (!feed) {
    feed = m_channel->feed(name, true, false);
    feed->head().acl().add(m_channel->id());
  }

  feed->head().acl().setMask(mask);
  return feed;
}
Beispiel #6
0
void ProfileField::reload()
{
  FeedPtr feed = ChatClient::channel()->feed(FEED_NAME_PROFILE, false);
  if (!feed)
    return;

  QVariant data = feed->data().value(m_field);
  if (data.isNull())
    return;

  setData(data);
}
Beispiel #7
0
/*!
 * Чтение нового входящего сообщения.
 */
bool NodeMessages::read(PacketReader *reader)
{
  if (ChatId(reader->sender()).type() != ChatId::UserId)
    return cleanup();

  m_sender = Ch::channel(reader->sender(), ChatId::UserId);
  if (!m_sender)
    return cleanup();

  MessageNotice packet(m_type, reader);
  m_packet          = &packet;
  const qint64 date = m_packet->date();

  FeedEvent *event = createEvent();
  if (event->status != Notice::OK) {
    reject(event->status);
    FeedEvents::start(event);
    return cleanup();
  }

  if (packet.direction() == Notice::Internal) {
    if (m_packet->command() == LS("ping"))
      pong(date);

    Core::i()->route(m_dest);
    delete event;
    return cleanup();
  }

  FeedPtr feed  = m_dest->feed(FEED_NAME_MESSAGES, true, false);
  event->diffTo = event->date;
  event->date   = m_packet->date();

  if (m_dest->type() == ChatId::UserId && m_dest->status().value() == Status::Offline) {
    event->status = Notice::ChannelOffline;
    reject(event->status);

    NodeMessagesDB::add(packet, event->status);
    Ch::gc(m_dest);
  }
  else {
    if (feed->get(MESSAGES_FEED_LOGGING_KEY).status == Notice::OK)
      NodeMessagesDB::add(packet);

    Core::i()->route(m_dest);
  }

  FeedStorage::save(feed, m_packet->date());
  FeedEvents::start(event);
  return cleanup();
}
Beispiel #8
0
/*!
 * Фиксация события обновления фида \b hosts и отправка уведомления об этом.
 *
 * \param host   Информация о подключении.
 * \param method \b post если пользователь подключился или \b put если отключился.
 * \param socket Номер сокета подключения.
 */
void Hosts::updateHostsFeed(HostInfo host, const QString &method, quint64 socket)
{
  m_date           = DateTime::utc();
  host->date       = m_date;

  FeedPtr hosts    = feed();
  FeedEvent *event = new FeedEvent(m_channel->id(), m_channel->id(), method);
  event->name      = FEED_NAME_HOSTS;
  event->diffTo    = hosts->head().date();
  event->date      = m_date;
  event->status    = Notice::OK;
  event->path      = SimpleID::encode(host->hostId);
  event->socket    = socket;

  DataBase::add(host);
  FeedStorage::save(feed(), m_date);
  FeedEvents::start(event);
}
Beispiel #9
0
/*!
 * Универсальный метод для отдачи тела фида.
 */
bool FeedHandler::serveFeed(ChatChannel channel, const QString &feedName)
{
  if (!ifMethodAllowed())
    return true;

  if (!channel || !channel->feeds().all().contains(feedName)) {
    setNoStore();
    m_response->writeHead(Tufao::HttpServerResponse::NOT_FOUND);
    m_response->end();
    return true;
  }

  FeedPtr feed = channel->feed(feedName);
  qint64 date  = feed->head().date();

  RestReplyCache &cache = m_cache[channel->id() + feedName.toUtf8()];
  if (cache.date != date) {
    cache.date = date;
    cache.etag = etag(date, m_path.toUtf8());

    cache.body = JSON::generate(feed->feed());
  }

  setLastModified(date);
  setETag(cache.etag);
  setNoCache();

  if (!ifModified(cache.etag)) {
    m_response->writeHead(Tufao::HttpServerResponse::NOT_MODIFIED);
    m_response->end();
    return true;
  }

  m_response->writeHead(Tufao::HttpServerResponse::OK);
  if (m_request->method() != "HEAD") {
    setContentLength(cache.body.size());
    m_response->end(cache.body);
  }
  else
    m_response->end();

  return true;
}
Beispiel #10
0
ChannelIndexData::ChannelIndexData(ChatChannel channel)
  : count(0)
  , options(NoOptions)
  , visibility(0)
  , name(channel->name())
{
  FeedPtr feed = channel->feed(FEED_NAME_INFO, false);
  if (!feed)
    return;

  visibility = feed->data().value(INFO_FEED_VISIBILITY_KEY, 0).toInt();
  if (visibility < 0)
    return;

  if (channel->permanent())
    options |= Permanent;

  id    = channel->id();
  count = channel->channels().size();
  title = feed->data().value(INFO_FEED_TITLE_KEY).toMap().value(INFO_FEED_TEXT_KEY).toString();

  if (feed->data().value(INFO_FEED_PINNED_KEY, false).toBool())
    options |= Pinned;

  FeedPtr acl = channel->feed(FEED_NAME_ACL, false);
  if (acl && AclValue::match(acl.data(), 0) == 0)
    options |= Private;
}
Beispiel #11
0
/*!
 * Фильтрация сообщения.
 *
 * \return Notice::OK если всё в порядке или другое значение, если сообщение должно быть отклонено.
 */
int NodeMessages::filter()
{
  if (!m_dest)
    return Notice::NotFound;

  if (m_dest->type() == ChatId::ServerId)
    return Notice::BadRequest;

  if (m_dest->type() == ChatId::ChannelId && !m_dest->channels().contains(m_sender->id()))
    return Notice::BadRequest;

  if (!m_dest->canWrite(m_sender))
    return Notice::Forbidden;

  if (m_dest->type() == ChatId::ChannelId) {
    const FeedPtr feed = m_dest->feed(FEED_NAME_INFO, true, false);
    if (m_packet->command() == LS("image") && !feed->data().value(INFO_FEED_IMAGES_KEY, true).toBool())
      return Notice::Forbidden;
  }

  return Notice::OK;
}
Beispiel #12
0
/*!
 * Фиксация события обновления фида \b user и отправка уведомления об этом.
 */
void Hosts::updateUserFeed(HostInfo host, const QString &method, quint64 socket)
{
  FeedPtr user     = this->user();
  FeedEvent *event = new FeedEvent(m_channel->id(), m_channel->id(), method);

  if (!user->head().f().isEmpty()) {
    event->broadcast = Sockets::all(Ch::channel(m_channel->id()), true);

    if (method == FEED_METHOD_POST)
      event->broadcast.removeAll(socket);
  }

  event->name      = FEED_NAME_USER;
  event->diffTo    = user->head().date();
  event->date      = m_date;
  event->status    = Notice::OK;
  event->path      = SimpleID::encode(host->hostId);
  event->socket    = socket;

  user->data()[LS("last")] = event->path;

  FeedStorage::save(user, m_date);
  FeedEvents::start(event);
}
Beispiel #13
0
inline bool FeedMergeGroup::addFeed(const FeedPtr& feed) {
  if (feed->miniMergeType() == FeedMergeReplace) {
    _feedList.push_front(feed);
    while (_feedList.front()->feed != _feedList.back()->feed) {
      _feedList.pop_back();
    }
    return updateWeight();
  }
  // for append --
  _feedList.push_front(feed);
  for (FeedList::iterator it = ++_feedList.begin(); it != _feedList.end();) {
    if ((*it)->isValid()) {
      ++it;
    } else {
      it = _feedList.erase(it);
    }
  }
  if (_feedList.size() > 5) {
    _feedList.pop_back();
  }
  return updateWeight();
}
Beispiel #14
0
void UserFeedSet::_addFeed(const FeedPtr& feed, const FeedConfigPtr& config) {
  //	MCE_DEBUG("UserFeedSet::_addFeed  "<<"feed="<<feed->feed<<" merge="<<feed->merge);
  StypeMergeIndex& index = _mergeGroupSet.get<0> ();
  StypeMergeIndex::iterator it = index.find(boost::make_tuple(
      feed->smallType(), feed->merge));
  if (it != index.end()) {
    MCE_DEBUG("UserFeedSet::addFeed --> find in map");
    FeedMergeGroupPtr g = (*it);

    if (config && config->updateTime == 0) {
      feed->time = (*it)->timestamp();
    }

    g->addFeed(feed);
    index.replace(it, g);
  } else {
    MCE_DEBUG("UserFeedSet::addFeed --> not in map");
    FeedMergeGroupPtr g = new FeedMergeGroup(feed);
    _mergeGroupSet.insert(g);
  }
  _miniTime = _miniTime < feed->time ? _miniTime : feed->time;

}
Beispiel #15
0
/*!
 * Базовая функция совершения операции над фидом.
 *
 * \param channel Канал владелец фида.
 * \param method  Метод \sa Methods.
 * \param name    Имя фида с опциональным путём запроса.
 * \param sender  Канал создавший запрос.
 * \param json    Данные запроса.
 */
FeedReply FeedsCore::request(ServerChannel *channel, const QString &method, const QString &name, ServerChannel *sender, const QVariantMap &json)
{
  if (!channel || !sender)
    return Notice::InternalError;

  const QPair<QString, QString> split = FeedNotice::split(name);
  FeedPtr feed = channel->feed(split.first, false);
  if (!feed)
    return Notice::NotFound;

  FeedReply reply(Notice::InternalError);
  const int cmd    = methodToInt(method);
  FeedEvent *event = new FeedEvent(channel->id(), sender->id(), method);
  event->request   = json;
  event->name      = split.first;
  event->path      = split.second;
  event->date      = feed->head().date();

  if (!feed->can(sender, Acl::Read))
    return done(event, Notice::Forbidden);

  if (cmd != Get && !feed->can(sender, Acl::Write))
    return done(event, Notice::Forbidden);

  switch (cmd) {
    case Get:
      reply = feed->get(event->path, json, sender);
      break;

    case Post:
      reply = feed->post(event->path, json, sender);
      break;

    case Put:
      reply = feed->put(event->path, json, sender);
      break;

    case Delete:
      reply = feed->del(event->path, sender);
      break;
  }

  if (cmd != Get && reply.status == Notice::OK) {
    const int options = json.value(FEED_KEY_OPTIONS).toInt();
    event->diffTo     = event->date;
    event->date       = reply.date;

    if (reply.date)
      FeedStorage::save(feed, reply.date);

    if (options & Feed::Broadcast) {
      if (channel->type() == SimpleID::ServerId) {
        const QList<QByteArray> channels = m_self->m_subscription.value(event->name);
        QList<quint64> sockets;

        foreach (const QByteArray &id, channels) {
          ChatChannel user = Ch::channel(id, SimpleID::UserId, false);
          if (user)
            Sockets::merge(sockets, user->sockets());
        }

        event->broadcast = sockets;
      }
      else
        event->broadcast = Sockets::channel(channel);
    }