func ListPosts(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { query := request.GetQuery(u) query = context.OverrideQuery(query) buildMessageQuery := query.Clone() 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 only channel messages query.Type = models.ChannelMessage_TYPE_POST query.AccountId = accountId cm := models.NewChannelMessage() messages, err := cm.FetchMessagesByChannelId(c.Id, query) if err != nil { return response.NewBadRequest(err) } buildMessageQuery.Limit = 3 return response.HandleResultAndError( cm.BuildMessages(buildMessageQuery, messages), ) }
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) }
// ByName finds topics by their name func ByName(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { q := context.OverrideQuery(request.GetQuery(u)) if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } if q.Type == "" { q.Type = models.Channel_TYPE_TOPIC } channel, err := models.NewChannel().ByName(q) if err != nil { if err == bongo.RecordNotFound { return response.NewNotFound() } if models.IsChannelLeafErr(err) { return http.StatusMovedPermanently, nil, nil, tigertonic.MovedPermanently{Err: err} } return response.NewBadRequest(err) } return handleChannelResponse(channel, q) }
// HasCreditCard returns the existance status of group's credit card func HasCreditCard(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } group, err := modelhelper.GetGroup(context.GroupName) if err != nil { return response.NewBadRequest(err) } if group.Payment.Customer.ID == "" { return response.NewNotFound() } err = payment.CheckCustomerHasSource(group.Payment.Customer.ID) if err == payment.ErrCustomerSourceNotExists { return response.NewNotFound() } if err != nil { return response.NewBadRequest(err) } return response.NewDefaultOK() }
func List(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { query := context.OverrideQuery(request.GetQuery(u)) if query.Id == 0 { return response.NewBadRequest(errors.New("channel id is not set")) } c, err := models.Cache.Channel.ById(query.Id) if err != nil { return response.NewBadRequest(err) } canOpen, err := c.CanOpen(query.AccountId) if err != nil { return response.NewBadRequest(err) } if !canOpen { return response.NewAccessDenied(fmt.Errorf("user %d tried to open unattended channel %d", query.AccountId, query.Id)) } return response.HandleResultAndError( fetchChannelParticipants(query), ) }
func Get(u *url.URL, h http.Header, _ interface{}, ctx *models.Context) (int, http.Header, interface{}, error) { cm, err := getMessageByUrl(u) if err != nil { return response.NewBadRequest(err) } if cm.Id == 0 { return response.NewNotFound() } ch, err := models.Cache.Channel.ById(cm.InitialChannelId) if err != nil { response.NewBadRequest(err) } canOpen, err := ch.CanOpen(ctx.Client.Account.Id) if err != nil { return response.NewBadRequest(err) } if !canOpen { return response.NewAccessDenied(models.ErrCannotOpenChannel) } cmc := models.NewChannelMessageContainer() return response.HandleResultAndError(cmc, cmc.Fetch(cm.Id, request.GetQuery(u))) }
// 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 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) }
// lists followed channels of an account func ListChannels(u *url.URL, h http.Header, _ interface{}, c *models.Context) (int, http.Header, interface{}, error) { accountId, err := request.GetURIInt64(u, "id") if err != nil { return response.NewBadRequest(err) } if !c.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } if accountId != c.Client.Account.Id { return response.NewBadRequest(models.ErrAccessDenied) } query := request.GetQuery(u) query = c.OverrideQuery(query) if query.Type == "" { query.Type = models.Channel_TYPE_TOPIC } a := &models.Account{Id: accountId} channels, err := a.FetchChannels(query) if err != nil { return response.NewBadRequest(err) } cc := models.NewChannelContainers() cc.PopulateWith(channels, query.AccountId).AddUnreadCount(query.AccountId) return response.HandleResultAndError(cc, cc.Err()) }
func GetWithRelated(u *url.URL, h http.Header, _ interface{}, ctx *models.Context) (int, http.Header, interface{}, error) { cm, err := getMessageByUrl(u) if err != nil { return response.NewBadRequest(err) } if cm.Id == 0 { return response.NewNotFound() } ch, err := models.Cache.Channel.ById(cm.InitialChannelId) if err != nil { return response.NewBadRequest(err) } q := request.GetQuery(u) query := ctx.OverrideQuery(q) canOpen, err := ch.CanOpen(query.AccountId) if err != nil { return response.NewBadRequest(err) } if !canOpen { return response.NewBadRequest(models.ErrCannotOpenChannel) } cmc := models.NewChannelMessageContainer() if err := cmc.Fetch(cm.Id, query); err != nil { return response.NewBadRequest(err) } return response.HandleResultAndError(cmc, cmc.Err) }
func List(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) { messageId, err := request.GetURIInt64(u, "id") if err != nil { return response.NewBadRequest(err) } accountId, err := request.GetURIInt64(u, "accountId") if err != nil { return response.NewBadRequest(err) } reply := models.NewMessageReply() reply.MessageId = messageId messages, err := reply.List(request.GetQuery(u)) if err != nil { return response.NewBadRequest(err) } return response.HandleResultAndError( helpers.ConvertMessagesToMessageContainers( messages, accountId, ), ) }
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 ParticipatedChannelCount(u *url.URL, h http.Header, _ interface{}, c *models.Context) (int, http.Header, interface{}, error) { accountId, err := request.GetURIInt64(u, "id") if err != nil { return response.NewBadRequest(err) } if !c.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } if accountId != c.Client.Account.Id { return response.NewBadRequest(models.ErrAccessDenied) } query := request.GetQuery(u) query = c.OverrideQuery(query) if query.Type == "" { query.Type = models.Channel_TYPE_TOPIC } cp := models.NewChannelParticipant() a := &models.Account{Id: query.AccountId} return response.HandleResultAndError(cp.ParticipatedChannelCount(a, query)) }
// ByParticipants finds private message channels by their participants func ByParticipants(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { // only logged in users if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } query := request.GetQuery(u) query = context.OverrideQuery(query) participantsStr, ok := u.Query()["id"] if !ok { return response.NewBadRequest(errors.New("participants not set")) } if len(participantsStr) == 0 { return response.NewBadRequest(errors.New("at least one participant is required")) } unify := make(map[string]interface{}) // add current account to participants list unify[strconv.FormatInt(context.Client.Account.Id, 10)] = struct{}{} // remove duplicates from participants for i := range participantsStr { unify[participantsStr[i]] = struct{}{} } participants := make([]int64, 0) // convert strings to int64 for participantStr := range unify { i, err := strconv.ParseInt(participantStr, 10, 64) if err != nil { return response.NewBadRequest(err) } participants = append(participants, i) } channels, err := models.NewChannel().ByParticipants(participants, query) if err != nil { if err == bongo.RecordNotFound { return response.NewNotFound() } } cc := models.NewChannelContainers(). PopulateWith(channels, context.Client.Account.Id). AddLastMessage(context.Client.Account.Id). AddUnreadCount(context.Client.Account.Id) return response.HandleResultAndError(cc, cc.Err()) }
// PostMessage posts a message to a slack channel/group func (s *Slack) PostMessage(u *url.URL, h http.Header, req *SlackMessageRequest, context *models.Context) (int, http.Header, interface{}, error) { if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } token, err := getSlackToken(context) if err != nil { return response.NewBadRequest(err) } return response.HandleResultAndError(postMessage(token, req)) }
// DeleteCreditCard deletes the credit card of a group func DeleteCreditCard(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { if err := context.IsGroupAdmin(); err != nil { return response.NewBadRequest(err) } if err := payment.DeleteCreditCardForGroup(context.GroupName); err != nil { return response.NewBadRequest(err) } return response.NewDefaultOK() }
func Unfollow(u *url.URL, h http.Header, req *models.Account, context *models.Context) (int, http.Header, interface{}, error) { targetId, err := request.GetURIInt64(u, "id") if err != nil { return response.NewBadRequest(err) } if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } return response.HandleResultAndError(req.Unfollow(targetId)) }
// TeamInfo shows basic info regarding a slack team func (s *Slack) TeamInfo(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } token, err := getSlackToken(context) if err != nil { return response.NewBadRequest(err) } return response.HandleResultAndError(getTeamInfo(token)) }
// HandleEvent handles events with given data func HandleEvent(u *url.URL, h http.Header, req map[string]interface{}) (int, http.Header, interface{}, error) { eventName := u.Query().Get("eventName") if eventName == "" { return response.NewBadRequest(errors.New("eventName can not be empty")) } if err := bongo.B.Emit(eventName, req); err != nil { return response.NewBadRequest(err) } return response.NewDefaultOK() }
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 List(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) } query := request.GetQuery(u) q := ctx.OverrideQuery(query) channelList, err := getPrivateChannels(q) if err != nil { return response.NewBadRequest(err) } return response.HandleResultAndError(buildContainer(channelList, q)) }
// Info return usage info for a group func Info(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { if err := context.IsGroupAdmin(); err != nil { return response.NewBadRequest(err) } group, err := modelhelper.GetGroup(context.GroupName) if err != nil { return response.NewBadRequest(err) } return response.HandleResultAndError( payment.EnsureInfoForGroup(group, context.Client.Account.Nick), ) }
// DeleteCustomer deletes customer for a group. Here for symmetry. func DeleteCustomer(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { // do not allow customer deletion, causes losing track of transactions. return http.StatusForbidden, nil, nil, nil if err := context.IsGroupAdmin(); err != nil { return response.NewBadRequest(err) } if err := payment.DeleteCustomerForGroup(context.GroupName); err != nil { return response.NewBadRequest(err) } return response.NewDeleted() }
func BlockMulti(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 block other users")) } } participants[i].ChannelId = query.Id if err := participants[i].Block(); 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) }
// Send initiates Slack OAuth func (s *Slack) Send(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } session, err := models.Cache.Session.ById(context.Client.SessionID) if err != nil { return response.NewBadRequest(models.ErrNotLoggedIn) } url := s.OAuthConf.AuthCodeURL(session.Id.Hex(), oauth2.AccessTypeOffline) h.Set("Location", url) return http.StatusTemporaryRedirect, h, nil, nil }
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 PublishEvent(u *url.URL, h http.Header, req *emailsender.Mail) (int, http.Header, interface{}, error) { if err := emailsender.Send(req); err != nil { return response.NewBadRequest(err) } return response.NewDefaultOK() }
func (h *Handler) GetToken(u *url.URL, header http.Header, req *socialapimodels.Account, context *socialapimodels.Context) (int, http.Header, interface{}, error) { if !context.IsLoggedIn() { return response.NewBadRequest(socialapimodels.ErrNotLoggedIn) } return responseWithCookie(req, context.Client.Account.Token) }
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 List(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 !query.ShowExempt { query.ShowExempt = context.Client.Account.IsTroll } // if channel is exempt and user should see the // content, return not found err if c.MetaBits.Is(models.Troll) && !query.ShowExempt { return response.NewNotFound() } 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, )) } cml := models.NewChannelMessageList() cml.ChannelId = c.Id return response.HandleResultAndError( cml.List(query, false), ) }