changeset 164:e3bdf5b26748

basic support for people
author Myk Melez <myk@mozilla.org>
date Sun, 13 Jul 2008 21:44:09 -0700
parents 3445777aa010
children 91524ab2554c
files extension/modules/collection.js extension/modules/datastore.js extension/modules/feed.js extension/modules/message.js
diffstat 4 files changed, 66 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/extension/modules/collection.js	Thu Jul 10 01:33:57 2008 -0700
+++ b/extension/modules/collection.js	Sun Jul 13 21:44:09 2008 -0700
@@ -175,8 +175,9 @@
       //"SELECT subject, author, link, timestamp, content \
       // FROM sources JOIN messages ON sources.id = messages.sourceID \
       // LEFT JOIN parts on messages.id = parts.messageID";
-      "SELECT messages.id, subject, author, link, timestamp, read " +
-      "FROM sources JOIN messages ON sources.id = messages.sourceID";
+      "SELECT messages.id, subject, authors.name AS author, link, timestamp, read " +
+      "FROM sources JOIN messages ON sources.id = messages.sourceID " +
+      "LEFT JOIN people AS authors ON messages.authorID = authors.id";
 
     let conditions = [];
 
--- a/extension/modules/datastore.js	Thu Jul 10 01:33:57 2008 -0700
+++ b/extension/modules/datastore.js	Sun Jul 13 21:44:09 2008 -0700
@@ -57,7 +57,7 @@
           "sourceID INTEGER NOT NULL REFERENCES sources(id)",
           "externalID TEXT",
           "subject TEXT",
-          "author TEXT",
+          "authorID INTEGER REFERENCES people(id)",
           "timestamp INTEGER",
           "link TEXT",
           "current BOOLEAN DEFAULT 1",
@@ -94,6 +94,34 @@
           "contentType TEXT NOT NULL",
           "value BLOB"
         ]
+      },
+
+      people: {
+        type: TABLE_TYPE_NORMAL,
+        columns: [
+          "id INTEGER PRIMARY KEY",
+          "name TEXT NOT NULL"
+        ]
+      },
+
+      personMetadata: {
+        type: TABLE_TYPE_NORMAL,
+        columns: [
+          "personID INTEGER NOT NULL REFERENCES people(id)",
+          "attributeID INTEGER NOT NULL REFERENCES attributes(id)",
+          "value BLOB"
+        ]
+      },
+
+      identities: {
+        type: TABLE_TYPE_NORMAL,
+        columns: [
+          "id INTEGER PRIMARY KEY",
+          "sourceID INTEGER NOT NULL REFERENCES sources(id)",
+          "externalID TEXT NOT NULL",
+          "personID INTEGER NOT NULL REFERENCES people(id)",
+          "UNIQUE(externalID, sourceID)"
+        ]
       }
 
     },
@@ -304,8 +332,8 @@
 
   get _insertMessageStatement() {
     let statement = this.createStatement(
-      "INSERT INTO messages(sourceID, externalID, subject, author, timestamp, link) \
-       VALUES (:sourceID, :externalID, :subject, :author, :timestamp, :link)"
+      "INSERT INTO messages(sourceID, externalID, subject, authorID, timestamp, link) \
+       VALUES (:sourceID, :externalID, :subject, :authorID, :timestamp, :link)"
     );
     this.__defineGetter__("_insertMessageStatement", function() { return statement });
     return this._insertMessageStatement;
@@ -317,21 +345,22 @@
    * @param aSourceID    {integer} the record ID of the message source
    * @param aExternalID  {string}  the external ID of the message
    * @param aSubject     {string}  the title of the message
-   * @param aAuthor      {string}  the author of the message
+   * @param aAuthorID    {string}  the author of the message
    * @param aTimestamp   {Date}    the date/time at which the message was sent
    * @param aLink        {nsIURI}  a link to the content of the message,
    *                               if the content is hosted on a server
    *
    * @returns {integer} the ID of the newly-created record
    */
-  insertMessage: function(aSourceID, aExternalID, aSubject, aAuthor, aTimestamp, aLink) {
+  insertMessage: function(aSourceID, aExternalID, aSubject, aAuthorID, aTimestamp, aLink) {
     this._insertMessageStatement.params.sourceID = aSourceID;
     this._insertMessageStatement.params.externalID = aExternalID;
     this._insertMessageStatement.params.subject = aSubject;
-    this._insertMessageStatement.params.author = aAuthor;
+    this._insertMessageStatement.params.authorID = aAuthorID;
     this._insertMessageStatement.params.timestamp = aTimestamp;
     this._insertMessageStatement.params.link = aLink;
     this._insertMessageStatement.execute();
+
     return this.dbConnection.lastInsertRowID;
   },
 
--- a/extension/modules/feed.js	Thu Jul 10 01:33:57 2008 -0700
+++ b/extension/modules/feed.js	Sun Jul 13 21:44:09 2008 -0700
@@ -17,6 +17,7 @@
 // Snowl-specific modules
 Cu.import("resource://snowl/modules/datastore.js");
 Cu.import("resource://snowl/modules/source.js");
+Cu.import("resource://snowl/modules/identity.js");
 
 // FIXME: factor this out into a common file.
 const PART_TYPE_CONTENT = 1;
@@ -260,24 +261,24 @@
    * @param aExternalID   {string}        the external ID of the entry
    */
   _addMessage: function(aFeed, aEntry, aExternalID) {
-    // Determine the author.
-    let author = null;
-    if (aEntry.authors.length > 0) {
-      let firstAuthor = aEntry.authors.queryElementAt(0, Ci.nsIFeedPerson);
-      if (firstAuthor.name)
-        author = firstAuthor.name;
-      else if (firstAuthor.email)
-        author = firstAuthor.email;
-    }
-    if (!author && aFeed.authors.length > 0) {
-      let firstAuthor = aFeed.authors.queryElementAt(0, Ci.nsIFeedPerson);
-      if (firstAuthor.name)
-        author = firstAuthor.name;
-      else if (firstAuthor.email)
-        author = firstAuthor.email;
-    }
-    if (!author && aFeed.title) {
-      author = aFeed.title.plainText();
+    let authorID = null;
+    let authors = (aEntry.authors.length > 0) ? aEntry.authors
+                  : (aFeed.authors.length > 0) ? aFeed.authors
+                  : null;
+    if (authors && authors.length > 0) {
+      let author = authors.queryElementAt(0, Ci.nsIFeedPerson);
+      // The external ID for an author is her email address, if provided
+      // (many feeds don't); otherwise it's her name.  For the name, on the
+      // other hand, we use the name, if provided, but fall back to the
+      // email address if a name is not provided (which it probably was).
+      let externalID = author.email || author.name;
+      let name = author.name || author.email;
+
+      // Get an existing identity or create a new one.  Creating an identity
+      // automatically creates a person record with the provided name.
+      identity = SnowlIdentity.get(this.id, externalID) ||
+                 SnowlIdentity.create(this.id, externalID, name);
+      authorID = identity.personID;
     }
 
     // Pick a timestamp, which is one of (by priority, high to low):
@@ -293,7 +294,7 @@
 
     // FIXME: handle titles that contain markup or are missing.
     let messageID = this.addSimpleMessage(this.id, aExternalID,
-                                          aEntry.title.text, author,
+                                          aEntry.title.text, authorID,
                                           timestamp, aEntry.link);
 
     // Add parts
@@ -315,6 +316,7 @@
     while (fields.hasMoreElements()) {
       let field = fields.getNext().QueryInterface(Ci.nsIProperty);
 
+      // FIXME: create people records for these.
       if (field.name == "authors") {
         let values = field.value.QueryInterface(Ci.nsIArray).enumerate();
         while (values.hasMoreElements()) {
@@ -352,6 +354,7 @@
         else if (field.value instanceof Ci.nsIArray) {
           let values = field.value.QueryInterface(Ci.nsIArray).enumerate();
           while (values.hasMoreElements()) {
+            // FIXME: values might not always have this interface.
             let value = values.getNext().QueryInterface(Ci.nsIPropertyBag2);
             this._addMetadatum(messageID, field.name, value.get(field.name));
           }
@@ -405,14 +408,14 @@
    * @param aSourceID    {integer} the record ID of the message source
    * @param aExternalID  {string}  the external ID of the message
    * @param aSubject     {string}  the title of the message
-   * @param aAuthor      {string}  the author of the message
+   * @param aAuthorID    {string}  the author of the message
    * @param aTimestamp   {Date}    the date/time at which the message was sent
    * @param aLink        {nsIURI}  a link to the content of the message,
    *                               if the content is hosted on a server
    *
    * @returns {integer} the internal ID of the newly-created message
    */
-  addSimpleMessage: function(aSourceID, aExternalID, aSubject, aAuthor,
+  addSimpleMessage: function(aSourceID, aExternalID, aSubject, aAuthorID,
                              aTimestamp, aLink) {
     // Convert the timestamp to milliseconds-since-epoch, which is how we store
     // it in the datastore.
@@ -423,7 +426,7 @@
     let link = aLink ? aLink.spec : null;
 
     let messageID =
-      SnowlDatastore.insertMessage(aSourceID, aExternalID, aSubject, aAuthor,
+      SnowlDatastore.insertMessage(aSourceID, aExternalID, aSubject, aAuthorID,
                                    timestamp, link);
 
     return messageID;
--- a/extension/modules/message.js	Thu Jul 10 01:33:57 2008 -0700
+++ b/extension/modules/message.js	Sun Jul 13 21:44:09 2008 -0700
@@ -35,7 +35,9 @@
   let message;
 
   let statement = SnowlDatastore.createStatement(
-    "SELECT subject, author, link, timestamp, read FROM messages WHERE id = :id"
+    "SELECT subject, authors.name AS author, link, timestamp, read " +
+    "FROM messages LEFT JOIN people AS authors ON messages.authorID = authors.id " +
+    "WHERE messages.id = :id"
   );
 
   try {