func UpdatePresence(u *url.URL, h http.Header, participant *models.ChannelParticipant, context *models.Context) (int, http.Header, interface{}, error) { query := context.OverrideQuery(request.GetQuery(u)) participant.ChannelId = query.Id // only requester can update their last seen date participant.AccountId = query.AccountId if err := checkChannelPrerequisites( query.Id, query.AccountId, []*models.ChannelParticipant{participant}, ); err != nil { return response.NewBadRequest(err) } // @todo add a new function into participant just // for updating with lastSeenDate if err := participant.FetchParticipant(); err != nil { return response.NewBadRequest(err) } // glance the channel if err := participant.Glance(); err != nil { return response.NewBadRequest(err) } return response.NewOK(participant) }
func FetchPostCount(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { query := request.GetQuery(u) query = context.OverrideQuery(query) accountId, err := request.GetId(u) if err != nil { return response.NewBadRequest(err) } c, err := models.Cache.Channel.ByGroupName(query.GroupName) if err != nil { return response.NewBadRequest(err) } // fetch user post count in koding channel q := request.NewQuery() q.AccountId = accountId q.Type = models.ChannelMessage_TYPE_POST q.GroupChannelId = c.Id cm := models.NewChannelMessage() count, err := cm.FetchTotalMessageCount(q) if err != nil { return response.NewBadRequest(err) } res := new(models.CountResponse) res.TotalCount = count return response.NewOK(res) }
func (s *SneakerS3) Get(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { pathName := u.Query().Get("pathName") logger := s.createLogger(context, "Get", pathName, http.StatusBadRequest) if pathName == "" { return response.NewBadRequestWithLogger(logger, ErrPathNotFound) } if !context.IsLoggedIn() { return response.NewBadRequestWithLogger(logger, models.ErrNotLoggedIn) } downArray := []string{pathName} down, err := s.Manager.Download(downArray) if err != nil { return response.NewBadRequestWithLogger(logger, err) } if down[pathName] == nil { return response.NewBadRequestWithLogger(logger, ErrPathContentNotFound) } var kv KeyValue downX := bytes.NewReader(down[pathName]) if err := json.NewDecoder(downX).Decode(&kv); err != nil { return response.NewBadRequestWithLogger(logger, err) } logger = s.createLogger(context, "Get", pathName, http.StatusOK) logger.Info("") return response.NewOK(kv) }
// Update modifies account data to the lates version by default all requests // coming to this handler are trusted & validity of the parameters are not // checked. // func Update(u *url.URL, h http.Header, req *models.Account) (int, http.Header, interface{}, error) { accountId, err := request.GetURIInt64(u, "id") if err != nil { return response.NewBadRequest(err) } if accountId == 0 { return response.NewBadRequest(models.ErrAccountIdIsNotSet) } acc := models.NewAccount() if err := acc.ById(accountId); err != nil { return response.NewBadRequest(err) } acc.Nick = req.Nick if err := models.ValidateAccount(acc); err != nil { if err != models.ErrGuestsAreNotAllowed { return response.NewBadRequest(err) } } acc.Settings = req.Settings if err := acc.Update(); err != nil { return response.NewBadRequest(err) } return response.NewOK(acc) }
func Update(u *url.URL, h http.Header, req *models.Channel, c *models.Context) (int, http.Header, interface{}, error) { if !c.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } id, err := request.GetURIInt64(u, "id") if err != nil { return response.NewBadRequest(err) } req.Id = id if req.Id == 0 { return response.NewBadRequest(err) } existingOne, err := models.Cache.Channel.ById(id) if err != nil { return response.NewBadRequest(err) } participant, err := existingOne.IsParticipant(c.Client.Account.Id) if err != nil { return response.NewBadRequest(err) } if !participant { return response.NewBadRequest(models.ErrAccountIsNotParticipant) } // if user is participant in the channel, then user can update only purpose of the channel // other fields cannot be updated by participant or anyone else. Only creator can update // purpose and other fields of the channel if participant { if req.Purpose != "" { existingOne.Purpose = req.Purpose } } // if user is the creator of the channel, then can update all fields of the channel if existingOne.CreatorId == c.Client.Account.Id { if req.Name != "" { existingOne.Name = req.Name } // some of the channels stores sparse data existingOne.Payload = req.Payload } // update channel if err := existingOne.Update(); err != nil { return response.NewBadRequest(err) } // generate container data cc := models.NewChannelContainer() if err := cc.PopulateWith(*existingOne, c.Client.Account.Id); err != nil { return response.NewBadRequest(err) } return response.NewOK(cc) }
func Count(u *url.URL, h http.Header, _ interface{}, ctx *models.Context) (int, http.Header, interface{}, error) { // check if user logged in or not if !ctx.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } q := request.GetQuery(u) qry := ctx.OverrideQuery(q) query := getUserChannelsQuery(qry) // add exempt clause if needed if !q.ShowExempt { query = query.Where("api.channel.meta_bits = ?", models.Safe) } var count int query = query.Count(&count) if query.Error != nil { return response.NewBadRequest(query.Error) } res := new(models.CountResponse) res.TotalCount = count return response.NewOK(res) }
func Register(u *url.URL, h http.Header, req *models.Account) (int, http.Header, interface{}, error) { if err := req.FetchOrCreate(); err != nil { return response.NewBadRequest(err) } return response.NewOK(req) }
func RemoveMulti(u *url.URL, h http.Header, participants []*models.ChannelParticipant, context *models.Context) (int, http.Header, interface{}, error) { query := context.OverrideQuery(request.GetQuery(u)) if err := checkChannelPrerequisites( query.Id, query.AccountId, participants, ); err != nil { return response.NewBadRequest(err) } ch := models.NewChannel() err := ch.ById(query.Id) if err != nil { return response.NewBadRequest(err) } if ch.TypeConstant == models.Channel_TYPE_BOT { return response.NewBadRequest(errors.New("can not remove participants for bot channel")) } isAdmin, err := modelhelper.IsAdmin(context.Client.Account.Nick, context.GroupName) if err != nil { return response.NewBadRequest(err) } for i := range participants { // if the requester is trying to remove some other user than themselves, and they are not the channel owner // return bad request if participants[i].AccountId != query.AccountId && query.AccountId != ch.CreatorId { if !isAdmin { return response.NewBadRequest(fmt.Errorf("User is not allowed to kick other users")) } } participants[i].ChannelId = query.Id if err := participants[i].Delete(); err != nil { return response.NewBadRequest(err) } if err := addLeaveActivity(query.Id, query.AccountId, participants[i]); err != nil { return response.NewBadRequest(err) } } // this could be moved into another worker, but i did not want to create a new worker that will be used // for just a few times go func() { if err := DeleteDesertedChannelMessages(query.Id); err != nil { runner.MustGetLogger().Error("Could not delete channel messages: %s", err.Error()) } }() go notifyParticipants(ch, models.ChannelParticipant_Removed_From_Channel_Event, participants) return response.NewOK(participants) }
func AddMulti(u *url.URL, h http.Header, participants []*models.ChannelParticipant, context *models.Context) (int, http.Header, interface{}, error) { query := context.OverrideQuery(request.GetQuery(u)) if err := checkChannelPrerequisites( query.Id, query.AccountId, participants, ); err != nil { return response.NewBadRequest(err) } ch := models.NewChannel() err := ch.ById(query.Id) if err != nil { return response.NewBadRequest(err) } if ch.TypeConstant == models.Channel_TYPE_BOT { return response.NewBadRequest(errors.New("can not add participants for bot channel")) } for i := range participants { participant := models.NewChannelParticipant() participant.ChannelId = query.Id // prevent duplicate participant addition isParticipant, err := participant.IsParticipant(participants[i].AccountId) if err != nil { return response.NewBadRequest(err) } if isParticipant { continue } participant.AccountId = participants[i].AccountId //We can add users with requestpending status if participants[i].StatusConstant != "" { participant.StatusConstant = participants[i].StatusConstant } if err := participant.Create(); err != nil { return response.NewBadRequest(err) } participants[i] = participant if err := addJoinActivity(query.Id, participant, query.AccountId); err != nil { return response.NewBadRequest(err) } } go notifyParticipants(ch, models.ChannelParticipant_Added_To_Channel_Event, participants) return response.NewOK(participants) }
func GetAccountFromSession(u *url.URL, h http.Header, _ interface{}, c *models.Context) (int, http.Header, interface{}, error) { if c.Client == nil || c.Client.Account == nil { return response.NewNotFound() } res := map[string]interface{}{ "id": strconv.FormatInt(c.Client.Account.Id, 10), "nick": c.Client.Account.Nick, "token": c.Client.Account.Token, } return response.NewOK(res) }
func CheckParticipation(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { q := context.OverrideQuery(request.GetQuery(u)) if context.Client != nil && context.Client.Account != nil { q.AccountId = context.Client.Account.Id } if q.Type == "" || q.AccountId == 0 { return response.NewBadRequest(errors.New("type or accountid is not set")) } channel, err := models.NewChannel().ByName(q) if err != nil { return response.NewBadRequest(err) } res := models.NewCheckParticipationResponse() res.Channel = &channel res.Account = context.Client.Account if context.Client.Account != nil { res.AccountToken = context.Client.Account.Token } canOpen, err := channel.CanOpen(q.AccountId) if err != nil { return response.NewBadRequest(err) } if !canOpen { cp := models.NewChannelParticipant() cp.ChannelId = channel.Id isInvited, err := cp.IsInvited(q.AccountId) if err != nil { return response.NewBadRequest(err) } if !isInvited { return response.NewAccessDenied( fmt.Errorf( "account (%d) tried to retrieve the unattended channel (%d)", q.AccountId, channel.Id, ), ) } } return response.NewOK(res) }
func Create(u *url.URL, h http.Header, req *models.Channel, context *models.Context) (int, http.Header, interface{}, error) { // only logged in users can create a channel if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } // get group name from context req.GroupName = context.GroupName req.CreatorId = context.Client.Account.Id if req.PrivacyConstant == "" { req.PrivacyConstant = models.Channel_PRIVACY_PRIVATE // if group is koding, then make it public, because it was public before if req.GroupName == models.Channel_KODING_NAME { req.PrivacyConstant = models.Channel_PRIVACY_PUBLIC } } if req.TypeConstant == "" { req.TypeConstant = models.Channel_TYPE_TOPIC } if err := validateChannelRequest(req); err != nil { return response.NewBadRequest(err) } if err := req.Create(); err != nil { return response.NewBadRequest(err) } if _, err := req.AddParticipant(req.CreatorId); err != nil { // channel create works as idempotent, that channel might have been created before if err != models.ErrAccountIsAlreadyInTheChannel { return response.NewBadRequest(err) } } cc := models.NewChannelContainer() if err := cc.PopulateWith(*req, context.Client.Account.Id); err != nil { return response.NewBadRequest(err) } return response.NewOK(cc) }
func Count(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) { channelId, err := request.GetURIInt64(u, "id") if err != nil { return response.NewBadRequest(err) } if channelId == 0 { return response.NewBadRequest(errors.New("channel id is not set")) } count, err := models.NewChannelMessageList().Count(channelId) if err != nil { return response.NewBadRequest(err) } res := new(models.CountResponse) res.TotalCount = count return response.NewOK(res) }
// End handles the terminate signals coming from client side func (mgoCache *CacheStore) End(u *url.URL, h http.Header, req *models.Ping, context *apimodels.Context) (int, http.Header, interface{}, error) { if err := validateOperation(req, context); err != nil { return response.NewBadRequest(err) } key := collaboration.PrepareFileKey(req.FileId) // when key is deleted, with the first ping received, collab will be ended if err := mgoCache.Delete(key); err != nil { return response.NewBadRequest(err) } // send the ping request to the related worker if err := bongo.B.PublishEvent(collaboration.FireEventName, req); err != nil { return response.NewBadRequest(err) } // send back the updated ping as response return response.NewOK(req) }
// Ping handles the pings coming from client side // // TOOD add throttling here func (mgoCache *CacheStore) Ping(u *url.URL, h http.Header, req *models.Ping, context *apimodels.Context) (int, http.Header, interface{}, error) { if err := validateOperation(req, context); err != nil { return response.NewBadRequest(err) } // set the last seen at time key := collaboration.PrepareFileKey(req.FileId) if err := mgoCache.SetEx(key, collaboration.ExpireSessionKeyDuration, req.CreatedAt.Unix()); err != nil { return response.NewBadRequest(err) } // send the ping request to the related worker if err := bongo.B.PublishEvent(collaboration.FireEventName, req); err != nil { return response.NewBadRequest(err) } // send back the updated ping as response return response.NewOK(req) }
func (h *Handler) GenerateKey(u *url.URL, header http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { var accountId int64 if context.IsLoggedIn() { accountId = context.Client.Account.Id } c := models.NewChannel() err := c.FetchGroupChannel(context.GroupName) if err != nil { return response.NewBadRequest(err) } searchOnlyKey, err := h.generateSearchOnlyKey(c, accountId) if err != nil { return response.NewBadRequest(err) } return response.NewOK(&Response{ApiKey: searchOnlyKey}) }
func CheckOwnership(u *url.URL, h http.Header) (int, http.Header, interface{}, error) { accountId, err := request.GetURIInt64(u, "id") if err != nil { return response.NewBadRequest(err) } query := request.GetQuery(u) ownershipResponse := func(err error) (int, http.Header, interface{}, error) { var success bool switch err { case bongo.RecordNotFound: success = false case nil: success = true default: return response.NewBadRequest(err) } return response.NewOK(map[string]bool{"success": success}) } switch query.Type { case "channel": channel := models.NewChannel() err = channel.One(&bongo.Query{ Selector: map[string]interface{}{ "id": query.ObjectId, "creator_id": accountId, }, }) case "channel-message": channelMessage := models.NewChannelMessage() err = channelMessage.One(&bongo.Query{ Selector: map[string]interface{}{ "id": query.ObjectId, "account_id": accountId, }, }) } return ownershipResponse(err) }
// Location returns the current approximate location of the requester func Location(u *url.URL, h http.Header, c *models.Context) (int, http.Header, interface{}, error) { record, err := helper.MustGetGeoIPDB().City(c.Client.IP) if err != nil { return response.NewBadRequest(err) } var location string city := record.City.Names[en] country := record.Country.Names[en] if city != "" { location = fmt.Sprintf("%s, %s", city, country) } else { location = fmt.Sprintf("%s", country) } return response.NewOK( map[string]interface{}{ "location": location, }, ) }
// Store stores the given credentials on s3 func (s *SneakerS3) Store(u *url.URL, h http.Header, kv KeyValue, context *models.Context) (int, http.Header, interface{}, error) { pathName := u.Query().Get("pathName") logger := s.createLogger(context, "Store", pathName, http.StatusBadRequest) if pathName == "" { return response.NewBadRequestWithLogger(logger, ErrPathNotFound) } if !context.IsLoggedIn() { return response.NewBadRequestWithLogger(logger, models.ErrNotLoggedIn) } if kv == nil { return response.NewBadRequestWithLogger(logger, ErrRequiredValuesNotFound) } // convert credentials to bytes byt, err := json.Marshal(kv) if err != nil { return response.NewBadRequestWithLogger(logger, err) } // bytes need to imlement io.Reader interface // then we can use struct as 2.parameter of manager.Upload function aa := bytes.NewReader(byt) // if another requeest comes to same pathName, its data will be updated. // and new incoming data is gonna override the old data err = s.Manager.Upload(pathName, aa) if err != nil { return response.NewBadRequestWithLogger(logger, err) } logger = s.createLogger(context, "Store", pathName, http.StatusOK) logger.Info("") return response.NewOK(nil) }
func UnblockMulti(u *url.URL, h http.Header, participants []*models.ChannelParticipant, context *models.Context) (int, http.Header, interface{}, error) { query := context.OverrideQuery(request.GetQuery(u)) if err := checkChannelPrerequisites( query.Id, query.AccountId, participants, ); err != nil { return response.NewBadRequest(err) } ch := models.NewChannel() err := ch.ById(query.Id) if err != nil { return response.NewBadRequest(err) } isAdmin, err := modelhelper.IsAdmin(context.Client.Account.Nick, context.GroupName) if err != nil { return response.NewBadRequest(err) } for i := range participants { // if the requester is trying to remove some other user than themselves, and they are not the channel owner // return bad request if participants[i].AccountId != query.AccountId && query.AccountId != ch.CreatorId { if !isAdmin { return response.NewBadRequest(fmt.Errorf("User is not allowed to unblock other users")) } } participants[i].ChannelId = query.Id if err := participants[i].Unblock(); err != nil { return response.NewBadRequest(err) } } return response.NewOK(participants) }
// this is a TEMP function just for @usirin func TempList(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { channelId, err := request.GetURIInt64(u, "id") if err != nil { return response.NewBadRequest(err) } query := request.GetQuery(u) query = context.OverrideQuery(query) c, err := models.Cache.Channel.ById(channelId) if err != nil { return response.NewBadRequest(err) } // if channel is exempt and user should see the // content, return not found err if !query.ShowExempt { query.ShowExempt = context.Client.Account.IsTroll } if c.MetaBits.Is(models.Troll) && !query.ShowExempt { return response.NewNotFound() } // check if channel is accessible by the requester canOpen, err := c.CanOpen(query.AccountId) if err != nil { return response.NewBadRequest(err) } if !canOpen { return response.NewAccessDenied( fmt.Errorf( "account (%d) tried to retrieve the unattended private channel (%d)", query.AccountId, c.Id, )) } bq := &bongo.Query{ Selector: map[string]interface{}{ "initial_channel_id": c.Id, }, Pagination: *bongo.NewPagination(query.Limit, query.Skip), Pluck: "id", } bq.AddScope(models.SortedByCreatedAt) bq.AddScope(models.RemoveTrollContent(c, query.ShowExempt)) bq.AddScope(models.ExcludeFields(query.Exclude)) bq.AddScope(models.TillTo(query.From)) bqq := bongo.B.BuildQuery(models.NewChannelMessage(), bq) var messages []int64 if err := bongo.CheckErr( bqq.Pluck(bq.Pluck, &messages), ); err != nil { return response.NewBadRequest(err) } // get the messages in regarding channel cmcs, err := models. NewChannelMessageList(). PopulateChannelMessages( messages, query, ) if err != nil { return response.NewBadRequest(err) } // reduce replies replyIds := make([]int64, 0) for i := range cmcs { cmc := cmcs[i] if cmc.Message.TypeConstant == models.ChannelMessage_TYPE_REPLY { replyIds = append(replyIds, cmc.Message.Id) } } if len(replyIds) == 0 { return response.NewOK(cmcs) } // select replies var mrs []models.MessageReply gerr := bongo.B. BuildQuery(models.NewMessageReply(), &bongo.Query{}). Where("reply_id in (?)", replyIds). Find(&mrs) if err := bongo.CheckErr(gerr); err != nil { return response.NewBadRequest(err) } // set their parent ids for j, mr := range mrs { for i := range cmcs { if mr.ReplyId == cmcs[i].Message.Id { cmcs[i].ParentID = mrs[j].MessageId } } } // send response return response.NewOK(cmcs) }