← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] ~cjwatson/launchpad:stormify-person-extras into launchpad:master

 

Colin Watson has proposed merging ~cjwatson/launchpad:stormify-person-extras into launchpad:master.

Commit message:
Convert SSHKey/WikiName/JabberID/IrcID to Storm

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/436138
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:stormify-person-extras into launchpad:master.
diff --git a/lib/lp/blueprints/stories/sprints/xx-sprints.rst b/lib/lp/blueprints/stories/sprints/xx-sprints.rst
index 70ed81e..c5acb12 100644
--- a/lib/lp/blueprints/stories/sprints/xx-sprints.rst
+++ b/lib/lp/blueprints/stories/sprints/xx-sprints.rst
@@ -485,10 +485,10 @@ First, we add a couple of IRC nicknames for Carlos.
     >>> login("carlos@xxxxxxxxxxxxx")
     >>> carlos = getUtility(IPersonSet).getByName("carlos")
     >>> IrcID(person=carlos, network="freenode", nickname="carlos")
-    <IrcID at ...>
+    <...IrcID object at ...>
 
     >>> IrcID(person=carlos, network="QuakeNet", nickname="qarlos")
-    <IrcID at ...>
+    <...IrcID object at ...>
 
     >>> for ircid in sorted(carlos.ircnicknames, key=attrgetter("nickname")):
     ...     print(ircid.nickname)
diff --git a/lib/lp/code/templates/branch-management.pt b/lib/lp/code/templates/branch-management.pt
index 2bae971..25a41b4 100644
--- a/lib/lp/code/templates/branch-management.pt
+++ b/lib/lp/code/templates/branch-management.pt
@@ -54,7 +54,7 @@
               </tt>
             </dd>
           </dl>
-          <p tal:condition="not:view/user/sshkeys" id="ssh-key-directions">
+          <p tal:condition="view/user/sshkeys/is_empty" id="ssh-key-directions">
             To authenticate with the Launchpad branch upload service, you need
             to <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
               register an SSH key</a>.
diff --git a/lib/lp/code/templates/configure-code-macros.pt b/lib/lp/code/templates/configure-code-macros.pt
index 5101f5c..7b5840b 100644
--- a/lib/lp/code/templates/configure-code-macros.pt
+++ b/lib/lp/code/templates/configure-code-macros.pt
@@ -30,7 +30,7 @@
     </p>
   </div>
 
-  <div metal:define-macro="no-keys" tal:condition="not:view/user/sshkeys">
+  <div metal:define-macro="no-keys" tal:condition="view/user/sshkeys/is_empty">
     <p class="infobox">To authenticate with the Launchpad branch upload service, you need to
     <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
     register an SSH key</a>.</p>
diff --git a/lib/lp/code/templates/git-macros.pt b/lib/lp/code/templates/git-macros.pt
index 1d02912..3960408 100644
--- a/lib/lp/code/templates/git-macros.pt
+++ b/lib/lp/code/templates/git-macros.pt
@@ -115,7 +115,7 @@
           </dd>
         </dl>
       </tal:cannot-push>
-      <p tal:condition="not:view/user/sshkeys" id="ssh-key-directions">
+      <p tal:condition="view/user/sshkeys/is_empty" id="ssh-key-directions">
         To authenticate with the Launchpad Git hosting service, you need to
         <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
           register an SSH key</a>.
diff --git a/lib/lp/code/templates/product-branch-summary.pt b/lib/lp/code/templates/product-branch-summary.pt
index 7c8a1d1..abcfeb1 100644
--- a/lib/lp/code/templates/product-branch-summary.pt
+++ b/lib/lp/code/templates/product-branch-summary.pt
@@ -103,7 +103,7 @@
       <tt class="command">
         bzr push lp:~<tal:user replace="view/user/name"/>/<tal:project replace="context/name"/>/<tal:series replace="context/name"/>
       </tt>
-      <tal:no-keys condition="not:view/user/sshkeys">
+      <tal:no-keys condition="view/user/sshkeys/is_empty">
         <br/>To authenticate with the Launchpad branch upload service,
         you need to
         <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
diff --git a/lib/lp/registry/browser/person.py b/lib/lp/registry/browser/person.py
index 8145cc0..37560bb 100644
--- a/lib/lp/registry/browser/person.py
+++ b/lib/lp/registry/browser/person.py
@@ -1652,7 +1652,7 @@ class PersonView(LaunchpadView, FeedsMixin, ContactViaWebLinksMixin):
         It's shown when the person has Jabber IDs registered or has rights
         to register new ones.
         """
-        return bool(self.context.jabberids) or (
+        return not self.context.jabberids.is_empty() or (
             check_permission("launchpad.Edit", self.context)
         )
 
@@ -1663,7 +1663,7 @@ class PersonView(LaunchpadView, FeedsMixin, ContactViaWebLinksMixin):
         It's shown when the person has SSH keys registered or has rights
         to register new ones.
         """
-        return bool(self.context.sshkeys) or (
+        return not self.context.sshkeys.is_empty() or (
             check_permission("launchpad.Edit", self.context)
         )
 
diff --git a/lib/lp/registry/interfaces/ssh.py b/lib/lp/registry/interfaces/ssh.py
index 2e50107..5590a99 100644
--- a/lib/lp/registry/interfaces/ssh.py
+++ b/lib/lp/registry/interfaces/ssh.py
@@ -85,7 +85,6 @@ class ISSHKey(Interface):
 
     id = Int(title=_("Database ID"), required=True, readonly=True)
     person = Int(title=_("Owner"), required=True, readonly=True)
-    personID = Int(title=_("Owner ID"), required=True, readonly=True)
     keytype = exported(
         Choice(
             title=_("Key type"),
diff --git a/lib/lp/registry/model/person.py b/lib/lp/registry/model/person.py
index 175ccfc..ec8941b 100644
--- a/lib/lp/registry/model/person.py
+++ b/lib/lp/registry/model/person.py
@@ -63,7 +63,7 @@ from storm.expr import (
     With,
 )
 from storm.info import ClassAlias
-from storm.locals import Int, Reference, ReferenceSet
+from storm.locals import Int, Reference, ReferenceSet, Unicode
 from storm.store import EmptyResultSet, Store
 from twisted.conch.ssh.common import getNS
 from twisted.conch.ssh.keys import Key
@@ -211,7 +211,6 @@ from lp.services.database.sqlobject import (
     BoolCol,
     ForeignKey,
     IntCol,
-    SQLMultipleJoin,
     SQLObjectNotFound,
     StringCol,
 )
@@ -550,7 +549,7 @@ class Person(
         storm_validator=validate_public_person,
     )
 
-    sshkeys = SQLMultipleJoin("SSHKey", joinColumn="person")
+    sshkeys = ReferenceSet("id", "SSHKey.person_id")
 
     renewal_policy = DBEnum(
         enum=TeamMembershipRenewalPolicy,
@@ -586,8 +585,8 @@ class Person(
     verbose_bugnotifications = BoolCol(notNull=True, default=True)
 
     signedcocs = ReferenceSet("<primary key>", "SignedCodeOfConduct.owner_id")
-    _ircnicknames = SQLMultipleJoin("IrcID", joinColumn="person")
-    jabberids = SQLMultipleJoin("JabberID", joinColumn="person")
+    _ircnicknames = ReferenceSet("id", "IrcID.person_id")
+    jabberids = ReferenceSet("id", "JabberID.person_id")
 
     visibility = DBEnum(
         enum=PersonVisibility,
@@ -5070,15 +5069,23 @@ class PersonLanguage(StormBase):
 
 
 @implementer(ISSHKey)
-class SSHKey(SQLBase):
-    _defaultOrder = ["person", "keytype", "keytext"]
+class SSHKey(StormBase):
+    __storm_table__ = "SSHKey"
+    __storm_order__ = ["person", "keytype", "keytext"]
 
-    _table = "SSHKey"
-
-    person = ForeignKey(foreignKey="Person", dbName="person", notNull=True)
+    id = Int(primary=True)
+    person_id = Int(name="person", allow_none=False)
+    person = Reference(person_id, "Person.id")
     keytype = DBEnum(name="keytype", allow_none=False, enum=SSHKeyType)
-    keytext = StringCol(dbName="keytext", notNull=True)
-    comment = StringCol(dbName="comment", notNull=True)
+    keytext = Unicode(name="keytext", allow_none=False)
+    comment = Unicode(name="comment", allow_none=False)
+
+    def __init__(self, person, keytype, keytext, comment):
+        super().__init__()
+        self.person = person
+        self.keytype = keytype
+        self.keytext = keytext
+        self.comment = comment
 
     def destroySelf(self, send_notification=True):
         if send_notification:
@@ -5097,7 +5104,7 @@ class SSHKey(SQLBase):
                 "SSH key removed from your Launchpad account.",
                 change_description,
             )
-        super().destroySelf()
+        IStore(self).remove(self)
 
     def getFullKeyText(self):
         try:
@@ -5162,26 +5169,22 @@ class SSHKeySet:
             )
 
         if not dry_run:
-            return SSHKey(
+            ssh_key = SSHKey(
                 person=person,
                 keytype=keytype,
                 keytext=keytext,
                 comment=comment,
             )
+            IStore(ssh_key).flush()
+            return ssh_key
 
     def getByID(self, id, default=None):
-        try:
-            return SSHKey.get(id)
-        except SQLObjectNotFound:
-            return default
+        return IStore(SSHKey).get(SSHKey, int(id))
 
     def getByPeople(self, people):
         """See `ISSHKeySet`"""
-        return SSHKey.select(
-            """
-            SSHKey.person IN %s
-            """
-            % sqlvalues([person.id for person in people])
+        return IStore(SSHKey).find(
+            SSHKey, SSHKey.person_id.is_in(person.id for person in people)
         )
 
     def getByPersonAndKeyText(self, person, sshkey):
@@ -5215,41 +5218,61 @@ class SSHKeySet:
 
 
 @implementer(IWikiName)
-class WikiName(SQLBase, HasOwnerMixin):
+class WikiName(StormBase, HasOwnerMixin):
 
-    _table = "WikiName"
+    __storm_table__ = "WikiName"
 
-    person = ForeignKey(dbName="person", foreignKey="Person", notNull=True)
-    wiki = StringCol(dbName="wiki", notNull=True)
-    wikiname = StringCol(dbName="wikiname", notNull=True)
+    id = Int(primary=True)
+    person_id = Int(name="person", allow_none=False)
+    person = Reference(person_id, "Person.id")
+    wiki = Unicode(name="wiki", allow_none=False)
+    wikiname = Unicode(name="wikiname", allow_none=False)
+
+    def __init__(self, person, wiki, wikiname):
+        super().__init__()
+        self.person = person
+        self.wiki = wiki
+        self.wikiname = wikiname
 
     @property
     def url(self):
         return self.wiki + self.wikiname
 
+    def destroySelf(self):
+        IStore(self).remove(self)
+
 
 @implementer(IWikiNameSet)
 class WikiNameSet:
     def get(self, id):
         """See `IWikiNameSet`."""
-        try:
-            return WikiName.get(id)
-        except SQLObjectNotFound:
-            return None
+        return IStore(WikiName).get(WikiName, int(id))
 
     def new(self, person, wiki, wikiname):
         """See `IWikiNameSet`."""
-        return WikiName(person=person, wiki=wiki, wikiname=wikiname)
+        wiki_name = WikiName(person=person, wiki=wiki, wikiname=wikiname)
+        IStore(wiki_name).flush()
+        return wiki_name
 
 
 @implementer(IJabberID)
-class JabberID(SQLBase, HasOwnerMixin):
+class JabberID(StormBase, HasOwnerMixin):
 
-    _table = "JabberID"
-    _defaultOrder = ["jabberid"]
+    __storm_table__ = "JabberID"
+    __storm_order__ = ["jabberid"]
 
-    person = ForeignKey(dbName="person", foreignKey="Person", notNull=True)
-    jabberid = StringCol(dbName="jabberid", notNull=True)
+    id = Int(primary=True)
+    person_id = Int(name="person", allow_none=False)
+    person = Reference(person_id, "Person.id")
+    jabberid = Unicode(name="jabberid", allow_none=False)
+
+    def __init__(self, person, jabberid):
+        super().__init__()
+        self.person = person
+        self.jabberid = jabberid
+
+    def destroySelf(self):
+        IStore(self).remove(self)
 
 
 @implementer(IJabberIDSet)
@@ -5260,22 +5283,33 @@ class JabberIDSet:
 
     def getByJabberID(self, jabberid):
         """See `IJabberIDSet`"""
-        return JabberID.selectOneBy(jabberid=jabberid)
+        return IStore(JabberID).find(JabberID, jabberid=jabberid).one()
 
     def getByPerson(self, person):
         """See `IJabberIDSet`"""
-        return JabberID.selectBy(person=person)
+        return IStore(JabberID).find(JabberID, person=person)
 
 
 @implementer(IIrcID)
-class IrcID(SQLBase, HasOwnerMixin):
+class IrcID(StormBase, HasOwnerMixin):
     """See `IIrcID`"""
 
-    _table = "IrcID"
+    __storm_table__ = "IrcID"
 
-    person = ForeignKey(dbName="person", foreignKey="Person", notNull=True)
-    network = StringCol(dbName="network", notNull=True)
-    nickname = StringCol(dbName="nickname", notNull=True)
+    id = Int(primary=True)
+    person_id = Int(name="person", allow_none=False)
+    person = Reference(person_id, "Person.id")
+    network = Unicode(name="network", allow_none=False)
+    nickname = Unicode(name="nickname", allow_none=False)
+
+    def __init__(self, person, network, nickname):
+        super().__init__()
+        self.person = person
+        self.network = network
+        self.nickname = nickname
+
+    def destroySelf(self):
+        IStore(self).remove(self)
 
 
 @implementer(IIrcIDSet)
@@ -5284,14 +5318,13 @@ class IrcIDSet:
 
     def get(self, id):
         """See `IIrcIDSet`"""
-        try:
-            return IrcID.get(id)
-        except SQLObjectNotFound:
-            return None
+        return IStore(IrcID).get(IrcID, int(id))
 
     def new(self, person, network, nickname):
         """See `IIrcIDSet`"""
-        return IrcID(person=person, network=network, nickname=nickname)
+        irc_id = IrcID(person=person, network=network, nickname=nickname)
+        IStore(irc_id).flush()
+        return irc_id
 
 
 class NicknameGenerationError(Exception):
diff --git a/lib/lp/registry/templates/person-portlet-contact-details.pt b/lib/lp/registry/templates/person-portlet-contact-details.pt
index 9f7d054..3d0e8b6 100644
--- a/lib/lp/registry/templates/person-portlet-contact-details.pt
+++ b/lib/lp/registry/templates/person-portlet-contact-details.pt
@@ -69,7 +69,7 @@
           <span tal:replace="jabberid/jabberid/fmt:obfuscate-email"
             /><span tal:condition="not: repeat/jabberid/end">,</span>
         </tal:block>
-        <div tal:condition="not: context/jabberids">
+        <div tal:condition="context/jabberids/is_empty">
           No Jabber IDs registered.
         </div>
       </dd>
@@ -164,7 +164,7 @@
           </a>
           <br />
         </tal:keys>
-        <div tal:condition="not: context/sshkeys">
+        <div tal:condition="context/sshkeys/is_empty">
           No SSH keys registered.
         </div>
       </dd>
diff --git a/lib/lp/registry/templates/productseries-codesummary.pt b/lib/lp/registry/templates/productseries-codesummary.pt
index d7c233b..d0c432d 100644
--- a/lib/lp/registry/templates/productseries-codesummary.pt
+++ b/lib/lp/registry/templates/productseries-codesummary.pt
@@ -32,7 +32,7 @@
             <tt class="command">
               bzr push lp:~<tal:user replace="view/user/name"/>/<tal:products replace="context/product/name"/>/<tal:series replace="context/name"/>
             </tt>
-            <tal:no-keys condition="not:view/user/sshkeys">
+            <tal:no-keys condition="view/user/sshkeys/is_empty">
               <br/>To authenticate with the Launchpad branch upload service,
               you need to
               <a tal:attributes="href string:${view/user/fmt:url}/+editsshkeys">
diff --git a/lib/lp/registry/vocabularies.py b/lib/lp/registry/vocabularies.py
index 59a48a8..eb4644f 100644
--- a/lib/lp/registry/vocabularies.py
+++ b/lib/lp/registry/vocabularies.py
@@ -758,7 +758,7 @@ class ValidPersonOrTeamVocabulary(
                 cache.preferredemail = email_by_person.get(person.id, None)
                 cache.ircnicknames = []
 
-            for nick in bulk.load_referencing(IrcID, persons, ["personID"]):
+            for nick in bulk.load_referencing(IrcID, persons, ["person_id"]):
                 get_property_cache(nick.person).ircnicknames.append(nick)
 
         return DecoratedResultSet(result, pre_iter_hook=pre_iter_hook)