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))) }
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 Create(u *url.URL, h http.Header, reply *models.ChannelMessage, c *models.Context) (int, http.Header, interface{}, error) { parentId, err := request.GetURIInt64(u, "id") if err != nil { return response.NewBadRequest(err) } // fetch the parent message parent, err := models.Cache.Message.ById(parentId) if err != nil { return response.NewBadRequest(err) } parentChannel, err := models.Cache.Channel.ById(parent.InitialChannelId) if err != nil { return response.NewBadRequest(err) } canOpen, err := parentChannel.CanOpen(c.Client.Account.Id) if err != nil { return response.NewBadRequest(err) } if !canOpen { return response.NewAccessDenied(models.ErrCannotOpenChannel) } // first create reply as a message reply.TypeConstant = models.ChannelMessage_TYPE_REPLY // set initial channel id for message creation reply.InitialChannelId = parent.InitialChannelId reply.AccountId = c.Client.Account.Id if err := reply.Create(); err != nil { // todo this should be internal server error return response.NewBadRequest(err) } // then add this message as a reply to a parent message mr := models.NewMessageReply() mr.MessageId = parentId mr.ReplyId = reply.Id mr.CreatedAt = reply.CreatedAt mr.ClientRequestId = reply.ClientRequestId if err := mr.Create(); err != nil { // todo this should be internal server error return response.NewBadRequest(err) } return response.HandleResultAndError( reply.BuildEmptyMessageContainer(), ) }
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 Delete(u *url.URL, h http.Header, req *models.Channel, context *models.Context) (int, http.Header, interface{}, error) { if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } id, err := request.GetURIInt64(u, "id") if err != nil { return response.NewBadRequest(err) } if err := req.ById(id); err != nil { return response.NewBadRequest(err) } if req.TypeConstant == models.Channel_TYPE_GROUP { return response.NewBadRequest(errors.New("You can not delete group channel")) } canOpen, err := req.CanOpen(context.Client.Account.Id) if err != nil { return response.NewBadRequest(err) } if !canOpen { return response.NewBadRequest(models.ErrCannotOpenChannel) } // TO-DO // add super-admin check here if req.CreatorId != context.Client.Account.Id { isAdmin, err := modelhelper.IsAdmin(context.Client.Account.Nick, req.GroupName) if err != nil { return response.NewBadRequest(err) } if !isAdmin { return response.NewAccessDenied(models.ErrAccessDenied) } } if err := req.Delete(); err != nil { return response.NewBadRequest(err) } // yes it is deleted but not removed completely from our system return response.NewDeleted() }
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), ) }
func handleChannelResponse(c models.Channel, q *request.Query) (int, http.Header, interface{}, error) { // add troll mode filter if c.MetaBits.Is(models.Troll) && !q.ShowExempt { return response.NewNotFound() } canOpen, err := c.CanOpen(q.AccountId) if err != nil { return response.NewBadRequest(err) } if !canOpen { cp := models.NewChannelParticipant() cp.ChannelId = c.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, c.Id, ), ) } } cc := models.NewChannelContainer() if err := cc.Fetch(c.GetId(), q); err != nil { return response.NewBadRequest(err) } cc.AddIsParticipant(q.AccountId) // TODO this should be in the channel cache by default cc.AddLastMessage(q.AccountId) cc.AddUnreadCount(q.AccountId) return response.HandleResultAndError(cc, cc.Err) }
// SubscribeChannel checks users channel accessability and regarding to that // grants channel access for them func (h *Handler) SubscribeChannel(u *url.URL, header http.Header, req *models.Channel, context *socialapimodels.Context) (int, http.Header, interface{}, error) { if !context.IsLoggedIn() { return response.NewBadRequest(socialapimodels.ErrNotLoggedIn) } req.Group = context.GroupName // override group name res, err := h.checkParticipation(u, header, req) if err != nil { return response.NewAccessDenied(err) } // user has access permission, now authenticate user to channel via pubnub a := new(models.Authenticate) a.Channel = models.NewPrivateMessageChannel(*res.Channel) a.Account = res.Account a.Account.Token = res.AccountToken err = h.pubnub.Authenticate(a) if err != nil { return response.NewBadRequest(err) } return responseWithCookie(req, a.Account.Token) }
// 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) }
func Delete(u *url.URL, h http.Header, _ interface{}, c *models.Context) (int, http.Header, interface{}, error) { if !c.IsLoggedIn() { return response.NewAccessDenied(models.ErrNotLoggedIn) } id, err := request.GetURIInt64(u, "id") if err != nil { return response.NewBadRequest(err) } if id == 0 { return response.NewBadRequest(models.ErrMessageIdIsNotSet) } cm := models.NewChannelMessage() cm.Id = id if err := cm.ById(id); err != nil { if err == bongo.RecordNotFound { return response.NewNotFound() } return response.NewBadRequest(err) } // Add isAdmin checking // is user is admin, then can delete another user's message if cm.AccountId != c.Client.Account.Id { isAdmin, err := modelhelper.IsAdmin(c.Client.Account.Nick, c.GroupName) if err != nil { return response.NewBadRequest(err) } if !isAdmin { return response.NewBadRequest(models.ErrAccessDenied) } } // if this is a reply no need to delete it's replies if cm.TypeConstant == models.ChannelMessage_TYPE_REPLY { mr := models.NewMessageReply() mr.ReplyId = id parent, err := mr.FetchParent() if err != nil { return response.NewBadRequest(err) } // delete the message here err = cm.DeleteMessageAndDependencies(false) // then invalidate the cache of the parent message bongo.B.AddToCache(parent) } else { err = cm.DeleteMessageAndDependencies(true) } if err != nil { return response.NewBadRequest(err) } // yes it is deleted but not removed completely from our system return response.NewDeleted() }