Exemplo n.º 1
0
Arquivo: messages.go Projeto: ovh/tat
func (m *MessagesController) innerList(ctx *gin.Context) (*tat.MessagesJSON, tat.User, tat.Topic, *tat.MessageCriteria, int, error) {
	var criteria = m.buildCriteria(ctx)

	if criteria.Limit <= 0 || criteria.Limit > 1000 {
		return nil, tat.User{}, tat.Topic{}, criteria, http.StatusBadRequest, fmt.Errorf("Please put a limit <= 50 for fetching message")
	}

	log.Debugf("criteria::---> %+v", criteria)
	out := &tat.MessagesJSON{}

	// we can't use NotLabel or NotTag with fulltree or onetree
	// this avoid potential wrong results associated with a short param limit
	if (criteria.NotLabel != "" || criteria.NotTag != "") &&
		(criteria.TreeView == tat.TreeViewFullTree || criteria.TreeView == tat.TreeViewOneTree) && criteria.OnlyMsgRoot == "" {
		return out, tat.User{}, tat.Topic{}, criteria, http.StatusBadRequest, fmt.Errorf("You can't use fulltree or onetree with NotLabel or NotTag")
	}

	topicIn, err := GetParam(ctx, "topic")
	if err != nil {
		return out, tat.User{}, tat.Topic{}, criteria, http.StatusBadRequest, fmt.Errorf("Invalid topic")
	}
	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 user tat.User
	var e error

	if getCtxUsername(ctx) != "" {
		user, e = PreCheckUser(ctx)
		if e != nil {
			return out, tat.User{}, tat.Topic{}, criteria, http.StatusBadRequest, e
		}
	}

	topic, errt := topicDB.FindByTopic(criteria.Topic, true, false, false, &user)
	if errt != nil {
		topicCriteria := ""
		_, topicCriteria, err = checkDMTopic(ctx, criteria.Topic)
		if err != nil {
			return out, tat.User{}, tat.Topic{}, criteria, http.StatusBadRequest, fmt.Errorf("topic " + criteria.Topic + " does not exist or you have no read access on it")
		}
		// hack to get new created DM Topic
		topic, errt = topicDB.FindByTopic(topicCriteria, true, false, false, &user)
		if errt != nil {
			return out, tat.User{}, tat.Topic{}, criteria, http.StatusBadRequest, fmt.Errorf("topic " + criteria.Topic + " does not exist or you have no read access on it (2)")
		}
		criteria.Topic = topicCriteria
	}

	out.IsTopicRw, out.IsTopicAdmin = topicDB.GetUserRights(topic, &user)

	return out, user, *topic, criteria, -1, nil
}
Exemplo n.º 2
0
Arquivo: topics.go Projeto: ovh/tat
func (t *TopicsController) preCheckUserAdminOnTopic(ctx *gin.Context, topicName string) (*tat.Topic, error) {

	topic, errfind := topicDB.FindByTopic(topicName, true, false, false, nil)
	if errfind != nil {
		e := errors.New(errfind.Error())
		return nil, e
	}

	if isTatAdmin(ctx) { // if Tat admin, ok
		return topic, nil
	}

	user, err := PreCheckUser(ctx)
	if err != nil {
		return nil, err
	}

	if !topicDB.IsUserAdmin(topic, &user) {
		e := fmt.Errorf("user %s is not admin on topic %s", user.Username, topic.Topic)
		ctx.JSON(http.StatusForbidden, gin.H{"error": e})
		return nil, e
	}

	return topic, nil
}
Exemplo n.º 3
0
Arquivo: topics.go Projeto: ovh/tat
// MigrateMessagesForDedicatedTopic migrates all msg of a topic to a dedicated collection
func (t *TopicsController) MigrateMessagesForDedicatedTopic(ctx *gin.Context) {
	slimit, e1 := GetParam(ctx, "limit")
	if e1 != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": e1.Error()})
		return
	}

	limit, e2 := strconv.Atoi(slimit)
	if e2 != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": e2.Error()})
		return
	}

	topicRequest, err := GetParam(ctx, "topic")
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	topic, errfind := topicDB.FindByTopic(topicRequest, true, false, false, nil)
	if errfind != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": errfind.Error()})
		return
	}

	nMigrate, err := messageDB.MigrateMessagesToDedicatedTopic(topic, limit)
	if err != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Error after %d migrate, err:%s", nMigrate, err.Error())})
		return
	}
	ctx.JSON(http.StatusOK, gin.H{"info": fmt.Sprintf("No error after migrate %d messages (%d asked for migrate)", nMigrate, limit)})
}
Exemplo n.º 4
0
Arquivo: topics.go Projeto: ovh/tat
func (t *TopicsController) innerOneTopic(ctx *gin.Context, topicRequest string) (*tat.TopicJSON, *tat.User, int, error) {
	var user = tat.User{}
	found, err := userDB.FindByUsername(&user, getCtxUsername(ctx))
	if !found {
		return nil, nil, http.StatusInternalServerError, fmt.Errorf("User unknown")
	} else if err != nil {
		return nil, nil, http.StatusInternalServerError, fmt.Errorf("Error while fetching user.")
	}
	topic, errfind := topicDB.FindByTopic(topicRequest, user.IsAdmin, true, true, &user)
	if errfind != nil {
		topic, _, err = checkDMTopic(ctx, topicRequest)
		if err != nil {
			return nil, nil, http.StatusBadRequest, fmt.Errorf("topic " + topicRequest + " does not exist or you have no access on it")
		}
	}

	filters := []tat.Filter{}
	for _, f := range topic.Filters {
		if f.UserID == user.ID {
			filters = append(filters, f)
		}
	}
	topic.Filters = filters
	out := &tat.TopicJSON{Topic: topic}
	out.IsTopicRw, out.IsTopicAdmin = topicDB.GetUserRights(topic, &user)
	return out, &user, http.StatusOK, nil
}
Exemplo n.º 5
0
Arquivo: messages.go Projeto: ovh/tat
func checkTopicParentDM(user tat.User) error {
	topicName := "/Private/" + user.Username + "/DM"
	topicParent, err := topicDB.FindByTopic(topicName, false, false, false, nil)
	if err != nil {
		topicParent.Topic = topicName
		topicParent.Description = "DM Topics"
		if err := topicDB.Insert(topicParent, &user); err != nil {
			log.Errorf("Error while InsertTopic Parent %s", err)
			return err
		}
	}
	return nil
}
Exemplo n.º 6
0
Arquivo: messages.go Projeto: ovh/tat
func (m *MessagesController) moveMessage(ctx *gin.Context, messageIn *tat.MessageJSON, message tat.Message, user tat.User, fromTopic tat.Topic) {

	// Check if user can delete msg on from topic
	if err := m.checkBeforeDelete(ctx, message, user, true, fromTopic); err != nil {
		// ctx writes in checkBeforeDelete
		return
	}

	toTopic, err := topicDB.FindByTopic(messageIn.Option, true, false, false, &user)
	if err != nil {
		e := fmt.Sprintf("Topic destination %s does not exist", message.Topic)
		ctx.JSON(http.StatusNotFound, gin.H{"error": e})
		return
	}

	// Check if user can write msg from dest topic
	if isRW, _ := topicDB.GetUserRights(toTopic, &user); !isRW {
		ctx.JSON(http.StatusForbidden, gin.H{"error": fmt.Sprintf("No RW Access to topic %s", toTopic.Topic)})
		return
	}

	// check if message is a reply -> not possible
	if message.InReplyOfIDRoot != "" {
		ctx.JSON(http.StatusForbidden, gin.H{"error": fmt.Sprintf("You can't move a reply message")})
		return
	}

	info := ""
	if messageIn.Action == tat.MessageActionMove {
		err := messageDB.Move(&message, user, fromTopic, *toTopic)
		if err != nil {
			log.Errorf("Error while move a message to topic: %s err: %s", toTopic.Topic, err)
			ctx.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Error while move a message to topic %s", toTopic.Topic)})
			return
		}
		info = fmt.Sprintf("Message move to %s", toTopic.Topic)
	} else {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Invalid action: " + messageIn.Action})
		return
	}
	out := &tat.MessageJSONOut{Info: info, Message: message}
	hook.SendHook(&tat.HookJSON{HookMessage: &tat.HookMessageJSON{MessageJSONOut: out, Action: messageIn.Action}}, *toTopic)
	ctx.JSON(http.StatusCreated, out)
}
Exemplo n.º 7
0
Arquivo: presences.go Projeto: ovh/tat
func (m *PresencesController) listWithCriteria(ctx *gin.Context, criteria *tat.PresenceCriteria) {
	user, e := m.preCheckUser(ctx)
	if e != nil {
		return
	}

	if criteria.Topic != "" {
		_, err := topicDB.FindByTopic(criteria.Topic, true, false, false, user)
		if err != nil {
			ctx.AbortWithError(http.StatusBadRequest, errors.New("topic "+criteria.Topic+" does not exist or you have no Read Access on it"))
			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/" + 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/" + getCtxUsername(ctx)
			criteria.Topic = criteria.Topic + "," + topicInverse
		}
	}

	count, presences, err := presenceDB.ListPresences(criteria)
	if err != nil {
		ctx.AbortWithError(http.StatusInternalServerError, err)
		return
	}
	out := &tat.PresencesJSON{
		Count:     count,
		Presences: presences,
	}
	ctx.JSON(http.StatusOK, out)
}
Exemplo n.º 8
0
Arquivo: topics.go Projeto: ovh/tat
// MigrateToDedicatedTopic migrates a topic to dedicated collection on mongo
func (t *TopicsController) MigrateToDedicatedTopic(ctx *gin.Context) {
	topicRequest, err := GetParam(ctx, "topic")
	if err != nil {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	topic, errfind := topicDB.FindByTopic(topicRequest, true, false, false, nil)
	if errfind != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}

	if errMigrate := topicDB.MigrateToDedicatedTopic(topic); errMigrate != nil {
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": errMigrate.Error()})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{"info": fmt.Sprintf("%s is now dedicated", topicRequest)})
}
Exemplo n.º 9
0
Arquivo: users.go Projeto: ovh/tat
// EnableNotificationsTopic enable notication on one topic
func (*UsersController) EnableNotificationsTopic(ctx *gin.Context) {
	topicIn, err := GetParam(ctx, "topic")
	if err != nil {
		return
	}
	user, err := PreCheckUser(ctx)
	if err != nil {
		return
	}

	topic, err := topicDB.FindByTopic(topicIn, true, false, false, &user)
	if err != nil {
		AbortWithReturnError(ctx, http.StatusBadRequest, errors.New("topic "+topicIn+" does not exist or you have no Read Access on it"))
		return
	}

	if err := userDB.EnableNotificationsTopic(&user, topic.Topic); err != nil {
		AbortWithReturnError(ctx, http.StatusInternalServerError, fmt.Errorf("Error while enable notication on topic %s to user:%s", topic.Topic, user.Username))
		return
	}
	ctx.JSON(http.StatusCreated, gin.H{"info": fmt.Sprintf("Notications enabled on Topic %s", topic.Topic)})
}
Exemplo n.º 10
0
Arquivo: presences.go Projeto: ovh/tat
func (m *PresencesController) preCheckTopic(ctx *gin.Context) (tat.PresenceJSON, tat.Topic, *tat.User, error) {
	var presenceIn tat.PresenceJSON
	ctx.Bind(&presenceIn)

	topicIn, err := GetParam(ctx, "topic")
	if err != nil {
		return presenceIn, tat.Topic{}, nil, err
	}
	presenceIn.Topic = topicIn

	user, e := m.preCheckUser(ctx)
	if e != nil {
		return presenceIn, tat.Topic{}, nil, err
	}

	topic, err := topicDB.FindByTopic(presenceIn.Topic, true, false, false, user)
	if err != nil {
		e := errors.New("Topic " + presenceIn.Topic + " does not exist")
		ctx.AbortWithError(http.StatusInternalServerError, e)
		return presenceIn, tat.Topic{}, nil, e
	}
	return presenceIn, *topic, user, nil
}
Exemplo n.º 11
0
Arquivo: user.go Projeto: ovh/tat
// CheckTopics check default topics for user and creates them if fixTopics is true
func CheckTopics(user *tat.User, fixTopics bool) string {
	topicsInfo := ""
	topicNames := [...]string{"", "Notifications"}
	for _, shortName := range topicNames {
		topicName := fmt.Sprintf("/Private/%s", user.Username)
		if shortName != "" {
			topicName = fmt.Sprintf("%s/%s", topicName, shortName)
		}

		if _, errfinding := topic.FindByTopic(topicName, false, false, false, nil); errfinding != nil {
			topicsInfo = fmt.Sprintf("%s %s KO : not exist; ", topicsInfo, topicName)
			if fixTopics {
				if err := CreatePrivateTopic(user, shortName); err != nil {
					topicsInfo = fmt.Sprintf("%s Error while creating %s; ", topicsInfo, topicName)
				} else {
					topicsInfo = fmt.Sprintf("%s %s created; ", topicsInfo, topicName)
				}
			}
		} else {
			topicsInfo = fmt.Sprintf("%s %s OK; ", topicsInfo, topicName)
		}
	}
	return topicsInfo
}
Exemplo n.º 12
0
Arquivo: messages.go Projeto: ovh/tat
func (m *MessagesController) messageDelete(ctx *gin.Context, cascade, force bool) {
	idMessageIn, err := GetParam(ctx, "idMessage")
	if err != nil {
		return
	}

	topicIn, err := GetParam(ctx, "topic")
	if err != nil {
		return
	}

	user, e := PreCheckUser(ctx)
	if e != nil {
		return
	}

	topic, errf := topicDB.FindByTopic(topicIn, true, false, false, &user)
	if errf != nil {
		log.Errorf("messageDelete> err:%s", errf)
		e := fmt.Sprintf("Topic %s does not exist", topicIn)
		ctx.JSON(http.StatusNotFound, gin.H{"error": e})
		return
	}

	message := tat.Message{}
	if err = messageDB.FindByID(&message, idMessageIn, *topic); err != nil {
		ctx.JSON(http.StatusNotFound, gin.H{"error": fmt.Sprintf("Message %s does not exist", idMessageIn)})
		return
	}

	err = m.checkBeforeDelete(ctx, message, user, force, *topic)
	if err != nil {
		// ctx writes in checkBeforeDelete
		return
	}

	c := &tat.MessageCriteria{
		InReplyOfID: message.ID,
		TreeView:    tat.TreeViewOneTree,
		Topic:       topic.Topic,
	}

	msgs, err := messageDB.ListMessages(c, "", *topic)
	if err != nil {
		log.Errorf("Error while list Messages in Delete %s", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Error while list Messages in Delete"})
		return
	}

	if cascade {
		for _, r := range msgs {
			errCheck := m.checkBeforeDelete(ctx, r, user, force, *topic)
			if errCheck != nil {
				// ctx writes in checkBeforeDelete
				return
			}
		}
	} else if len(msgs) > 0 {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "Could not delete this message, this message have replies"})
		return
	}

	if err = messageDB.Delete(&message, cascade, *topic); err != nil {
		log.Errorf("Error while delete a message %s", err)
		ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{"info": fmt.Sprintf("Message deleted from %s", topic.Topic)})
}
Exemplo n.º 13
0
Arquivo: messages.go Projeto: ovh/tat
func (m *MessagesController) preCheckTopic(ctx *gin.Context, messageIn *tat.MessageJSON) (tat.Message, tat.Topic, *tat.User, error) {
	var message = tat.Message{}

	user, e := PreCheckUser(ctx)
	if e != nil {
		return message, tat.Topic{}, nil, e
	}

	topicIn, err := GetParam(ctx, "topic")
	if err != nil {
		return message, tat.Topic{}, nil, err
	}
	messageIn.Topic = topicIn

	if messageIn.Topic == "/" && messageIn.IDReference != "" {
		log.Warnf("preCheckTopic fallback to FindByIDDefaultCollection for %s", messageIn.IDReference)
		if efind := messageDB.FindByIDDefaultCollection(&message, messageIn.IDReference); efind != nil {
			e := errors.New("Invalid request, no topic and message " + messageIn.IDReference + " not found in default collection")
			ctx.JSON(http.StatusNotFound, gin.H{"error": e.Error()})
			return message, tat.Topic{}, nil, e
		}
		messageIn.Topic = message.Topic
	}

	topic, efind := topicDB.FindByTopic(messageIn.Topic, true, true, true, &user)
	if efind != nil {
		topica, _, edm := checkDMTopic(ctx, messageIn.Topic)
		if edm != nil {
			e := errors.New("Topic " + messageIn.Topic + " does not exist or you have no read access on it")
			ctx.JSON(http.StatusNotFound, gin.H{"error": e.Error()})
			return message, tat.Topic{}, nil, e
		}
		topic = topica
	}

	if messageIn.IDReference == "" &&
		messageIn.TagReference == "" &&
		messageIn.StartTagReference == "" &&
		messageIn.LabelReference == "" &&
		messageIn.StartLabelReference == "" {
		// nothing here
	} else if messageIn.IDReference != "" ||
		messageIn.StartTagReference != "" || messageIn.TagReference != "" ||
		messageIn.StartLabelReference != "" || messageIn.LabelReference != "" {
		if messageIn.IDReference != "" {
			if efind := messageDB.FindByID(&message, messageIn.IDReference, *topic); efind != nil {
				e := errors.New("Message " + messageIn.IDReference + " does not exist or you have no read access on it")
				ctx.JSON(http.StatusNotFound, gin.H{"error": e.Error()})
				return message, tat.Topic{}, nil, e
			}
		} else { // TagReference, StartTagReference,LabelReference, StartLabelReference
			onlyMsgRoot := tat.True // default value must be true
			if messageIn.OnlyRootReference == tat.False {
				onlyMsgRoot = tat.False
			}
			c := &tat.MessageCriteria{
				AndTag:      messageIn.TagReference,
				StartTag:    messageIn.StartTagReference,
				AndLabel:    messageIn.LabelReference,
				StartLabel:  messageIn.StartLabelReference,
				OnlyMsgRoot: onlyMsgRoot,
				Topic:       topic.Topic,
			}
			mlist, efind := messageDB.ListMessages(c, user.Username, *topic)
			if efind != nil {
				e := errors.New("Searched Message does not exist or you have no read access on it")
				ctx.JSON(http.StatusNotFound, gin.H{"error": e.Error()})
				return message, tat.Topic{}, nil, e
			}
			if len(mlist) != 1 {
				if messageIn.Action != "" {
					e := errors.New(fmt.Sprintf("Searched Message, expected 1 message and %d message(s) matching on tat", len(mlist)))
					ctx.JSON(http.StatusNotFound, gin.H{"error": e.Error()})
					return message, tat.Topic{}, nil, e
				}
				// take last root message
				if len(mlist) > 0 {
					message = mlist[0]
				}
			} else {
				message = mlist[0]
			}
		}

		topicName := ""
		if messageIn.Action == tat.MessageActionUpdate {
			topicName = messageIn.Topic
		} else if messageIn.Action == "" || messageIn.Action == tat.MessageActionReply ||
			messageIn.Action == tat.MessageActionLike || messageIn.Action == tat.MessageActionUnlike ||
			messageIn.Action == tat.MessageActionLabel || messageIn.Action == tat.MessageActionUnlabel ||
			messageIn.Action == tat.MessageActionVoteup || messageIn.Action == tat.MessageActionVotedown ||
			messageIn.Action == tat.MessageActionUnvoteup || messageIn.Action == tat.MessageActionUnvotedown ||
			messageIn.Action == tat.MessageActionRelabel || messageIn.Action == tat.MessageActionConcat {
			topicName = m.inverseIfDMTopic(ctx, message.Topic)
		} else if messageIn.Action == tat.MessageActionMove {
			topicName = topicIn
		} else if messageIn.Action == tat.MessageActionTask || messageIn.Action == tat.MessageActionUntask {
			topicName = m.inverseIfDMTopic(ctx, message.Topic)
		} else {
			e := errors.New("Invalid Call. IDReference not empty with unknown action")
			ctx.JSON(http.StatusBadRequest, gin.H{"error": e.Error()})
			return message, tat.Topic{}, nil, e
		}
		if topicName == "" && messageIn.Action == "" {
			topicName = messageIn.Topic
		}

		topic, err = topicDB.FindByTopic(topicName, true, true, true, &user)
		if err != nil {
			e := errors.New("Topic " + topicName + " does not exist")
			ctx.JSON(http.StatusNotFound, gin.H{"error": e.Error()})
			return message, tat.Topic{}, nil, e
		}
	} else {
		e := errors.New("Topic and Reference (ID, StartTag, Tag, StartLabel, Label) are null. Wrong request")
		ctx.JSON(http.StatusBadRequest, gin.H{"error": e.Error()})
		return message, tat.Topic{}, nil, e
	}
	return message, *topic, &user, nil
}
Exemplo n.º 14
0
Arquivo: topics.go Projeto: ovh/tat
// SetParam update Topic Parameters : MaxLength, CanForeceDate, CanUpdateMsg, CanDeleteMsg, CanUpdateAllMsg, CanDeleteAllMsg, AdminCanDeleteAllMsg
// admin only, except on Private topic
func (t *TopicsController) SetParam(ctx *gin.Context) {
	var paramsBind paramsJSON
	ctx.Bind(&paramsBind)

	topic := &tat.Topic{}
	var errFind, err error
	if strings.HasPrefix(paramsBind.Topic, "/Private/"+getCtxUsername(ctx)) {
		topic, errFind = topicDB.FindByTopic(paramsBind.Topic, false, false, false, nil)
		if errFind != nil {
			ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Error while fetching topic /Private/" + getCtxUsername(ctx)})
			return
		}
	} else {
		topic, err = t.preCheckUserAdminOnTopic(ctx, paramsBind.Topic)
		if err != nil {
			ctx.JSON(tat.Error(err))
			return
		}
	}

	for _, p := range paramsBind.Parameters {
		if strings.HasPrefix(p.Key, tat.HookTypeKafka) && !isTatAdmin(ctx) {
			ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Only Tat Admin can use tathook-kafka"})
			return
		}
	}

	err = topicDB.SetParam(topic, getCtxUsername(ctx),
		paramsBind.Recursive,
		paramsBind.MaxLength,
		paramsBind.CanForceDate,
		paramsBind.CanUpdateMsg,
		paramsBind.CanDeleteMsg,
		paramsBind.CanUpdateAllMsg,
		paramsBind.CanDeleteAllMsg,
		paramsBind.AdminCanUpdateAllMsg,
		paramsBind.AdminCanDeleteAllMsg,
		paramsBind.IsAutoComputeTags,
		paramsBind.IsAutoComputeLabels,
		paramsBind.Parameters)

	// add tat2xmpp_username RO or RW on this topic if a key is xmpp
	for _, p := range paramsBind.Parameters {
		if strings.HasPrefix(p.Key, tat.HookTypeXMPPOut) {
			found := false
			for _, u := range topic.ROUsers {
				if u == viper.GetString("tat2xmpp_username") {
					found = true
				}
			}
			for _, u := range topic.RWUsers {
				if u == viper.GetString("tat2xmpp_username") {
					found = true
				}
			}
			if !found {
				if errf := topicDB.AddRoUser(topic, getCtxUsername(ctx), viper.GetString("tat2xmpp_username"), false); errf != nil {
					log.Errorf("Error while adding read only user tat2xmpp_username: %s", errf)
					ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
					return
				}
			}
		} else if strings.HasPrefix(p.Key, tat.HookTypeXMPP) {
			found := false
			for _, u := range topic.RWUsers {
				if u == viper.GetString("tat2xmpp_username") {
					found = true
				}
			}
			if !found {
				if errf := topicDB.AddRwUser(topic, getCtxUsername(ctx), viper.GetString("tat2xmpp_username"), false); errf != nil {
					log.Errorf("Error while adding read write user tat2xmpp_username: %s", errf)
					ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
					return
				}
			}
		}
	}

	if err != nil {
		log.Errorf("Error while setting parameters: %s", err)
		ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
		return
	}
	ctx.JSON(http.StatusCreated, gin.H{"info": fmt.Sprintf("Topic %s updated", topic.Topic)})
}