Exemple #1
0
// todo - refactor this part
func (f *Controller) MessageListDeleted(cml *models.ChannelMessageList) error {
	c, err := models.Cache.Channel.ById(cml.ChannelId)
	if err != nil {
		return err
	}

	// Since we are making hard deletes, we no longer need to check the
	// message existency
	cm := models.NewChannelMessage()
	cm.Id = cml.MessageId

	cp := models.NewChannelParticipant()
	cp.AccountId = c.CreatorId

	cue := &channelUpdatedEvent{
		Controller:           f,
		Channel:              c,
		ParentChannelMessage: cm,
		ChannelParticipant:   cp,
		EventType:            channelUpdatedEventMessageRemovedFromChannel,
	}

	if err := cue.notifyAllParticipants(); err != nil {
		return err
	}

	// f.sendNotification(cp.AccountId, ChannelUpdateEventName, cue)

	if err := f.sendChannelEvent(cml, cm, MessageRemovedEventName); err != nil {
		return err
	}

	return nil
}
Exemple #2
0
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)
}
Exemple #3
0
func (mwc *Controller) GrantMessageAccess() {
	mwc.log.Notice("Granting public access for messages")

	c := models.NewChannelMessage()
	query := bongo.B.DB.
		Model(c).
		Table(c.BongoName()).
		Select("api.channel_message.token")

	rows, err := query.Rows()
	defer rows.Close()
	if err != nil {
		panic(err)
	}

	if rows == nil {
		return
	}

	var token string
	for rows.Next() {
		rows.Scan(&token)
		channel := realtimemodels.UpdateInstanceMessage{
			Token: token,
		}

		err := mwc.pubnub.GrantPublicAccess(realtimemodels.NewMessageUpdateChannel(channel))
		if err != nil {
			mwc.log.Error("Could not grant public access to token %s: %s", token, err)
		}
	}
}
Exemple #4
0
func CreatePostWithBody(channelId, accountId int64, body string) (*models.ChannelMessage, error) {
	cm := models.NewChannelMessage()
	cm.Body = body
	cm.AccountId = accountId

	return createPostRequest(channelId, cm, http.Header{})
}
Exemple #5
0
func getMessageByUrl(u *url.URL) (*models.ChannelMessage, error) {

	// TODO
	// fmt.Println(`
	// 	------->
	//             ADD SECURTY CHECK FOR VISIBILTY OF THE MESSAGE
	//                         FOR THE REQUESTER
	//     ------->"`,
	// )

	id, err := request.GetURIInt64(u, "id")
	if err != nil {
		return nil, err
	}

	// get url query params
	q := request.GetQuery(u)

	query := &bongo.Query{
		Selector: map[string]interface{}{
			"id": id,
		},
		Pagination: *bongo.NewPagination(1, 0),
	}

	cm := models.NewChannelMessage()
	// add exempt info
	query.AddScope(models.RemoveTrollContent(cm, q.ShowExempt))

	if err := cm.One(query); err != nil {
		return nil, err
	}

	return cm, nil
}
Exemple #6
0
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),
	)
}
Exemple #7
0
func GetPost(id int64, token string) (*models.ChannelMessage, error) {
	url := fmt.Sprintf("/message/%d", id)
	cm := models.NewChannelMessage()
	cmI, err := sendModelWithAuth("GET", url, cm, token)
	if err != nil {
		return nil, err
	}
	return cmI.(*models.ChannelMessage), nil
}
Exemple #8
0
func checkThrottle(channelId, requesterId int64) error {
	c, err := models.Cache.Channel.ById(channelId)
	if err != nil {
		return err
	}

	if c.TypeConstant != models.Channel_TYPE_GROUP {
		return nil
	}

	cm := models.NewChannelMessage()

	conf := config.MustGet()

	// if oit is defaul treturn  early
	if conf.Limits.PostThrottleDuration == "" {
		return nil
	}

	// if throttle count is zero, it meands it is not set
	if conf.Limits.PostThrottleCount == 0 {
		return nil
	}

	dur, err := time.ParseDuration(conf.Limits.PostThrottleDuration)
	if err != nil {
		return err
	}

	// subtrack duration from current time
	prevTime := time.Now().UTC().Truncate(dur)

	// count sends positional parameters, no need to sanitize input
	count, err := bongo.B.Count(
		cm,
		"initial_channel_id = ? and "+
			"account_id = ? and "+
			"created_at > ?",
		channelId,
		requesterId,
		prevTime.Format(time.RFC3339Nano),
	)
	if err != nil {
		return err
	}

	if count > conf.Limits.PostThrottleCount {
		return fmt.Errorf("reached to throttle, current post count %d for user %d", count, requesterId)
	}

	return nil
}
Exemple #9
0
func decorateContainers(containers []*models.ChannelMessageContainer, messages []models.ChannelMessage, accountId int64) {
	log := runner.MustGetLogger()
	var err error
	for i, message := range messages {
		d := models.NewChannelMessage()
		*d = message

		containers[i], err = d.BuildEmptyMessageContainer()
		if err != nil {
			log.Error("Could not create message container for message %d: %s", containers[i].Message.Id, err)
			continue
		}
	}
}
Exemple #10
0
func addRepliesToMessage(channelId, accountId, messageId int64) {
	// add replies to the message
	rply1 := models.NewChannelMessage()
	rply1.AccountId = accountId
	rply1.InitialChannelId = channelId
	rply1.TypeConstant = models.ChannelMessage_TYPE_REPLY
	rply1.Body = "hello reply all from test"
	So(rply1.Create(), ShouldBeNil)

	mr := models.NewMessageReply()
	mr.ReplyId = rply1.Id
	mr.MessageId = messageId
	So(mr.Create(), ShouldBeNil)
}
Exemple #11
0
func FetchMessagesByIds(messageIds []int64, err error) ([]models.ChannelMessage, error) {
	if err != nil {
		return make([]models.ChannelMessage, 0), err
	}

	if len(messageIds) == 0 {
		return make([]models.ChannelMessage, 0), nil
	}

	channelMessages, err := models.NewChannelMessage().FetchByIds(messageIds)
	if err != nil {
		return nil, err
	}

	return channelMessages, nil
}
Exemple #12
0
func CreatePostWithBodyAndAuth(channelId int64, body, token string) (*models.ChannelMessage, error) {
	url := fmt.Sprintf("/channel/%d/message", channelId)
	cm := models.NewChannelMessage()
	cm.Body = body
	res, err := marshallAndSendRequestWithAuth("POST", url, cm, token)
	if err != nil {
		return nil, err
	}

	container := models.NewChannelMessageContainer()
	err = json.Unmarshal(res, container)
	if err != nil {
		return nil, err
	}

	return container.Message, nil

}
Exemple #13
0
func (m *Mail) persistReply(accountId int64) error {

	mId, err := m.getIdsFromMailboxHash()
	if err != nil {
		return err
	}
	messageId := mId
	cm, err := socialapimodels.Cache.Message.ById(messageId)
	if err != nil {
		return err
	}

	c, err := channelPermission(cm.InitialChannelId, accountId)
	if err != nil {
		return err
	}

	// create reply
	reply := socialapimodels.NewChannelMessage()
	reply.Body = m.StrippedTextReply // set the body

	reply.TypeConstant = socialapimodels.ChannelMessage_TYPE_REPLY
	if cm.TypeConstant == socialapimodels.ChannelMessage_TYPE_PRIVATE_MESSAGE {
		reply.TypeConstant = socialapimodels.ChannelMessage_TYPE_PRIVATE_MESSAGE
	}

	if c.TypeConstant == socialapimodels.Channel_TYPE_COLLABORATION {
		reply.TypeConstant = socialapimodels.ChannelMessage_TYPE_PRIVATE_MESSAGE
	}

	reply.InitialChannelId = cm.InitialChannelId
	reply.AccountId = accountId
	if err := reply.Create(); err != nil {
		return err
	}

	if _, err = cm.AddReply(reply); err != nil {
		return err
	}
	return nil
}
Exemple #14
0
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)
}
Exemple #15
0
func migrateChannels(r *runner.Runner, handler *algoliaconnector.Controller) error {
	count := 0
	for b := 0; ; b++ {

		var messages []models.ChannelMessage

		err := models.NewChannelMessage().Some(&messages, &bongo.Query{
			Pagination: bongo.Pagination{
				Limit: 100,
				Skip:  b * 100,
			},
			Sort: map[string]string{
				"created_at": "DESC",
			},
		})
		if err != nil {
			return err
		}

		for _, message := range messages {
			cmls, err := message.GetChannelMessageLists()
			if err != nil {
				return err
			}

			for _, cml := range cmls {
				count++
				r.Log.Info("[%d]: currently migrating channel.Id: %d message.Id: %d", count, cml.ChannelId, cml.MessageId)
				if err := handler.MessageListSaved(&cml); err != nil {
					return err
				}
			}

		}

		if len(messages) < 100 {
			return nil
		}
	}
}
Exemple #16
0
func GetBySlug(u *url.URL, h http.Header, _ interface{}, ctx *models.Context) (int, http.Header, interface{}, error) {
	q := request.GetQuery(u)

	if q.Slug == "" {
		return response.NewBadRequest(errors.New("slug is not set"))
	}

	cm := models.NewChannelMessage()
	if err := cm.BySlug(q); err != nil {
		if err == bongo.RecordNotFound {
			return response.NewNotFound()
		}
		return response.NewBadRequest(err)
	}

	ch := models.NewChannel()
	if err := ch.ById(cm.InitialChannelId); err != nil {
		return response.NewBadRequest(err)
	}

	query := ctx.OverrideQuery(q)

	// check if user can open
	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)
}
Exemple #17
0
func Delete(u *url.URL, h http.Header, _ interface{}) (int, http.Header, interface{}, error) {
	parentId, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	if parentId == 0 {
		// todo add proper logging
		return response.NewBadRequest(err)
	}

	replyId, err := request.GetURIInt64(u, "replyId")
	if err != nil {
		return response.NewBadRequest(err)
	}

	if replyId == 0 {
		// todo add proper logging
		return response.NewBadRequest(err)
	}

	// first delete the connection between message and the reply
	mr := models.NewMessageReply()
	mr.MessageId = parentId
	mr.ReplyId = replyId
	if err := mr.Delete(); err != nil {
		return response.NewBadRequest(err)
	}

	// then delete the message itself
	reply := models.NewChannelMessage()
	reply.Id = replyId
	if err := reply.Delete(); err != nil {
		return response.NewBadRequest(err)
	}

	// yes it is deleted but not removed completely from our system
	return response.NewDeleted()
}
Exemple #18
0
func (m *Mail) persistPost(accountId int64) error {

	cid, err := m.getIdsFromMailboxHash()
	if err != nil {
		return err
	}

	channelId := cid
	c, err := channelPermission(channelId, accountId)
	if err != nil {
		return err
	}

	cm := socialapimodels.NewChannelMessage()
	cm.Body = m.TextBody // set the body

	cm.TypeConstant = socialapimodels.ChannelMessage_TYPE_POST
	if c.TypeConstant == socialapimodels.Channel_TYPE_PRIVATE_MESSAGE {
		cm.TypeConstant = socialapimodels.ChannelMessage_TYPE_PRIVATE_MESSAGE
	}

	if c.TypeConstant == socialapimodels.Channel_TYPE_COLLABORATION {
		cm.TypeConstant = socialapimodels.ChannelMessage_TYPE_PRIVATE_MESSAGE
	}

	cm.InitialChannelId = channelId
	cm.AccountId = accountId
	if err := cm.Create(); err != nil {
		return err
	}

	_, err = c.EnsureMessage(cm, true)
	if err != nil {
		return err
	}

	return nil
}
Exemple #19
0
func (f *Controller) MessageListSaved(listing *models.ChannelMessageList) error {
	message := models.NewChannelMessage()
	if err := message.ById(listing.MessageId); err != nil {
		return err
	}

	if !message.SearchIndexable() {
		return nil
	}

	objectID := strconv.FormatInt(message.Id, 10)
	channelId := strconv.FormatInt(listing.ChannelId, 10)

	// if message is doesnt exist on algolia it will be created and tag will be
	// added, if it is already created before tag will be added
	return f.partialUpdate(IndexMessages, map[string]interface{}{
		"objectID": objectID,
		"body":     message.Body,
		"_tags": map[string]interface{}{
			"_operation": "AddUnique",
			"value":      channelId,
		},
	})
}
Exemple #20
0
// 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)
}
Exemple #21
0
func CreatePostWithHeader(channelId int64, header http.Header, token string) (*models.ChannelMessage, error) {
	cm := models.NewChannelMessage()
	cm.Body = "Text1Text2"

	return createPostRequestWithAuth(channelId, cm, header, token)
}
Exemple #22
0
func TestChannelParticipantOperations(t *testing.T) {
	tests.WithRunner(t, func(r *runner.Runner) {
		Convey("while testing channel participants", t, func() {
			Convey("First Create Users and initiate conversation", func() {
				ownerAccount, groupChannel, groupName := models.CreateRandomGroupDataWithChecks()

				ownerSes, err := modelhelper.FetchOrCreateSession(ownerAccount.Nick, groupName)
				So(err, ShouldBeNil)
				So(ownerSes, ShouldNotBeNil)

				secondAccount, err := models.CreateAccountInBothDbs()
				tests.ResultedWithNoErrorCheck(secondAccount, err)
				_, err = groupChannel.AddParticipant(secondAccount.Id)
				So(err, ShouldBeNil)

				thirdAccount, err := models.CreateAccountInBothDbs()
				tests.ResultedWithNoErrorCheck(thirdAccount, err)
				_, err = groupChannel.AddParticipant(thirdAccount.Id)
				So(err, ShouldBeNil)

				forthAccount, err := models.CreateAccountInBothDbs()
				tests.ResultedWithNoErrorCheck(forthAccount, err)
				_, err = groupChannel.AddParticipant(forthAccount.Id)
				So(err, ShouldBeNil)

				devrim, err := models.CreateAccountInBothDbsWithNick("devrim")
				tests.ResultedWithNoErrorCheck(devrim, err)
				_, err = groupChannel.AddParticipant(devrim.Id)
				So(err, ShouldBeNil)

				ses, err := modelhelper.FetchOrCreateSession(ownerAccount.Nick, groupName)
				tests.ResultedWithNoErrorCheck(ses, err)

				secondSes, err := modelhelper.FetchOrCreateSession(secondAccount.Nick, groupName)
				tests.ResultedWithNoErrorCheck(secondSes, err)

				pmr := models.ChannelRequest{}

				pmr.AccountId = ownerAccount.Id

				pmr.Body = "new conversation"
				pmr.GroupName = groupName
				pmr.Recipients = []string{"devrim"}

				channelContainer, err := rest.SendPrivateChannelRequest(pmr, ownerSes.ClientId)
				So(err, ShouldBeNil)
				So(channelContainer, ShouldNotBeNil)

				Convey("First user should be able to add second and third users to conversation", func() {
					_, err = rest.AddChannelParticipant(channelContainer.Channel.Id, ownerSes.ClientId, secondAccount.Id, thirdAccount.Id)
					So(err, ShouldBeNil)
					participants, err := rest.ListChannelParticipants(channelContainer.Channel.Id, ownerSes.ClientId)
					So(err, ShouldBeNil)
					So(participants, ShouldNotBeNil)
					// it is four because first user is "devrim" here
					So(len(participants), ShouldEqual, 4)

					Convey("First user should not be able to re-add second participant", func() {
						_, err = rest.AddChannelParticipant(channelContainer.Channel.Id, ownerSes.ClientId, secondAccount.Id)
						So(err, ShouldBeNil)

						participants, err := rest.ListChannelParticipants(channelContainer.Channel.Id, ownerSes.ClientId)
						So(err, ShouldBeNil)
						So(participants, ShouldNotBeNil)
						So(len(participants), ShouldEqual, 4)
					})

					Convey("Second user should be able to leave conversation", func() {
						// token of account -> secondAccount
						_, err = rest.DeleteChannelParticipant(channelContainer.Channel.Id, secondSes.ClientId, secondAccount.Id)
						So(err, ShouldBeNil)

						participants, err := rest.ListChannelParticipants(channelContainer.Channel.Id, ownerSes.ClientId)
						So(err, ShouldBeNil)
						So(participants, ShouldNotBeNil)
						So(len(participants), ShouldEqual, 3)

						Convey("A user who is not participant of a conversation should not be able to add another user to the conversation", func() {
							_, err = rest.AddChannelParticipant(channelContainer.Channel.Id, secondSes.ClientId, forthAccount.Id)
							So(err, ShouldNotBeNil)

							participants, err := rest.ListChannelParticipants(channelContainer.Channel.Id, ownerSes.ClientId)
							So(err, ShouldBeNil)
							So(participants, ShouldNotBeNil)
							So(len(participants), ShouldEqual, 3)
						})
					})

					Convey("Channel owner should be able to kick another conversation participant", func() {
						_, err = rest.DeleteChannelParticipant(channelContainer.Channel.Id, ownerSes.ClientId, secondAccount.Id)
						So(err, ShouldBeNil)

						participants, err := rest.ListChannelParticipants(channelContainer.Channel.Id, ownerSes.ClientId)
						So(err, ShouldBeNil)
						So(participants, ShouldNotBeNil)
						So(len(participants), ShouldEqual, 3)
					})

					Convey("when a user is blocked", func() {
						_, err = rest.BlockChannelParticipant(channelContainer.Channel.Id, ownerSes.ClientId, secondAccount.Id)
						So(err, ShouldBeNil)

						Convey("it should not be in channel participant list", func() {
							participants, err := rest.ListChannelParticipants(channelContainer.Channel.Id, ownerSes.ClientId)
							So(err, ShouldBeNil)
							So(participants, ShouldNotBeNil)
							So(len(participants), ShouldEqual, 3)
						})

						Convey("should not be able to add it back", func() {
							_, err = rest.AddChannelParticipant(channelContainer.Channel.Id, ownerSes.ClientId, secondAccount.Id)
							So(err, ShouldNotBeNil)
						})

						Convey("should be able to unblock", func() {
							_, err = rest.UnblockChannelParticipant(channelContainer.Channel.Id, ownerSes.ClientId, secondAccount.Id)
							So(err, ShouldBeNil)

							Convey("it should not be in channel participant list still", func() {
								participants, err := rest.ListChannelParticipants(channelContainer.Channel.Id, ownerSes.ClientId)
								So(err, ShouldBeNil)
								So(participants, ShouldNotBeNil)
								So(len(participants), ShouldEqual, 3)
							})

							Convey("when we add the same user as participant", func() {
								_, err = rest.AddChannelParticipant(channelContainer.Channel.Id, ownerSes.ClientId, secondAccount.Id, thirdAccount.Id)
								So(err, ShouldBeNil)

								Convey("it should be in channel participant list", func() {
									participants, err := rest.ListChannelParticipants(channelContainer.Channel.Id, ownerSes.ClientId)
									So(err, ShouldBeNil)
									So(participants, ShouldNotBeNil)
									So(len(participants), ShouldEqual, 4)
								})
							})
						})
					})

					Convey("Second user should not be able to kick another conversation participant", func() {
						_, err = rest.DeleteChannelParticipant(channelContainer.Channel.Id, secondSes.ClientId, thirdAccount.Id)
						So(err, ShouldNotBeNil)
					})

				})
				Convey("First user should be able to invite second user", func() {
					_, err = rest.InviteChannelParticipant(channelContainer.Channel.Id, ownerSes.ClientId, secondAccount.Id)
					So(err, ShouldBeNil)
					participants, err := rest.ListChannelParticipants(channelContainer.Channel.Id, ownerSes.ClientId)
					So(err, ShouldBeNil)
					So(participants, ShouldNotBeNil)
					// it is four because first user is "devrim" here
					So(len(participants), ShouldEqual, 2)

					Convey("Second user should be able to reject invitation", func() {
						ses, err := modelhelper.FetchOrCreateSession(secondAccount.Nick, groupName)
						So(err, ShouldBeNil)
						So(ses, ShouldNotBeNil)

						err = rest.RejectInvitation(channelContainer.Channel.Id, ses.ClientId)
						So(err, ShouldBeNil)

						participants, err := rest.ListChannelParticipants(channelContainer.Channel.Id, ownerSes.ClientId)
						So(err, ShouldBeNil)
						So(participants, ShouldNotBeNil)
						So(len(participants), ShouldEqual, 2)
					})

					Convey("Second user should be able to accept invitation", func() {
						ses, err := modelhelper.FetchOrCreateSession(secondAccount.Nick, groupName)
						So(err, ShouldBeNil)
						So(ses, ShouldNotBeNil)

						err = rest.AcceptInvitation(channelContainer.Channel.Id, ses.ClientId)
						So(err, ShouldBeNil)

						participants, err := rest.ListChannelParticipants(channelContainer.Channel.Id, ownerSes.ClientId)
						So(err, ShouldBeNil)
						So(participants, ShouldNotBeNil)
						So(len(participants), ShouldEqual, 3)
					})
				})

				// TODO Until we find a better way for handling async stuff, this test is skipped. Instead of sleep, we should use some
				// timeouts for testing these kind of stuff.
				SkipConvey("All private messages must be deleted when all participant users leave the channel", func() {
					account := models.NewAccount()
					err = account.ByNick("devrim")
					So(err, ShouldBeNil)

					_, err = rest.DeleteChannelParticipant(channelContainer.Channel.Id, ses.ClientId, account.Id)
					So(err, ShouldBeNil)

					_, err = rest.DeleteChannelParticipant(channelContainer.Channel.Id, ownerSes.ClientId, ownerAccount.Id)
					So(err, ShouldBeNil)

					time.Sleep(1 * time.Second)

					testChannel := models.NewChannel()
					err := testChannel.ById(channelContainer.Channel.Id)
					So(err, ShouldEqual, bongo.RecordNotFound)

					testChannelList := models.NewChannelMessageList()
					err = bongo.B.Unscoped().Where("channel_id = ?", channelContainer.Channel.Id).Find(testChannelList).Error
					So(err, ShouldEqual, bongo.RecordNotFound)

					testMessage := models.NewChannelMessage()
					err = bongo.B.Unscoped().Where("initial_channel_id = ?", channelContainer.Channel.Id).Find(testMessage).Error
					So(err, ShouldEqual, bongo.RecordNotFound)
				})
				Convey("Users should not be able to add/remove users to/from bot channels", func() {
					ownerAccount, _, groupName := models.CreateRandomGroupDataWithChecks()

					participant := models.NewAccount()
					participant.OldId = AccountOldId.Hex()
					participant, err = rest.CreateAccount(participant)
					So(err, ShouldBeNil)
					So(participant, ShouldNotBeNil)

					ses, err := modelhelper.FetchOrCreateSession(ownerAccount.Nick, groupName)
					So(err, ShouldBeNil)

					ch, err := rest.CreateChannelByGroupNameAndType(ownerAccount.Id, groupName, models.Channel_TYPE_BOT, ses.ClientId)
					So(err, ShouldBeNil)
					So(ch, ShouldNotBeNil)

					// account is -> ownerAccount.Id
					_, err = rest.AddChannelParticipant(ch.Id, ses.ClientId, participant.Id)
					So(strings.Contains(err.Error(), "can not add participants for bot channel"), ShouldBeTrue)
				})

				Convey("Users should be able to add/remove users to/from topic channels", func() {
					ownerAccount, _, groupName := models.CreateRandomGroupDataWithChecks()

					participant := models.NewAccount()
					participant.OldId = AccountOldId.Hex()
					participant, err = rest.CreateAccount(participant)
					So(err, ShouldBeNil)
					So(participant, ShouldNotBeNil)

					ses, err := modelhelper.FetchOrCreateSession(ownerAccount.Nick, groupName)
					So(err, ShouldBeNil)

					ch, err := rest.CreateChannelByGroupNameAndType(ownerAccount.Id, groupName, models.Channel_TYPE_TOPIC, ses.ClientId)
					So(err, ShouldBeNil)
					So(ch, ShouldNotBeNil)

					// account is -> ownerAccount.Id
					_, err = rest.AddChannelParticipant(ch.Id, ses.ClientId, participant.Id)
					So(err, ShouldBeNil)

					Convey("adding same user again should success", func() {
						_, err = rest.AddChannelParticipant(ch.Id, ses.ClientId, participant.Id)
						So(err, ShouldBeNil)
					})

					_, err = rest.DeleteChannelParticipant(ch.Id, ses.ClientId, participant.Id)
					So(err, ShouldBeNil)

					Convey("removing same user again should success", func() {
						_, err = rest.DeleteChannelParticipant(ch.Id, ses.ClientId, participant.Id)
						So(err, ShouldBeNil)
					})
				})
				Convey("while removing users from group channels", func() {
					ownerAccount, _, groupName := models.CreateRandomGroupDataWithChecks()

					participant := models.NewAccount()
					participant.OldId = AccountOldId.Hex()
					participant, err = rest.CreateAccount(participant)
					So(err, ShouldBeNil)
					So(participant, ShouldNotBeNil)

					participant2 := models.NewAccount()
					participant2.OldId = AccountOldId.Hex()
					participant2, err = rest.CreateAccount(participant2)
					So(err, ShouldBeNil)
					So(participant2, ShouldNotBeNil)

					ownerSes, err := modelhelper.FetchOrCreateSession(ownerAccount.Nick, groupName)
					So(err, ShouldBeNil)

					ses, err := modelhelper.FetchOrCreateSession(participant.Nick, groupName)
					So(err, ShouldBeNil)

					ch, err := rest.CreateChannelByGroupNameAndType(ownerAccount.Id, groupName, models.Channel_TYPE_GROUP, ownerSes.ClientId)
					So(err, ShouldBeNil)
					So(ch, ShouldNotBeNil)

					// ownerSes session is admin's session data
					_, err = rest.AddChannelParticipant(ch.Id, ownerSes.ClientId, participant.Id)
					So(err, ShouldBeNil)

					_, err = rest.AddChannelParticipant(ch.Id, ownerSes.ClientId, participant2.Id)
					So(err, ShouldBeNil)
					Convey("owner should  be able to remove user from group channel", func() {
						// ownerSes session is admin's session data
						_, err = rest.DeleteChannelParticipant(ch.Id, ownerSes.ClientId, participant2.Id)
						So(err, ShouldBeNil)
					})

					Convey("nonOwner should not be able to remove user from group channel", func() {
						// ses session is participant's session data
						_, err = rest.DeleteChannelParticipant(ch.Id, ses.ClientId, participant2.Id)
						So(err, ShouldNotBeNil)
					})
				})
			})
		})
	})
}
Exemple #23
0
func TestChannelUpdatedCalculateUnreadItemCount(t *testing.T) {
	r := runner.New("test")
	if err := r.Init(); err != nil {
		t.Fatalf("couldnt start bongo %s", err.Error())
	}
	defer r.Close()

	config.MustRead(r.Conf.Path)

	groupName := models.RandomGroupName()

	Convey("while testing unread count", t, func() {
		Convey("channel should be set", func() {
			cue := &channelUpdatedEvent{}
			unreadCount, err := cue.calculateUnreadItemCount()
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, models.ErrChannelIsNotSet)
			So(unreadCount, ShouldEqual, 0)
		})

		Convey("unread count for group channel can not be calculated", func() {
			c := models.NewChannel()
			c.TypeConstant = models.Channel_TYPE_GROUP
			cue := &channelUpdatedEvent{
				Channel: c,
			}
			unreadCount, err := cue.calculateUnreadItemCount()
			So(err, ShouldNotBeNil)
			So(err.Error(), ShouldContainSubstring, "not supported channel type for unread count calculation")
			So(unreadCount, ShouldEqual, 0)
		})

		Convey("unread count for following feed channel can not be calculated", func() {
			c := models.NewChannel()
			c.TypeConstant = models.Channel_TYPE_FOLLOWINGFEED
			cue := &channelUpdatedEvent{
				Channel: c,
			}
			unreadCount, err := cue.calculateUnreadItemCount()
			So(err, ShouldNotBeNil)
			So(err.Error(), ShouldContainSubstring, "not supported channel type for unread count calculation")
			So(unreadCount, ShouldEqual, 0)
		})

		Convey("unread count for followers feed channel can not be calculated", func() {
			c := models.NewChannel()
			c.TypeConstant = models.Channel_TYPE_FOLLOWERS
			cue := &channelUpdatedEvent{
				Channel: c,
			}
			unreadCount, err := cue.calculateUnreadItemCount()
			So(err, ShouldNotBeNil)
			So(err.Error(), ShouldContainSubstring, "not supported channel type for unread count calculation")
			So(unreadCount, ShouldEqual, 0)
		})

		Convey("unread count for default channel can not be calculated", func() {
			c := models.NewChannel()
			c.TypeConstant = models.Channel_TYPE_DEFAULT
			cue := &channelUpdatedEvent{
				Channel: c,
			}
			unreadCount, err := cue.calculateUnreadItemCount()
			So(err, ShouldNotBeNil)
			So(err.Error(), ShouldContainSubstring, "not supported channel type for unread count calculation")
			So(unreadCount, ShouldEqual, 0)
		})

		Convey("channel participant should be set", func() {
			c := models.NewChannel()
			c.TypeConstant = models.Channel_TYPE_TOPIC
			cue := &channelUpdatedEvent{
				Channel: c,
			}
			unreadCount, err := cue.calculateUnreadItemCount()
			So(err, ShouldNotBeNil)
			So(err, ShouldEqual, models.ErrChannelParticipantIsNotSet)
			So(unreadCount, ShouldEqual, 0)
		})

		SkipConvey("pinned message's unread count could be calculated", func() {
			// create an account
			account, err := createAccount()
			So(err, ShouldBeNil)
			So(account, ShouldNotBeNil)

			// create their pinned activity channel
			c, err := models.EnsurePinnedActivityChannel(account.Id, groupName)
			So(err, ShouldBeNil)
			So(c, ShouldNotBeNil)

			// fetch participant
			cp, err := c.FetchParticipant(account.Id)
			So(err, ShouldBeNil)
			So(cp, ShouldNotBeNil)

			// create message
			cm := models.NewChannelMessage()
			cm.AccountId = account.Id
			// this cahnnel should be group channel
			cm.InitialChannelId = c.Id
			cm.Body = "hello all from test"
			So(cm.Create(), ShouldBeNil)

			// add message to the list
			cml, err := c.AddMessage(cm)
			So(err, ShouldBeNil)
			So(cml, ShouldNotBeNil)

			cue := &channelUpdatedEvent{
				Channel:              c,
				ChannelParticipant:   cp,
				ParentChannelMessage: cm,
			}

			unreadCount, err := cue.calculateUnreadItemCount()
			So(err, ShouldBeNil)
			So(unreadCount, ShouldEqual, 0)

			// add replies to the message
			addRepliesToMessage(c.Id, account.Id, cm.Id)
			addRepliesToMessage(c.Id, account.Id, cm.Id)

			cue = &channelUpdatedEvent{
				Channel:              c,
				ChannelParticipant:   cp,
				ParentChannelMessage: cm,
			}

			unreadCount, err = cue.calculateUnreadItemCount()
			So(err, ShouldBeNil)
			So(unreadCount, ShouldEqual, 2)

			// glance message
			cml.Glance()
			//after glancing the message, unread count should be zero

			cue = &channelUpdatedEvent{
				Channel:              c,
				ChannelParticipant:   cp,
				ParentChannelMessage: cm,
			}

			unreadCount, err = cue.calculateUnreadItemCount()
			So(err, ShouldBeNil)
			So(unreadCount, ShouldEqual, 0)
		})

		Convey("private message's unread count could be calculated", func() {
			// create an account
			account, err := createAccount()
			So(err, ShouldBeNil)
			So(account, ShouldNotBeNil)

			// create private message channel
			c := models.NewPrivateMessageChannel(account.Id, groupName)
			So(c.Create(), ShouldBeNil)

			// add participant into channel
			cp, err := c.AddParticipant(account.Id)
			So(err, ShouldBeNil)
			So(cp, ShouldNotBeNil)

			// create message
			cm := models.NewChannelMessage()
			cm.AccountId = account.Id
			cm.InitialChannelId = c.Id
			cm.Body = "hello all from test"
			So(cm.Create(), ShouldBeNil)

			// add message to the list
			// but message is already added into channel
			cml, err := c.EnsureMessage(cm, false)
			So(err, ShouldBeNil)
			So(cml, ShouldNotBeNil)

			cue := &channelUpdatedEvent{
				Channel:              c,
				ChannelParticipant:   cp,
				ParentChannelMessage: cm,
			}

			// calculate unread count
			unreadCount, err := cue.calculateUnreadItemCount()
			So(err, ShouldBeNil)
			So(unreadCount, ShouldEqual, 1)

			cp.LastSeenAt = time.Now().UTC()
			So(cp.Update(), ShouldBeNil)

			// calculate unread count
			unreadCount, err = cue.calculateUnreadItemCount()
			So(err, ShouldBeNil)
			So(unreadCount, ShouldEqual, 0)
		})

		Convey("collaboration channel's unread count could be calculated", func() {
			// create an account
			account, err := createAccount()
			So(err, ShouldBeNil)
			So(account, ShouldNotBeNil)

			// create private message channel
			c := models.NewCollaborationChannel(account.Id, groupName)
			So(c.Create(), ShouldBeNil)

			// add participant into channel
			cp, err := c.AddParticipant(account.Id)
			So(err, ShouldBeNil)
			So(cp, ShouldNotBeNil)

			// create message
			cm := models.NewChannelMessage()
			cm.AccountId = account.Id
			cm.InitialChannelId = c.Id
			cm.Body = "hello all from test"
			So(cm.Create(), ShouldBeNil)

			// add message to the list
			cml, err := c.EnsureMessage(cm, false)
			So(err, ShouldBeNil)
			So(cml, ShouldNotBeNil)

			cue := &channelUpdatedEvent{
				Channel:              c,
				ChannelParticipant:   cp,
				ParentChannelMessage: cm,
			}

			// calculate unread count
			unreadCount, err := cue.calculateUnreadItemCount()
			So(err, ShouldBeNil)
			So(unreadCount, ShouldEqual, 1)

			cp.LastSeenAt = time.Now().UTC()
			So(cp.Update(), ShouldBeNil)

			// calculate unread count
			unreadCount, err = cue.calculateUnreadItemCount()
			So(err, ShouldBeNil)
			So(unreadCount, ShouldEqual, 0)
		})

		Convey("topic channel's unread count could be calculated", func() {
			// create an account
			account, err := createAccount()
			So(err, ShouldBeNil)
			So(account, ShouldNotBeNil)

			// create private message channel
			c, err := createTypedChannel(account.Id, groupName, models.Channel_TYPE_TOPIC)
			So(err, ShouldBeNil)
			So(c.Create(), ShouldBeNil)

			// add participant into channel
			cp, err := c.AddParticipant(account.Id)
			So(err, ShouldBeNil)
			So(cp, ShouldNotBeNil)

			// create message
			cm := models.NewChannelMessage()
			cm.AccountId = account.Id
			cm.InitialChannelId = c.Id
			cm.Body = "hello all from test"
			So(cm.Create(), ShouldBeNil)

			// add message to the list
			cml, err := c.AddMessage(cm)
			So(err, ShouldBeNil)
			So(cml, ShouldNotBeNil)

			cue := &channelUpdatedEvent{
				Channel:              c,
				ChannelParticipant:   cp,
				ParentChannelMessage: cm,
			}

			// calculate unread count
			unreadCount, err := cue.calculateUnreadItemCount()
			So(err, ShouldBeNil)
			So(unreadCount, ShouldEqual, 1)

			cp.LastSeenAt = time.Now().UTC()
			So(cp.Update(), ShouldBeNil)

			// calculate unread count
			unreadCount, err = cue.calculateUnreadItemCount()
			So(err, ShouldBeNil)
			So(unreadCount, ShouldEqual, 0)
		})

		Convey("announcement channel's unread count could be calculated", func() {
			// create an account
			account, err := createAccount()
			So(err, ShouldBeNil)
			So(account, ShouldNotBeNil)

			// create private message channel
			c, err := createTypedChannel(account.Id, groupName, models.Channel_TYPE_ANNOUNCEMENT)
			So(err, ShouldBeNil)
			So(c.Create(), ShouldBeNil)

			// add participant into channel
			cp, err := c.AddParticipant(account.Id)
			So(err, ShouldBeNil)
			So(cp, ShouldNotBeNil)

			// create message
			cm := models.NewChannelMessage()
			cm.AccountId = account.Id
			cm.InitialChannelId = c.Id
			cm.Body = "hello all from test"
			So(cm.Create(), ShouldBeNil)

			// add message to the list
			cml, err := c.EnsureMessage(cm, false)
			So(err, ShouldBeNil)
			So(cml, ShouldNotBeNil)

			cue := &channelUpdatedEvent{
				Channel:              c,
				ChannelParticipant:   cp,
				ParentChannelMessage: cm,
			}

			// calculate unread count
			unreadCount, err := cue.calculateUnreadItemCount()
			So(err, ShouldBeNil)
			So(unreadCount, ShouldEqual, 1)

			cp.LastSeenAt = time.Now().UTC()
			So(cp.Update(), ShouldBeNil)

			// calculate unread count
			unreadCount, err = cue.calculateUnreadItemCount()
			So(err, ShouldBeNil)
			So(unreadCount, ShouldEqual, 0)
		})
	})
}
Exemple #24
0
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()
}