summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/db/gloda/modules/GlodaExplicitAttr.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'comm/mailnews/db/gloda/modules/GlodaExplicitAttr.jsm')
-rw-r--r--comm/mailnews/db/gloda/modules/GlodaExplicitAttr.jsm188
1 files changed, 188 insertions, 0 deletions
diff --git a/comm/mailnews/db/gloda/modules/GlodaExplicitAttr.jsm b/comm/mailnews/db/gloda/modules/GlodaExplicitAttr.jsm
new file mode 100644
index 0000000000..7a10b4112e
--- /dev/null
+++ b/comm/mailnews/db/gloda/modules/GlodaExplicitAttr.jsm
@@ -0,0 +1,188 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * This file provides the "explicit attribute" provider for messages. It is
+ * concerned with attributes that are the result of user actions. For example,
+ * whether a message is starred (flagged), message tags, whether it is
+ * read/unread, etc.
+ */
+
+const EXPORTED_SYMBOLS = ["GlodaExplicitAttr"];
+
+const { Gloda } = ChromeUtils.import("resource:///modules/gloda/Gloda.jsm");
+const { GlodaConstants } = ChromeUtils.import(
+ "resource:///modules/gloda/GlodaConstants.jsm"
+);
+const { TagNoun } = ChromeUtils.import("resource:///modules/gloda/NounTag.jsm");
+
+/**
+ * @namespace Explicit attribute provider. Indexes/defines attributes that are
+ * explicitly a result of user action. This dubiously includes marking a
+ * message as read.
+ */
+var GlodaExplicitAttr = {
+ providerName: "gloda.explattr",
+ strings: Services.strings.createBundle(
+ "chrome://messenger/locale/gloda.properties"
+ ),
+ _log: null,
+
+ init() {
+ this._log = console.createInstance({
+ prefix: "gloda.explattr",
+ maxLogLevel: "Warn",
+ maxLogLevelPref: "gloda.loglevel",
+ });
+
+ try {
+ this.defineAttributes();
+ } catch (ex) {
+ this._log.error("Error in init: " + ex);
+ throw ex;
+ }
+ },
+
+ /** Boost for starred messages. */
+ NOTABILITY_STARRED: 16,
+ /** Boost for tagged messages, first tag. */
+ NOTABILITY_TAGGED_FIRST: 8,
+ /** Boost for tagged messages, each additional tag. */
+ NOTABILITY_TAGGED_ADDL: 1,
+
+ defineAttributes() {
+ // Tag
+ this._attrTag = Gloda.defineAttribute({
+ provider: this,
+ extensionName: GlodaConstants.BUILT_IN,
+ attributeType: GlodaConstants.kAttrExplicit,
+ attributeName: "tag",
+ bindName: "tags",
+ singular: false,
+ emptySetIsSignificant: true,
+ facet: true,
+ subjectNouns: [GlodaConstants.NOUN_MESSAGE],
+ objectNoun: GlodaConstants.NOUN_TAG,
+ parameterNoun: null,
+ // Property change notifications that we care about:
+ propertyChanges: ["keywords"],
+ }); // not-tested
+
+ // Star
+ this._attrStar = Gloda.defineAttribute({
+ provider: this,
+ extensionName: GlodaConstants.BUILT_IN,
+ attributeType: GlodaConstants.kAttrExplicit,
+ attributeName: "star",
+ bindName: "starred",
+ singular: true,
+ facet: true,
+ subjectNouns: [GlodaConstants.NOUN_MESSAGE],
+ objectNoun: GlodaConstants.NOUN_BOOLEAN,
+ parameterNoun: null,
+ }); // tested-by: test_attributes_explicit
+ // Read/Unread
+ this._attrRead = Gloda.defineAttribute({
+ provider: this,
+ extensionName: GlodaConstants.BUILT_IN,
+ attributeType: GlodaConstants.kAttrExplicit,
+ attributeName: "read",
+ // Make the message query-able but without using the database.
+ canQuery: "truthy-but-not-true",
+ singular: true,
+ subjectNouns: [GlodaConstants.NOUN_MESSAGE],
+ objectNoun: GlodaConstants.NOUN_BOOLEAN,
+ parameterNoun: null,
+ }); // tested-by: test_attributes_explicit
+
+ /**
+ * Has this message been replied to by the user.
+ */
+ this._attrRepliedTo = Gloda.defineAttribute({
+ provider: this,
+ extensionName: GlodaConstants.BUILT_IN,
+ attributeType: GlodaConstants.kAttrExplicit,
+ attributeName: "repliedTo",
+ singular: true,
+ subjectNouns: [GlodaConstants.NOUN_MESSAGE],
+ objectNoun: GlodaConstants.NOUN_BOOLEAN,
+ parameterNoun: null,
+ }); // tested-by: test_attributes_explicit
+
+ /**
+ * Has this user forwarded this message to someone.
+ */
+ this._attrForwarded = Gloda.defineAttribute({
+ provider: this,
+ extensionName: GlodaConstants.BUILT_IN,
+ attributeType: GlodaConstants.kAttrExplicit,
+ attributeName: "forwarded",
+ singular: true,
+ subjectNouns: [GlodaConstants.NOUN_MESSAGE],
+ objectNoun: GlodaConstants.NOUN_BOOLEAN,
+ parameterNoun: null,
+ }); // tested-by: test_attributes_explicit
+ },
+
+ *process(aGlodaMessage, aRawReps, aIsNew, aCallbackHandle) {
+ let aMsgHdr = aRawReps.header;
+
+ aGlodaMessage.starred = aMsgHdr.isFlagged;
+ if (aGlodaMessage.starred) {
+ aGlodaMessage.notability += this.NOTABILITY_STARRED;
+ }
+
+ aGlodaMessage.read = aMsgHdr.isRead;
+
+ let flags = aMsgHdr.flags;
+ aGlodaMessage.repliedTo = Boolean(flags & Ci.nsMsgMessageFlags.Replied);
+ aGlodaMessage.forwarded = Boolean(flags & Ci.nsMsgMessageFlags.Forwarded);
+
+ let tags = (aGlodaMessage.tags = []);
+
+ // -- Tag
+ // build a map of the keywords
+ let keywords = aMsgHdr.getStringProperty("keywords");
+ let keywordList = keywords.split(" ");
+ let keywordMap = {};
+ for (let iKeyword = 0; iKeyword < keywordList.length; iKeyword++) {
+ let keyword = keywordList[iKeyword];
+ keywordMap[keyword] = true;
+ }
+
+ let tagArray = TagNoun.getAllTags();
+ for (let iTag = 0; iTag < tagArray.length; iTag++) {
+ let tag = tagArray[iTag];
+ if (tag.key in keywordMap) {
+ tags.push(tag);
+ }
+ }
+
+ if (tags.length) {
+ aGlodaMessage.notability +=
+ this.NOTABILITY_TAGGED_FIRST +
+ (tags.length - 1) * this.NOTABILITY_TAGGED_ADDL;
+ }
+
+ yield GlodaConstants.kWorkDone;
+ },
+
+ /**
+ * Duplicates the notability logic from process(). Arguably process should
+ * be factored to call us, grokNounItem should be factored to call us, or we
+ * should get sufficiently fancy that our code wildly diverges.
+ */
+ score(aMessage, aContext) {
+ let score = 0;
+ if (aMessage.starred) {
+ score += this.NOTABILITY_STARRED;
+ }
+ if (aMessage.tags.length) {
+ score +=
+ this.NOTABILITY_TAGGED_FIRST +
+ (aMessage.tags.length - 1) * this.NOTABILITY_TAGGED_ADDL;
+ }
+ return score;
+ },
+};