func (m *MessagesController) checkDMTopic(ctx *gin.Context, topicName string) (models.Topic, string, error) { var topic = models.Topic{} topicParentName := "/Private/" + utils.GetCtxUsername(ctx) + "/DM" if !strings.HasPrefix(topicName, topicParentName+"/") { log.Errorf("wrong topic name for DM:" + topicName) return topic, "", errors.New("Wrong tpic name for DM:" + topicName) } // /Private/usernameFrom/DM/usernameTO part := strings.Split(topicName, "/") if len(part) != 5 { log.Errorf("wrong topic name for DM") return topic, "", errors.New("Wrong topic name for DM:" + topicName) } var userFrom = models.User{} err := userFrom.FindByUsername(utils.GetCtxUsername(ctx)) if err != nil { return topic, "", errors.New("Error while fetching user.") } var userTo = models.User{} usernameTo := part[4] err = userTo.FindByUsername(usernameTo) if err != nil { return topic, "", errors.New("Error while fetching user.") } err = m.checkTopicParentDM(userFrom) if err != nil { return topic, "", errors.New(err.Error()) } err = m.checkTopicParentDM(userTo) if err != nil { return topic, "", errors.New(err.Error()) } topic, err = m.insertTopicDM(userFrom, userTo) if err != nil { return topic, "", errors.New(err.Error()) } _, err = m.insertTopicDM(userTo, userFrom) if err != nil { return topic, "", errors.New(err.Error()) } topicCriteria := topicName + "," + "/Private/" + usernameTo + "/DM/" + userFrom.Username return topic, topicCriteria, nil }
func (m *MessagesController) inverseIfDMTopic(ctx *gin.Context, topicName string) string { if !strings.HasPrefix(topicName, "/Private/") { return topicName } if !strings.HasSuffix(topicName, "/DM/"+utils.GetCtxUsername(ctx)) { return topicName } // /Private/usernameFrom/DM/usernameTO part := strings.Split(topicName, "/") if len(part) != 5 { return topicName } return "/Private/" + utils.GetCtxUsername(ctx) + "/DM/" + part[2] }
// Contacts retrieves contacts presences since n seconds func (*UsersController) Contacts(ctx *gin.Context) { sinceSeconds, err := GetParam(ctx, "sinceSeconds") if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"error": "Error while getting seconds parameter"}) return } seconds, err := strconv.ParseInt(sinceSeconds, 10, 64) if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid since parameter : must be an interger"}) return } var user = models.User{} err = user.FindByUsername(utils.GetCtxUsername(ctx)) if err != nil { ctx.JSON(http.StatusInternalServerError, errors.New("Error while fetching user")) return } criteria := models.PresenceCriteria{} for _, contact := range user.Contacts { criteria.Username = criteria.Username + "," + contact.Username } criteria.DateMinPresence = strconv.FormatInt(time.Now().Unix()-seconds, 10) count, presences, _ := models.ListPresences(&criteria) out := &contactsJSON{ Contacts: user.Contacts, CountContactsPresences: count, ContactsPresences: &presences, } ctx.JSON(http.StatusOK, out) }
// Convert a "normal" user to a "system" user func (*UsersController) Convert(ctx *gin.Context) { var convertJSON convertUserJSON ctx.Bind(&convertJSON) if !strings.HasPrefix(convertJSON.Username, "tat.system") { AbortWithReturnError(ctx, http.StatusBadRequest, fmt.Errorf("Username does not begin with tat.system (%s), it's not possible to convert this user", convertJSON.Username)) return } var userToConvert = models.User{} err := userToConvert.FindByUsername(convertJSON.Username) if err != nil { AbortWithReturnError(ctx, http.StatusBadRequest, fmt.Errorf("user with username %s does not exist", convertJSON.Username)) return } if userToConvert.IsSystem { AbortWithReturnError(ctx, http.StatusBadRequest, fmt.Errorf("user with username %s is already a system user", convertJSON.Username)) return } newPassword, err := userToConvert.ConvertToSystem(utils.GetCtxUsername(ctx), convertJSON.CanWriteNotifications) if err != nil { AbortWithReturnError(ctx, http.StatusBadRequest, fmt.Errorf("Convert %s to system user failed", convertJSON.Username)) return } ctx.JSON(http.StatusOK, gin.H{ "message": "Verification successfull", "username": userToConvert.Username, "password": newPassword, "url": fmt.Sprintf("%s://%s:%s%s", viper.GetString("exposed_scheme"), viper.GetString("exposed_host"), viper.GetString("exposed_port"), viper.GetString("exposed_path")), }) }
// Delete deletes requested topic only if user is Tat admin, or admin on topic func (t *TopicsController) Delete(ctx *gin.Context) { topicRequest, err := GetParam(ctx, "topic") if err != nil { return } var user = models.User{} err = user.FindByUsername(utils.GetCtxUsername(ctx)) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Error while fetching user."}) return } paramJSON := paramTopicUserJSON{ Topic: topicRequest, Username: user.Username, Recursive: false, } topic, e := t.preCheckUser(ctx, ¶mJSON) if e != nil { return } err = topic.Delete(&user) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, errors.New(err.Error())) return } ctx.JSON(http.StatusOK, "") }
// OneTopic returns only requested topic, and only if user has read access func (t *TopicsController) OneTopic(ctx *gin.Context) { topicRequest, err := GetParam(ctx, "topic") if err != nil { return } var user = models.User{} err = user.FindByUsername(utils.GetCtxUsername(ctx)) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Error while fetching user."}) return } topic := &models.Topic{} errfinding := topic.FindByTopic(topicRequest, user.IsAdmin) if errfinding != nil { ctx.JSON(http.StatusInternalServerError, errfinding) return } isReadAccess := topic.IsUserReadAccess(user) if !isReadAccess { ctx.JSON(http.StatusInternalServerError, errors.New("No Read Access to this topic: "+user.Username+" "+topic.Topic)) return } out := &topicJSON{Topic: topic} ctx.JSON(http.StatusOK, out) }
func (m *PresencesController) listWithCriteria(ctx *gin.Context, criteria *models.PresenceCriteria) { user, e := m.preCheckUser(ctx) if e != nil { return } var topic = models.Topic{} err := topic.FindByTopic(criteria.Topic, true) if err != nil { ctx.AbortWithError(http.StatusBadRequest, errors.New("topic "+criteria.Topic+" does not exist")) return } isReadAccess := topic.IsUserReadAccess(user) if !isReadAccess { ctx.AbortWithError(http.StatusForbidden, errors.New("No Read Access to this topic.")) return } // add / if search on topic // as topic is in path, it can't start with a / if criteria.Topic != "" && string(criteria.Topic[0]) != "/" { criteria.Topic = "/" + criteria.Topic } topicDM := "/Private/" + utils.GetCtxUsername(ctx) + "/DM/" if strings.HasPrefix(criteria.Topic, topicDM) { part := strings.Split(criteria.Topic, "/") if len(part) != 5 { log.Errorf("wrong topic name for DM") ctx.AbortWithError(http.StatusInternalServerError, errors.New("Wrong topic name for DM:"+criteria.Topic)) return } topicInverse := "/Private/" + part[4] + "/DM/" + utils.GetCtxUsername(ctx) criteria.Topic = criteria.Topic + "," + topicInverse } count, presences, err := models.ListPresences(criteria) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, err) return } out := &presencesJSON{ Count: count, Presences: presences, } ctx.JSON(http.StatusOK, out) }
func (*PresencesController) preCheckUser(ctx *gin.Context) (models.User, error) { var user = models.User{} err := user.FindByUsername(utils.GetCtxUsername(ctx)) if err != nil { e := errors.New("Error while fetching user.") ctx.AbortWithError(http.StatusInternalServerError, e) return user, e } return user, nil }
// Me retrieves all information about me (exception information about Authentication) func (*UsersController) Me(ctx *gin.Context) { var user = models.User{} err := user.FindByUsername(utils.GetCtxUsername(ctx)) if err != nil { AbortWithReturnError(ctx, http.StatusInternalServerError, errors.New("Error while fetching user")) return } out := &userJSON{User: &user} ctx.JSON(http.StatusOK, out) }
// List returns the list of topics that can be viewed by user func (t *TopicsController) List(ctx *gin.Context) { criteria := t.buildCriteria(ctx) var user = &models.User{} err := user.FindByUsername(utils.GetCtxUsername(ctx)) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Error while fetching user."}) return } count, topics, err := models.ListTopics(criteria, user) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Error while fetching topics."}) return } out := &topicsJSON{Topics: topics, Count: count} if criteria.GetNbMsgUnread == "true" { c := &models.PresenceCriteria{ Username: user.Username, } count, presences, err := models.ListPresencesAllFields(c) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, err) return } unread := make(map[string]int) knownPresence := false for _, topic := range topics { if utils.ArrayContains(user.OffNotificationsTopics, topic.Topic) { continue } knownPresence = false for _, presence := range presences { if topic.Topic != presence.Topic { continue } knownPresence = true nb, err := models.CountMsgSinceDate(presence.Topic, presence.DatePresence) if err != nil { ctx.JSON(http.StatusInternalServerError, err) return } unread[presence.Topic] = nb } if !knownPresence { unread[topic.Topic] = -1 } } out.TopicsMsgUnread = unread out.CountTopicsMsgUnread = count } ctx.JSON(http.StatusOK, out) }
func (m *MessagesController) getTopicNonPrivateTasks(ctx *gin.Context, topics []string) (string, error) { // if msg is only in topic Tasks topicTasks := "/Private/" + utils.GetCtxUsername(ctx) + "/Tasks" for _, name := range topics { if !strings.HasPrefix(name, "/Private") { return name, nil } if !strings.HasPrefix(topics[0], topicTasks) { return name, nil } } return "", errors.New("Could not get non private task topic ") }
// AddAdminUser add a user to a group func (g *GroupsController) AddAdminUser(ctx *gin.Context) { var paramJSON paramUserJSON ctx.Bind(¶mJSON) group, e := g.preCheckUser(ctx, ¶mJSON) if e != nil { return } err := group.AddAdminUser(utils.GetCtxUsername(ctx), paramJSON.Username) if err != nil { return } ctx.JSON(http.StatusCreated, "") }
// AddRoUser add a readonly user on selected topic func (t *TopicsController) AddRoUser(ctx *gin.Context) { var paramJSON paramTopicUserJSON ctx.Bind(¶mJSON) topic, e := t.preCheckUser(ctx, ¶mJSON) if e != nil { return } err := topic.AddRoUser(utils.GetCtxUsername(ctx), paramJSON.Username, paramJSON.Recursive) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, errors.New(err.Error())) return } ctx.JSON(http.StatusCreated, "") }
// RemoveAdminGroup removes an admin group on selected topic func (t *TopicsController) RemoveAdminGroup(ctx *gin.Context) { var paramJSON paramGroupJSON ctx.Bind(¶mJSON) topic, e := t.preCheckGroup(ctx, ¶mJSON) if e != nil { return } err := topic.RemoveAdminGroup(utils.GetCtxUsername(ctx), paramJSON.Groupname, paramJSON.Recursive) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, errors.New(err.Error())) return } ctx.JSON(http.StatusOK, "") }
// SetParam update Topic Parameters : MaxLength, CanForeceDate, CanUpdateMsg, CanDeleteMsg, CanUpdateAllMsg, CanDeleteAllMsg, IsROPublic // admin only, except on Private topic func (t *TopicsController) SetParam(ctx *gin.Context) { var paramJSON paramJSON ctx.Bind(¶mJSON) topic := models.Topic{} var err error if strings.HasPrefix(paramJSON.Topic, "/Private/"+utils.GetCtxUsername(ctx)) { err := topic.FindByTopic(paramJSON.Topic, false) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Error while fetching topic /Private/" + utils.GetCtxUsername(ctx)}) return } } else { topic, err = t.preCheckUserAdminOnTopic(ctx, paramJSON.Topic) if err != nil { ctx.JSON(http.StatusInternalServerError, err) return } } err = topic.SetParam(utils.GetCtxUsername(ctx), paramJSON.Recursive, paramJSON.MaxLength, paramJSON.CanForceDate, paramJSON.CanUpdateMsg, paramJSON.CanDeleteMsg, paramJSON.CanUpdateAllMsg, paramJSON.CanDeleteAllMsg, paramJSON.IsROPublic) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, errors.New(err.Error())) return } ctx.JSON(http.StatusCreated, "") }
// Create a new message on one topic func (m *MessagesController) Create(ctx *gin.Context) { messageIn, messageReference, topic, e := m.preCheckTopic(ctx) if e != nil { return } user, e := PreCheckUser(ctx) if e != nil { return } isRw := topic.IsUserRW(&user) if !isRw { ctx.JSON(http.StatusForbidden, gin.H{"error": fmt.Sprintf("No RW Access to topic " + messageIn.Topic)}) return } var message = models.Message{} info := "" if messageIn.Action == "bookmark" { var originalUser = models.User{} err := originalUser.FindByUsername(utils.GetCtxUsername(ctx)) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, errors.New("Error while fetching original user.")) return } err = message.Insert(originalUser, topic, messageReference.Text, "", -1) if err != nil { log.Errorf("Error while InsertMessage with action %s : %s", messageIn.Action, err) ctx.AbortWithError(http.StatusInternalServerError, errors.New(err.Error())) return } info = fmt.Sprintf("New Bookmark created in %s", topic.Topic) } else { err := message.Insert(user, topic, messageIn.Text, messageIn.IDReference, messageIn.DateCreation) if err != nil { log.Errorf("Error while InsertMessage %s", err) ctx.AbortWithError(http.StatusInternalServerError, errors.New(err.Error())) return } go models.WSMessageNew(&models.WSMessageNewJSON{Topic: topic.Topic}) info = fmt.Sprintf("Message created in %s", topic.Topic) } out := &messageJSONOut{Message: message, Info: info} go models.WSMessage(&models.WSMessageJSON{Action: "create", Username: user.Username, Message: message}) ctx.JSON(http.StatusCreated, out) }
// AddParameter add a parameter on selected topic func (t *TopicsController) AddParameter(ctx *gin.Context) { var topicParameterJSON topicParameterJSON ctx.Bind(&topicParameterJSON) topic, e := t.preCheckUserAdminOnTopic(ctx, topicParameterJSON.Topic) if e != nil { return } err := topic.AddParameter(utils.GetCtxUsername(ctx), topicParameterJSON.Key, topicParameterJSON.Value, topicParameterJSON.Recursive) if err != nil { ctx.AbortWithError(http.StatusInternalServerError, errors.New(err.Error())) return } ctx.JSON(http.StatusCreated, "") }
// Create creates a new topic func (*TopicsController) Create(ctx *gin.Context) { var topicIn topicCreateJSON ctx.Bind(&topicIn) var user = models.User{} err := user.FindByUsername(utils.GetCtxUsername(ctx)) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Error while fetching user."}) return } var topic models.Topic topic.Topic = topicIn.Topic topic.Description = topicIn.Description err = topic.Insert(&user) if err != nil { log.Errorf("Error while InsertTopic %s", err) ctx.JSON(http.StatusInternalServerError, err) return } ctx.JSON(http.StatusCreated, topic) }
// Archive a user func (*UsersController) Archive(ctx *gin.Context) { var archiveJSON usernameUserJSON ctx.Bind(&archiveJSON) var userToArchive = models.User{} err := userToArchive.FindByUsername(archiveJSON.Username) if err != nil { AbortWithReturnError(ctx, http.StatusBadRequest, fmt.Errorf("user with username %s does not exist", archiveJSON.Username)) return } if userToArchive.IsArchived { AbortWithReturnError(ctx, http.StatusBadRequest, fmt.Errorf("user with username %s is already archived", archiveJSON.Username)) return } err = userToArchive.Archive(utils.GetCtxUsername(ctx)) if err != nil { AbortWithReturnError(ctx, http.StatusBadRequest, fmt.Errorf("archive user %s failed", archiveJSON.Username)) return } ctx.JSON(http.StatusCreated, "") }
// SetAdmin a "normal" user to an admin user func (*UsersController) SetAdmin(ctx *gin.Context) { var convertJSON convertUserJSON ctx.Bind(&convertJSON) var userToGrant = models.User{} err := userToGrant.FindByUsername(convertJSON.Username) if err != nil { AbortWithReturnError(ctx, http.StatusBadRequest, fmt.Errorf("user with username %s does not exist", convertJSON.Username)) return } if userToGrant.IsAdmin { AbortWithReturnError(ctx, http.StatusBadRequest, fmt.Errorf("user with username %s is already an admin user", convertJSON.Username)) return } err = userToGrant.ConvertToAdmin(utils.GetCtxUsername(ctx)) if err != nil { AbortWithReturnError(ctx, http.StatusBadRequest, fmt.Errorf("Convert %s to admin user failed", convertJSON.Username)) return } ctx.JSON(http.StatusCreated, "") }
// List messages on one topic, with given criterias func (m *MessagesController) List(ctx *gin.Context) { var criteria = m.buildCriteria(ctx) presenceArg := ctx.Query("presence") topicIn, err := GetParam(ctx, "topic") if err != nil { return } criteria.Topic = topicIn // add / if search on topic // as topic is in path, it can't start with a / if criteria.Topic != "" && string(criteria.Topic[0]) != "/" { criteria.Topic = "/" + criteria.Topic } var topic = models.Topic{} err = topic.FindByTopic(criteria.Topic, true) if err != nil { topicCriteria := "" _, topicCriteria, err = m.checkDMTopic(ctx, criteria.Topic) if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"error": "topic " + criteria.Topic + " does not exist"}) return } // hack to get new created DM Topic err := topic.FindByTopic(criteria.Topic, true) if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"error": "topic " + criteria.Topic + " does not exist (2)"}) return } criteria.Topic = topicCriteria } out := &messagesJSON{} var user models.User var e error if utils.GetCtxUsername(ctx) != "" { user, e = PreCheckUser(ctx) if e != nil { return } isReadAccess := topic.IsUserReadAccess(user) if !isReadAccess { ctx.JSON(http.StatusForbidden, gin.H{"error": "No Read Access to this topic"}) return } out.IsTopicRw = topic.IsUserRW(&user) } else if !topic.IsROPublic { ctx.JSON(http.StatusForbidden, gin.H{"error": "No Public Read Access Public to this topic"}) return } else if topic.IsROPublic && strings.HasPrefix(topic.Topic, "/Private") { ctx.JSON(http.StatusForbidden, gin.H{"error": "No Public Read Access to this topic"}) return } // send presence if presenceArg != "" && !user.IsSystem { go func() { var presence = models.Presence{} err := presence.Upsert(user, topic, presenceArg) if err != nil { log.Errorf("Error while InsertPresence %s", err) } go models.WSPresence(&models.WSPresenceJSON{Action: "create", Presence: presence}) }() } messages, err := models.ListMessages(criteria) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } out.Messages = messages ctx.JSON(http.StatusOK, out) }
func (m *MessagesController) preCheckTopic(ctx *gin.Context) (messageJSON, models.Message, models.Topic, error) { var topic = models.Topic{} var message = models.Message{} var messageIn messageJSON ctx.Bind(&messageIn) topicIn, err := GetParam(ctx, "topic") if err != nil { return messageIn, message, topic, err } messageIn.Topic = topicIn if messageIn.IDReference == "" || messageIn.Action == "" { err := topic.FindByTopic(messageIn.Topic, true) if err != nil { topic, _, err = m.checkDMTopic(ctx, messageIn.Topic) if err != nil { e := errors.New("Topic " + messageIn.Topic + " does not exist") ctx.JSON(http.StatusNotFound, gin.H{"error": e.Error()}) return messageIn, message, topic, e } } } else if messageIn.IDReference != "" { err := message.FindByID(messageIn.IDReference) if err != nil { e := errors.New("Message " + messageIn.IDReference + " does not exist") ctx.JSON(http.StatusNotFound, gin.H{"error": e.Error()}) return messageIn, message, topic, e } topicName := "" if messageIn.Action == "update" { topicName = messageIn.Topic } else if messageIn.Action == "reply" || messageIn.Action == "unbookmark" || messageIn.Action == "like" || messageIn.Action == "unlike" || messageIn.Action == "label" || messageIn.Action == "unlabel" || messageIn.Action == "tag" || messageIn.Action == "untag" { topicName = m.inverseIfDMTopic(ctx, message.Topics[0]) } else if messageIn.Action == "task" || messageIn.Action == "untask" { topicName, err = m.getTopicNonPrivateTasks(ctx, message.Topics) if err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return messageIn, message, topic, err } } else if messageIn.Action == "bookmark" { topicAction := m.getTopicNameFromAction(utils.GetCtxUsername(ctx), messageIn.Action) if !strings.HasPrefix(messageIn.Topic, topicAction) { e := fmt.Errorf("Invalid Topic name for action %s mTopic %s topicAction:%s ", messageIn.Action, messageIn.Topic, topicAction) ctx.JSON(http.StatusBadRequest, gin.H{"error": e.Error()}) return messageIn, message, topic, e } topicName = messageIn.Topic } else { e := errors.New("Invalid Call. IDReference not empty with unknown action") ctx.JSON(http.StatusBadRequest, gin.H{"error": e.Error()}) return messageIn, message, topic, e } err = topic.FindByTopic(topicName, true) if err != nil { e := errors.New("Topic " + topicName + " does not exist") ctx.JSON(http.StatusNotFound, gin.H{"error": e.Error()}) return messageIn, message, topic, e } } else { e := errors.New("Topic and IDReference are null. Wrong request") ctx.JSON(http.StatusBadRequest, gin.H{"error": e.Error()}) return messageIn, message, topic, e } return messageIn, message, topic, nil }