Ejemplo n.º 1
0
// 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()
}
Ejemplo n.º 2
0
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)
}
Ejemplo n.º 3
0
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)))
}
Ejemplo n.º 4
0
// 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)
}
Ejemplo n.º 5
0
// 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())
}
Ejemplo n.º 6
0
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)
}
Ejemplo n.º 7
0
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),
	)
}
Ejemplo n.º 8
0
func Update(u *url.URL, h http.Header, req *models.ChannelMessage, c *models.Context) (int, http.Header, interface{}, error) {
	if !c.IsLoggedIn() {
		return response.NewBadRequest(models.ErrAccessDenied)
	}

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

	body := req.Body
	payload := req.Payload
	if err := req.ById(id); err != nil {
		if err == bongo.RecordNotFound {
			return response.NewNotFound()
		}
		return response.NewBadRequest(err)
	}

	if req.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 req.Id == 0 {
		return response.NewBadRequest(err)
	}

	req.Body = body
	req.Payload = payload

	if err := req.Update(); err != nil {
		return response.NewBadRequest(err)
	}

	cmc := models.NewChannelMessageContainer()
	return response.HandleResultAndError(cmc, cmc.Fetch(id, request.GetQuery(u)))
}
Ejemplo n.º 9
0
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)
}
Ejemplo n.º 10
0
func Get(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) {
	id, err := request.GetURIInt64(u, "id")
	if err != nil {
		return response.NewBadRequest(err)
	}

	q := request.GetQuery(u)
	q = context.OverrideQuery(q)

	c := models.NewChannel()
	if err := c.ById(id); err != nil {
		if err == bongo.RecordNotFound {
			return response.NewNotFound()
		}
		return response.NewBadRequest(err)
	}

	return handleChannelResponse(*c, q)
}
Ejemplo n.º 11
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)
}
Ejemplo n.º 12
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)
}
Ejemplo n.º 13
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()
}