// 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) }
// 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 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)) }
func updateStatus(participant *models.ChannelParticipant, query *request.Query, ctx *models.Context) (*models.ChannelParticipant, error) { if ok := ctx.IsLoggedIn(); !ok { return nil, models.ErrNotLoggedIn } query.AccountId = ctx.Client.Account.Id cp := models.NewChannelParticipant() cp.ChannelId = query.Id // check if the user is invited isInvited, err := cp.IsInvited(query.AccountId) if err != nil { return nil, err } if !isInvited { return nil, errors.New("uninvited user error") } cp.StatusConstant = participant.StatusConstant // update the status if err := cp.Update(); err != nil { return nil, err } return cp, nil }
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) }
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 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) }
// 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 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) }
// GetSubscription gets the subscription of group func GetSubscription(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } return response.HandleResultAndError( payment.GetSubscriptionForGroup(context.GroupName), ) }
// CreateSubscription creates the subscription of group func CreateSubscription(u *url.URL, h http.Header, params *stripe.SubParams, context *models.Context) (int, http.Header, interface{}, error) { if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } return response.HandleResultAndError( payment.EnsureSubscriptionForGroup(context.GroupName, params), ) }
// createLogger creates the log system for sneaker S3 storage func (s *SneakerS3) createLogger(context *models.Context, reqType, keyPath string, statusCode int) logging.Logger { ctx := s.log.New("SneakerS3") if context.IsLoggedIn() { return ctx.New("IP", context.Client.IP, "requester", context.Client.Account.Nick, "operation", reqType, "key path", keyPath, "status code", statusCode) } else { return ctx.New("operation", reqType, "key path", keyPath, "status code", statusCode) } }
// 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)) }
func Send(u *url.URL, h http.Header, req *models.ChannelRequest, ctx *models.Context) (int, http.Header, interface{}, error) { // check if user logged in or not if !ctx.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } req.AccountId = ctx.Client.Account.Id req.GroupName = ctx.GroupName return response.HandleResultAndError(req.Send()) }
// 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)) }
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)) }
// Ping handles the pings coming from client side func Ping(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { // only logged in users can send a ping if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } req := &presence.Ping{ GroupName: context.GroupName, AccountID: context.Client.Account.Id, // if client is logged in, those values are all set } return handlePing(u, h, req) }
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)) }
// 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 validateOperation(req *models.Ping, context *apimodels.Context) error { // realtime doc id if req.FileId == "" { return errors.New("fileId not set") } // only logged in users can send a ping if !context.IsLoggedIn() { return errors.New("not logged in") } // override the account id and set created at req.AccountId = context.Client.Account.Id // if client is logged in, those values are all set req.CreatedAt = time.Now().UTC() return collaboration.CanOpen(req) }
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 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))) }
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 (h *Handler) SubscribeNotification(u *url.URL, header http.Header, temp *socialapimodels.Account, context *socialapimodels.Context) (int, http.Header, interface{}, error) { if !context.IsLoggedIn() { return response.NewBadRequest(socialapimodels.ErrNotLoggedIn) } account := context.Client.Account // authenticate user to their notification channel a := new(models.Authenticate) a.Channel = models.NewNotificationChannel(account) a.Account = account // TODO need async requests. Re-try in case of an error err := h.pubnub.Authenticate(a) if err != nil { return response.NewBadRequest(err) } return responseWithCookie(temp, account.Token) }
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}) }
// ListChannels lists the channels of a slack team func (s *Slack) ListChannels(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { if !context.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } var groupToken string userToken, err := getSlackToken(context) if err != nil || userToken == "" { groupToken, err = getAnySlackTokenWithGroup(context) if err != nil { return response.NewBadRequest(err) } } if userToken != "" { return response.HandleResultAndError(getChannels(userToken)) } else { return response.HandleResultAndError(getOnlyChannels(groupToken)) } }
func ListGroupChannels(u *url.URL, h http.Header, _ interface{}, c *models.Context) (int, http.Header, interface{}, error) { if !c.IsLoggedIn() { return response.NewBadRequest(models.ErrNotLoggedIn) } cp := models.NewChannelParticipant() cids, err := cp.FetchAllParticipatedChannelIdsInGroup(c.Client.Account.Id, c.GroupName) if err != nil { return response.NewBadRequest(err) } channels, err := models.NewChannel().FetchByIds(cids) if err != nil { return response.NewBadRequest(err) } cc := models.NewChannelContainers() cc.PopulateWith(channels, c.Client.Account.Id) return response.HandleResultAndError(cc, cc.Err()) }
// 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 (s *SneakerS3) Delete(u *url.URL, h http.Header, _ interface{}, context *models.Context) (int, http.Header, interface{}, error) { pathName := u.Query().Get("pathName") logger := s.createLogger(context, "Delete", pathName, http.StatusBadRequest) if pathName == "" { return response.NewBadRequestWithLogger(logger, ErrPathNotFound) } if !context.IsLoggedIn() { return response.NewBadRequestWithLogger(logger, models.ErrNotLoggedIn) } err := s.Manager.Rm(pathName) if err != nil { return response.NewBadRequestWithLogger(logger, err) } logger = s.createLogger(context, "Delete", pathName, http.StatusAccepted) logger.Info("") return response.NewDeleted() }