Simone Pelosi has proposed merging ~pelpsi/launchpad:social-account-interface-and-implementation into launchpad:master.
Commit message: SocialAccount interface and implementation SocialAccount interface to reflect DB table SocialAccount: each row of this new table is storing SocialAccount infomation associated to one person. One person could have more than one SocialAccount. This change is required since we are implementing Matrix. Requested reviews: Launchpad code reviewers (launchpad-reviewers) For more details, see: https://code.launchpad.net/~pelpsi/launchpad/+git/launchpad/+merge/457527 -- Your team Launchpad code reviewers is requested to review the proposed merge of ~pelpsi/launchpad:social-account-interface-and-implementation into launchpad:master.
diff --git a/lib/lp/registry/configure.zcml b/lib/lp/registry/configure.zcml index 3cf36a8..e362c03 100644 --- a/lib/lp/registry/configure.zcml +++ b/lib/lp/registry/configure.zcml @@ -650,6 +650,17 @@ interface="lp.registry.interfaces.jabber.IJabberIDSet"/> </lp:securedutility> <class + class="lp.registry.model.person.SocialAccountSet"> + <allow + interface="lp.registry.interfaces.socialaccount.ISocialAccountSet"/> + </class> + <lp:securedutility + class="lp.registry.model.person.SocialAccountSet" + provides="lp.registry.interfaces.socialaccount.ISocialAccountSet"> + <allow + interface="lp.registry.interfaces.socialaccount.ISocialAccountSet"/> + </lp:securedutility> + <class class="lp.registry.model.pillar.PillarName"> <allow interface="lp.registry.interfaces.pillar.IPillarName"/> diff --git a/lib/lp/registry/doc/socialaccount.rst b/lib/lp/registry/doc/socialaccount.rst new file mode 100644 index 0000000..84542be --- /dev/null +++ b/lib/lp/registry/doc/socialaccount.rst @@ -0,0 +1,31 @@ +Social Accounts +========== + +Social Accounts are associated with a person and must be created through the +ISocialAccountSet utility. + + >>> from lp.registry.interfaces.person import IPersonSet + >>> from lp.registry.interfaces.role import IHasOwner + >>> from lp.registry.interfaces.socialaccount import ( + ... ISocialAccount, + ... ISocialAccountSet, + ... PlatformType, + ... ) + +The new() method of ISocialAccountSet takes the person who will be associated +with the Social Account, a platform type and an identity dictionary. + + >>> salgado = getUtility(IPersonSet).getByName("salgado") + >>> identity = {} + >>> identity["matrix_id"] = "abc" + >>> social_account = getUtility(ISocialAccountSet).new( + ... salgado, PlatformType.MATRIX, identity + ... ) + +The returned SocialAccount object provides both ISocialAccount and IHasOwner. + + >>> from lp.testing import verifyObject + >>> verifyObject(ISocialAccount, social_account) + True + >>> verifyObject(IHasOwner, social_account) + True diff --git a/lib/lp/registry/interfaces/person.py b/lib/lp/registry/interfaces/person.py index 3aeae4c..bdb5ca6 100644 --- a/lib/lp/registry/interfaces/person.py +++ b/lib/lp/registry/interfaces/person.py @@ -121,6 +121,7 @@ from lp.registry.interfaces.location import ( from lp.registry.interfaces.mailinglistsubscription import ( MailingListAutoSubscribePolicy, ) +from lp.registry.interfaces.socialaccount import ISocialAccount from lp.registry.interfaces.ssh import ISSHKey from lp.registry.interfaces.teammembership import ( ITeamMembership, @@ -1030,6 +1031,15 @@ class IPersonViewRestricted( ), exported_as="jabber_ids", ) + socialaccounts = exported( + CollectionField( + title=_("List of Social Accounts of this Person."), + readonly=True, + required=False, + value_type=Reference(schema=ISocialAccount), + ), + exported_as="social_accounts", + ) team_memberships = exported( CollectionField( title=_( @@ -3241,3 +3251,4 @@ patch_reference_property(IIrcID, "person", IPerson) patch_reference_property(IJabberID, "person", IPerson) patch_reference_property(IWikiName, "person", IPerson) patch_reference_property(IEmailAddress, "person", IPerson) +patch_reference_property(ISocialAccount, "person", IPerson) diff --git a/lib/lp/registry/interfaces/socialaccount.py b/lib/lp/registry/interfaces/socialaccount.py new file mode 100644 index 0000000..f23a457 --- /dev/null +++ b/lib/lp/registry/interfaces/socialaccount.py @@ -0,0 +1,90 @@ +# Copyright 2009 Canonical Ltd. This software is licensed under the +# GNU Affero General Public License version 3 (see the file LICENSE). + +"""Jabber interfaces.""" + +__all__ = ["ISocialAccount", "ISocialAccountSet", "PlatformType"] + +from lazr.enum import DBEnumeratedType, DBItem +from lazr.restful.declarations import exported, exported_as_webservice_entry +from lazr.restful.fields import Reference +from zope.interface import Interface +from zope.schema import Choice, Dict, Int, TextLine + +from lp import _ +from lp.registry.interfaces.role import IHasOwner + + +class PlatformType(DBEnumeratedType): + """Platform Type + + When a social account is added it is referring + to a given platform type. + """ + + MATRIX = DBItem( + 1, + """ + Matrix platform + + To define matrix + """, + ) + + JABBER = DBItem( + 2, + """ + Jabber platform + + To define jabber + """, + ) + + +@exported_as_webservice_entry(as_of="beta") +class ISocialAccount(IHasOwner): + """Jabber specific user ID""" + + id = Int(title=_("Database ID"), required=True, readonly=True) + # schema=Interface will be overridden in person.py because of circular + # dependencies. + person = exported( + Reference( + title=_("Owner"), required=True, schema=Interface, readonly=True + ) + ) + + platform = exported( + Choice( + title=_("Platform type"), + required=True, + vocabulary=PlatformType, + default=PlatformType.MATRIX, + ) + ) + + identity = exported( + Dict( + title=_("SocialAccount identity"), + key_type=TextLine(), + required=True, + readonly=False, + description=_( + "A dictionary mapping attributes for the social media account " + "(JSON format specific per social media platform). " + ), + ) + ) + + def destroySelf(): + """Delete this SocialAccount from the database.""" + + +class ISocialAccountSet(Interface): + """The set of SocialAccounts.""" + + def new(self, person, platform, identity): + """Create a new SocialAccount pointing to the given Person.""" + + def getByPerson(person): + """Return all SocialAccounts for the given person.""" diff --git a/lib/lp/registry/model/person.py b/lib/lp/registry/model/person.py index 779616d..aa5f4be 100644 --- a/lib/lp/registry/model/person.py +++ b/lib/lp/registry/model/person.py @@ -19,6 +19,8 @@ __all__ = [ "PersonLanguage", "PersonSet", "PersonSettings", + "SocialAccount", + "SocialAccountSet", "SSHKey", "SSHKeySet", "TeamInvitationEvent", @@ -62,7 +64,15 @@ from storm.expr import ( With, ) from storm.info import ClassAlias -from storm.locals import Bool, DateTime, Int, Reference, ReferenceSet, Unicode +from storm.locals import ( + JSON, + Bool, + DateTime, + Int, + Reference, + ReferenceSet, + Unicode, +) from storm.store import EmptyResultSet, Store from twisted.conch.ssh.common import getNS from twisted.conch.ssh.keys import Key @@ -161,6 +171,11 @@ from lp.registry.interfaces.persontransferjob import IPersonMergeJobSource from lp.registry.interfaces.product import IProduct, IProductSet from lp.registry.interfaces.projectgroup import IProjectGroup from lp.registry.interfaces.role import IPersonRoles +from lp.registry.interfaces.socialaccount import ( + ISocialAccount, + ISocialAccountSet, + PlatformType, +) from lp.registry.interfaces.ssh import ( SSH_TEXT_TO_KEY_TYPE, ISSHKey, @@ -646,6 +661,7 @@ class Person( signedcocs = ReferenceSet("id", "SignedCodeOfConduct.owner_id") _ircnicknames = ReferenceSet("id", "IrcID.person_id") jabberids = ReferenceSet("id", "JabberID.person_id") + socialaccounts = ReferenceSet("id", "SocialAccount.person_id") visibility = DBEnum( enum=PersonVisibility, @@ -5321,6 +5337,45 @@ class WikiNameSet: return wiki_name +@implementer(ISocialAccount) +class SocialAccount(StormBase, HasOwnerMixin): + __storm_table__ = "SocialAccount" + + id = Int(primary=True) + person_id = Int(name="person", allow_none=False) + person = Reference(person_id, "Person.id") + platform = DBEnum( + name="platform", + allow_none=False, + enum=PlatformType, + ) + identity = JSON(name="identity", allow_none=False) + + def __init__(self, person, platform, identity): + super().__init__() + self.person = person + self.platform = platform + self.identity = identity + + def destroySelf(self): + IStore(self).remove(self) + + +@implementer(ISocialAccountSet) +class SocialAccountSet: + def getByPerson(self, person): + """See `ISocialAccountSet`.""" + return IStore(SocialAccount).find(SocialAccount, person=person) + + def new(self, person, platform, identity): + """See `ISocialAccountSet`.""" + social_account = SocialAccount( + person=person, platform=platform, identity=identity + ) + IStore(social_account).flush() + return social_account + + @implementer(IJabberID) class JabberID(StormBase, HasOwnerMixin): __storm_table__ = "JabberID" diff --git a/lib/lp/registry/tests/test_person.py b/lib/lp/registry/tests/test_person.py index 5381103..30fd456 100644 --- a/lib/lp/registry/tests/test_person.py +++ b/lib/lp/registry/tests/test_person.py @@ -38,6 +38,10 @@ from lp.registry.interfaces.karma import IKarmaCacheManager from lp.registry.interfaces.person import ImmutableVisibilityError, IPersonSet from lp.registry.interfaces.pocket import PackagePublishingPocket from lp.registry.interfaces.product import IProductSet +from lp.registry.interfaces.socialaccount import ( + ISocialAccountSet, + PlatformType, +) from lp.registry.interfaces.teammembership import ITeamMembershipSet from lp.registry.model.karma import KarmaCategory, KarmaTotalCache from lp.registry.model.person import Person, get_recipients @@ -438,6 +442,18 @@ class TestPerson(TestCaseWithFactory): self.assertEqual(None, person.homepage_content) self.assertEqual(None, person.teamdescription) + def test_social_account(self): + user = self.factory.makePerson() + attributes = {} + attributes["matrix_id"] = "abc" + getUtility(ISocialAccountSet).new( + user, PlatformType.MATRIX, attributes + ) + social_account = user.socialaccounts.one() + social_account = removeSecurityProxy(social_account) + self.assertEqual(social_account.platform, PlatformType.MATRIX) + self.assertEqual(social_account.identity["matrix_id"], "abc") + def test_getAffiliatedPillars_kinds(self): # Distributions, project groups, and projects are returned in this # same order.
_______________________________________________ Mailing list: https://launchpad.net/~launchpad-reviewers Post to : launchpad-reviewers@lists.launchpad.net Unsubscribe : https://launchpad.net/~launchpad-reviewers More help : https://help.launchpad.net/ListHelp