File: models/server/Tag.js
"use strict";
var Cocktail = require("backbone.cocktail");
require("../../db");
var Base = require("./Base");
var User = require("./User");
var TagMixin = require("../TagMixin");
/**
* Ticket tags.
*
* Tags with a `status:` are handled as a special status tags.
* Only one tag with the prefix can be active at once.
*
* @namespace models.server
* @class Tag
* @extends models.server.Base
* @uses models.TagMixin
*/
var Tag = Base.extend({
tableName: "tags",
defaults: function() {
return {
createdAt: new Date(),
updatedAt: new Date()
};
},
initialize: function(attrs, options) {
this.on("creating", function(tagModel) {
return tagModel.clones().fetch()
.bind(this)
.then(function validateTagUniqueness(collection) {
if (collection.size() > 0) {
throw new Error("tag " + tagModel.get("tag") + " already exists");
}
})
.then(function deletePreviousStatustags() {
if (tagModel.isStatusTag()) {
return Tag.softDeleteStatusTagsFor(
tagModel.get("ticketId"),
tagModel.get("createdById")
);
}
})
.then(function() {
return this._assertOnlyHandlerCanChangeStatus(options);
});
});
},
_assertOnlyHandlerCanChangeStatus: function(options) {
if (!this.isStatusTag()) return;
if (options && options.force) return;
return this.ticket().fetch({
require: true,
withRelated: "handlerUsers"
})
.bind(this)
.then(function(ticket) {
if (!ticket.isHandler(this.get("createdById"))) {
throw new Error("Only handlers can change status");
}
});
},
/**
* Return Collection for clones of this tag
*
* @method clones
* @return {Bookshelf.Collection}
*/
clones: function(){
var self = this;
return Tag.collection()
.query(function(qb) {
qb
.whereNull("deletedAt")
.andWhere({
tag: self.get("tag"),
ticketId: self.get("ticketId")
});
});
},
ticket: function() {
var Ticket = require("./Ticket");
return this.belongsTo(Ticket, "ticketId");
},
createdBy: function() {
return this.belongsTo(User, "createdById");
}
}, {
/**
* Soft delete status tags for the given ticket
*
* @static
* @method softDeleteStatusTagsFor
* @param {models.server.Ticket|Number} ticket Model object or table id
* @param {models.server.User|Number} byUser The user who deleted the tags
* @return {Bluebird.Promise}
*/
softDeleteStatusTagsFor: function(ticket, byUser){
return Tag.statusTagsFor(ticket).fetch()
.then(function(coll) {
return coll.invokeThen("softDelete", byUser);
});
},
/**
* Fetch all status tags for the given ticket
*
* @static
* @method statusTagsFor
* @param {models.server.Ticket|Number} ticket Model object or table id
* @return {Bookshelf.Collection} Collection of models.server.Tag models
*/
statusTagsFor: function(ticket){
var ticketId = Base.toId(ticket);
return Tag.collection()
.query(function(qb) {
qb
.whereNull("deletedAt")
.andWhere({ ticketId: ticketId })
.andWhere("tag", "like", "status:%");
});
}
});
Cocktail.mixin(Tag, TagMixin);
module.exports = Tag;