~wgrant/launchpad/bootstrap-db-from-scratch

10987 by William Grant
Add bootstrap scripts.
1
#!/usr/bin/python -S
2
#
3
# Copyright 2009 Canonical Ltd.  This software is licensed under the
4
# GNU Affero General Public License version 3 (see the file LICENSE).
5
6
"""Bootstrap a Launchpad database from scratch.
7
11011 by William Grant
Stop using the factory, and fix account creation to deal with OpenID properly.
8
Usage: bootstrap-lp-db <admin username> <admin email address> <openid suffix>
10987 by William Grant
Add bootstrap scripts.
9
10
This script will populate an empty Launchpad database with just the
11
celebrities and other magic required to not have everything crash.
12
11011 by William Grant
Stop using the factory, and fix account creation to deal with OpenID properly.
13
It also creates a user with the given username, email address and OpenID
14
identifier suffix as the root of everything. The OpenID identifier is arbitrary
15
if using testopenid.dev, but should match your identity provider otherwise.
10987 by William Grant
Add bootstrap scripts.
16
"""
17
18
import _pythonpath
19
20
import os
21
import sys
22
23
import transaction
24
from zope.component import getUtility
25
10994 by William Grant
Unbitrot bootstrap-lp-db.
26
from lp.services.scripts import execute_zcml_for_scripts
10987 by William Grant
Add bootstrap scripts.
27
from lp.registry.interfaces.distribution import IDistributionSet
10994 by William Grant
Unbitrot bootstrap-lp-db.
28
from lp.registry.interfaces.person import (
29
    IPersonSet,
11010 by William Grant
Allow the god's email addres to be customised.
30
    PersonCreationRationale,
11005 by William Grant
unbitrot bootstrap-lp-db.
31
    TeamMembershipPolicy,
10994 by William Grant
Unbitrot bootstrap-lp-db.
32
    )
10987 by William Grant
Add bootstrap scripts.
33
from lp.registry.interfaces.product import IProductSet
34
from lp.registry.model.karma import KarmaAction, KarmaCategory
11005 by William Grant
unbitrot bootstrap-lp-db.
35
from lp.services.database.interfaces import IStore
10997 by William Grant
Refactor celebrity creation to be a bit less duplicatastic, and create unactivated accounts by default.
36
from lp.services.identity.interfaces.account import AccountStatus
37
from lp.services.identity.interfaces.emailaddress import EmailAddressStatus
11011 by William Grant
Stop using the factory, and fix account creation to deal with OpenID properly.
38
from lp.services.identity.interfaces.emailaddress import EmailAddressStatus
39
from lp.services.openid.model.openididentifier import OpenIdIdentifier
10994 by William Grant
Unbitrot bootstrap-lp-db.
40
from lp.services.statistics.interfaces.statistic import (
41
    ILaunchpadStatisticSet)
10987 by William Grant
Add bootstrap scripts.
42
from lp.services.worlddata.interfaces.language import ILanguageSet
10994 by William Grant
Unbitrot bootstrap-lp-db.
43
from lp.testing.dbuser import switch_dbuser
10987 by William Grant
Add bootstrap scripts.
44
45
# Shut up, pyflakes.
46
_pythonpath = _pythonpath
47
48
49
def main(arguments):
50
    """Run the script."""
11011 by William Grant
Stop using the factory, and fix account creation to deal with OpenID properly.
51
    if len(arguments) != 3:
10987 by William Grant
Add bootstrap scripts.
52
        print __doc__
53
        return 2
54
    execute_zcml_for_scripts()
11011 by William Grant
Stop using the factory, and fix account creation to deal with OpenID properly.
55
    username, email_address, openid_suffix = [
56
        arg.decode('utf-8') for arg in arguments]
10987 by William Grant
Add bootstrap scripts.
57
    transaction.begin()
58
11001 by William Grant
Create a few more person/team celebs, and rework commentary a little.
59
    # Create the person named on the commandline first. It'll own the
60
    # admin team.
11011 by William Grant
Stop using the factory, and fix account creation to deal with OpenID properly.
61
    person, email = getUtility(IPersonSet).createPersonAndEmail(
62
        email_address, PersonCreationRationale.OWNER_CREATED_LAUNCHPAD,
63
        name=username, displayname=username)
64
    person.account.reactivate(u"when bootstrapping the database.")
65
    person.setPreferredEmail(email)
66
67
    identifier = OpenIdIdentifier()
68
    identifier.account = person.account
69
    identifier.identifier = openid_suffix
70
    IStore(OpenIdIdentifier).add(identifier)
10998 by William Grant
Since the people and teams all tend to be alike, just define dicts.
71
11001 by William Grant
Create a few more person/team celebs, and rework commentary a little.
72
    # Create celebrities. Lots of them.
73
    # There are a few that we don't create:
74
    # debbugs, debian, gnome_bugzilla, obsolete_junk, savannah_tracker,
75
    # sourceforge_tracker, ubuntu_bugzilla, ubuntu_archive_mirror,
76
    # ubuntu_cdimage_mirror.
77
10998 by William Grant
Since the people and teams all tend to be alike, just define dicts.
78
    # Create the admin team, the owner of most of the other celebrities.
11011 by William Grant
Stop using the factory, and fix account creation to deal with OpenID properly.
79
    admins = getUtility(IPersonSet).newTeam(
80
        person, 'admins', 'Launchpad Administrators',
11005 by William Grant
unbitrot bootstrap-lp-db.
81
        membership_policy=TeamMembershipPolicy.RESTRICTED)
10998 by William Grant
Since the people and teams all tend to be alike, just define dicts.
82
83
    teams = {
11012 by William Grant
Fix buildd-admins name.
84
        'launchpad-buildd-admins': 'Launchpad Builder Administrators',
10998 by William Grant
Since the people and teams all tend to be alike, just define dicts.
85
        'commercial-admins': 'Commercial Admins',
86
        'hwdb-team': 'Hardware Database Team',
87
        'launchpad': 'Launchpad Developers',
88
        'launchpad-beta-testers': 'Launchpad Beta Testers',
11006 by William Grant
Update celebrities.
89
        'launchpad-ppa-self-admins': 'Launchpad PPA Self Admins',
10998 by William Grant
Since the people and teams all tend to be alike, just define dicts.
90
        'registry': 'Registry Admins',
91
        'rosetta-admins': 'Rosetta Experts',
11001 by William Grant
Create a few more person/team celebs, and rework commentary a little.
92
        'ubuntu-security': 'Ubuntu Security Team',
93
        'techboard': 'Ubuntu Technical Board',
94
        'vcs-imports': 'VCS Imports Team',
10998 by William Grant
Since the people and teams all tend to be alike, just define dicts.
95
        }
96
    for name, displayname in teams.iteritems():
11011 by William Grant
Stop using the factory, and fix account creation to deal with OpenID properly.
97
        getUtility(IPersonSet).newTeam(
98
            admins, name, displayname,
11005 by William Grant
unbitrot bootstrap-lp-db.
99
            membership_policy=TeamMembershipPolicy.RESTRICTED)
10998 by William Grant
Since the people and teams all tend to be alike, just define dicts.
100
101
    people = {
11001 by William Grant
Create a few more person/team celebs, and rework commentary a little.
102
        'bug-importer': 'Bug Importer',
103
        'bug-watch-updater': 'Bug Watch Updater',
10998 by William Grant
Since the people and teams all tend to be alike, just define dicts.
104
        'janitor': 'Launchpad Janitor',
105
        'katie': 'Launchpad Autosync',
11001 by William Grant
Create a few more person/team celebs, and rework commentary a little.
106
        'ppa-key-guard': 'PPA Key Guard',
107
        'software-center-agent': 'Software Center Agent',
10998 by William Grant
Since the people and teams all tend to be alike, just define dicts.
108
        }
109
    for name, displayname in people.iteritems():
11011 by William Grant
Stop using the factory, and fix account creation to deal with OpenID properly.
110
        getUtility(IPersonSet).createPersonAndEmail(
111
            '%s@example.com' % name, PersonCreationRationale.UNKNOWN,
112
            name=name, displayname=displayname, hide_email_addresses=True)
10997 by William Grant
Refactor celebrity creation to be a bit less duplicatastic, and create unactivated accounts by default.
113
10987 by William Grant
Add bootstrap scripts.
114
    english = getUtility(ILanguageSet).createLanguage(
115
        'en', 'English', 'English', 2, 'n != 1')
10998 by William Grant
Since the people and teams all tend to be alike, just define dicts.
116
117
    launchpad_developers = getUtility(IPersonSet).getByName('launchpad')
10987 by William Grant
Add bootstrap scripts.
118
    launchpad = getUtility(IProductSet).createProduct(
119
        launchpad_developers, 'launchpad', 'Launchpad', 'Launchpad itself',
120
        'Launchpad is Launchpad.', 'Launchpad.',
121
        registrant=launchpad_developers)
11001 by William Grant
Create a few more person/team celebs, and rework commentary a little.
122
10987 by William Grant
Add bootstrap scripts.
123
    ubuntu = getUtility(IDistributionSet).new(
124
        'ubuntu', 'Ubuntu', 'Ubuntu', 'Ubuntu', 'Ubuntu', 'ubuntu.com',
10989 by William Grant
Unbitrot.
125
        admins, admins, admins)
10999 by William Grant
Set ubuntu.official_malone when bootstrapping, as otherwise BugTask:+editstatus and BugTask:+index crash.
126
    # BugTask:+editstatus crashes if Ubuntu isn't set to use Bugs
127
    # officially, as it's hardcoded as a default for a widget that only
128
    # allows official_malone pillars.
129
    ubuntu.official_malone = True
11000 by William Grant
Create Warty in bootstrap-lp-db to unbreak various things that assume ubuntu.currentseries exists.
130
    # Product:+index and various other places assume that
131
    # ubuntu.currentseries exists. So give it a series.
132
    # populate-ubuntu-from-scratch.py can create a more complete set
133
    # later if desired.
134
    ubuntu.newSeries(
135
        name='warty', title='Warty Warthog', displayname='Warty',
136
        summary='Ubuntu 4.10 is good.', description='4.10 is awesome.',
137
        version='4.10', previous_series=None, registrant=admins)
10987 by William Grant
Add bootstrap scripts.
138
139
140
    # Create some important karmaactions.
141
    karmacategories = {
142
        "code": ("Bazaar Branches", "This category for all karma associated "
143
                 "with branches and the links between branches and other "
144
                 "Launchpad entities.", {
145
            "branchmergerejected": (
146
                15, "Branch merge rejected", "User rejected a proposed "
147
                "branch merge."),
148
            "bugbranchcreated": (
149
                5, "Branch linked to a bug", "User linked a branch to a bug."),
150
            "specbranchcreated": (
151
                5, "Branch linked to a blueprint", "User linked a branch to "
152
                "a blueprint."),
153
            "branchmergeproposed": (
154
                1, "Branch merge proposed", "User proposed a branch for "
155
                "merging."),
156
            "codereviewcomment": (
157
                0, "Commented on a review", "User commented on a code "
158
                "review."),
159
            "branchmergerejectedown": (
160
                0, "Branch merge rejected", "User rejected their own proposed "
161
                "branch merge."),
162
            "revisionadded": (
163
                1, "Revision added", "A new revision by the user is available "
164
                "through Launchpad."),
165
            "codereviewreviewercomment": (
166
                10, "Reviewer commented on a review", "Reviewer commented on "
167
                "a code review."),
168
            "branchmergeapprovedown": (
169
                0, "Branch merge approved", "User approved their own branch "
170
                "for merging."),
171
            "branchmergeapproved": (
172
                15, "Branch merge approved", "User approved a branch for "
173
                "merging."),
174
            "branchcreated": (
175
                1, "New branch registered", "User registered a new branch.")
176
            }),
177
        "translations": ("Translations in Rosetta", "This categor covers all "
178
                         "actions related to translation using the Rosetta "
179
                         "web translation portal. Creating new translation "
180
                         "projects, submitting new translations and editing "
181
                         "existing translations will all earn karma.", {
182
            "translationtemplateimport": (
183
                1, "Import of Translation Template", "The user updated a "
184
                "translation template, providing a newer version to be "
185
                "imported in Rosetta."),
186
            "translationimportupstream": (
187
                0, "Upstream Translation Imported", "The user imported a set "
188
                "of upstream translations into Rosetta"),
189
            "translationtemplatedescriptionchanged": (
190
                2, "Edited Translation Template Description", "The user "
191
                "updated the description of a specific translation template."),
192
            "translationreview": (
193
                1, "Translation Review", "The user has completed a review of "
194
                "suggested translations."),
195
            "translationsuggestionapproved": (
196
                1, "Translation Suggestion Approved", "The user approved a "
197
                "translation suggestion that was previously contributed by "
198
                "someone else."),
199
            "translationsuggestionadded": (
200
                1, "Translation Suggestion", "The user contributed a new "
201
                "suggested translation. That may not yet have been accepted, "
202
                "but is valued nonetheless.")
203
            }),
204
        "bugs": ("Bug Management", "This karma category covers work in the "
205
                 "Malone bug tracking system, such as filing, closing and "
206
                 "otherwise working with bugs.", {
207
            "bugcreated": (
208
                10, "New Bug Filed", "The user filed a new bug report. This "
209
                "is distinct from creating a new \"task\" for an existing "
210
                "bug, on, say, an upstream product."),
211
            "bugmarkedasduplicate": (
212
                5, "Bug Marked as Duplicate", "The user has marked a bug as "
213
                "a duplicate of another bug. This greatly reduces the amount "
214
                "of time developers need to spend reviewing existing bug "
215
                "lists."),
216
            "bugaccepted": (
217
                5, "Bug Accepted", "The user has marked a bug as accepted."),
218
            "bugrejected": (
219
                3, "Bug Rejected", "The user has rejected a bug."),
220
            "bugtaskimportancechanged": (
221
                1, "Bug importance changed", "Updating the importance of a "
222
                "bug to a specific context. (The importance of a bug can vary "
223
                "depending on where the buggy code is being used.)"),
224
            "bugtaskprioritychanged": (
225
                1, "Bug Priority Changed", "The user has updated the priority "
226
                "of a particular bug task. Note that bug task has a distinct "
227
                "priority, because each of them will likely have a different "
228
                "developer responsible for them."),
229
            "bugextrefadded": (
230
                10, "Bug External Reference Added", "The user provided a URL "
231
                "to information which is relevant to this bug, for example, "
232
                "to a mailing list archive where it is discussed, or to a "
233
                "detailed problem report."),
234
            "bugtitlechanged": (
235
                1, "Edited Bug Title", "The user edited the title of the bug "
236
                "to provide a clearer idea of the core issue."),
237
            "bugdescriptionchanged": (
238
                3, "Edited Bug Description", "The user edited the bug "
239
                "description to describe more clearly the specific symptoms "
240
                "and expected outcomes for the bug. This will also improve "
241
                "the ability of other users to find this bug report and "
242
                "avoid creating duplicates."),
243
            "bugwatchadded": (
244
                10, "Bug Watch Added", "The user has linked an existing bug "
245
                "in Launchpad to an external bug tracker, to indicate that "
246
                "the bug is being tracked in that bug tracker too."),
247
            "bugfixed": (
248
                10, "Bug Marked as Fixed", "The user marked a bug as fixed."),
249
            "bugtaskcreated": (
250
                10, "Bug Task Created", "The user has created a new task on a "
251
                "bug. This means that they have indicated that the same bug "
252
                "exists in another place (for example, upstream) and have "
253
                "reported that in Malone."),
254
            "bugsummarychanged": (
255
                2, "Edited Bug Summary", "The user edited the bug summary. "
256
                "This will specifically help users searching for existing "
257
                "bugs in Malone."),
258
            "bugcommentadded": (
259
                0, "Bug Comment Added", "The user commented on an existing "
260
                "bug in Malone."),
261
            "bugcverefadded": (
262
                15, "Bug CVE Link Added", "The user has linked a bug report "
263
                "to a specific entry in the CVE database.")
264
            }),
265
        "answers": ("Answer Tracker", "This is the category for all karma "
266
                    "associated with helping with users questions in the "
267
                    "Launchpad Answer Tracker. Help solve users problems to "
268
                    "earn this karma.", {
269
            "questionownersolved": (
270
                3, "Solved own question", "User post a message explaining how "
271
                "he solved his own problem."),
272
            "questionrejected": (
273
                0, "Rejected question", "User rejected a question in the "
274
                "Answer Tracker."),
275
            "questionanswered": (
276
                15, "Answered question", "User posed a message that was "
277
                "accepted by the question owner as answering the question."),
278
            "questiongaveanswer": (
279
                0, "Gave answer on a question", "User post a message "
280
                "containing an answer to a question in the Answer Tracker. "
281
                "This is distinct from having that message confirmed as "
282
                "solving the problem."),
283
            "questionasked": (
284
                1, "Asked question", "User asked a question in the Answer "
285
                "Tracker."),
286
            "questiongaveinfo": (
287
                0, "Gave more information on a question", "User replied to a "
288
                "message asking for more information on a question in the "
289
                "Answer Tracker."),
290
            "questiontitlechanged": (
291
                1, "Question title changed", "User changed the title of a "
292
                "question in the Answer Tracker"),
293
            "faqcreated": (
294
                5, "FAQ created", "User create a new FAQ in Launchpad."),
295
            "questionansweraccepted": (
296
                5, "Question owner accepted answer", "User accepted one of "
297
                "the message as the actual answer to his question."),
298
            "faqedited": (
299
                1, "FAQ edited", "User updated the details of a FAQ in "
300
                "Launchpad."),
301
            "questionlinkedtobug": (
302
                5, "Question linked to a bug", "User linked a question in the "
303
                "Answer Tracker to a bug."),
304
            "questionreopened": (
305
                0, "Reopened question", "User posed a message to reopen his "
306
                "question in the Answer Tracker."),
307
            "questiondescriptionchanged": (
308
                3, "Question description changed", "User changed the "
309
                "description of a question in the Answer Tracker"),
310
            "questionrequestedinfo": (
311
                0, "Requested for information on a question", "User post a "
312
                "message requesting for more information from a question "
313
                "owner in the Answer Tracker."),
314
            "questioncommentadded": (
315
                0, "Comment made on a question", "User made a comment on a "
316
                "ticket in Launchpad.")
317
            }),
318
        "soyuz": ("Soyuz", "This category is for all karma associated with "
319
                  "Soyuz actions.", {
320
            "ppauploadaccepted": (
321
                1, "PPA package upload accepted", "A user uploaded a package "
322
                "to a PPA."),
323
            "distributionuploadaccepted": (
324
                10, "Distribution package upload accepted", "A user uploaded "
325
                "a package to a distribution."),
326
            "sponsoruploadaccepted": (
327
                5, "Sponsored package upload accepted", "A package sponsor "
328
                "uploaded a package to a distribution.")
329
            }),
330
        "specs": ("Specification Tracking", "This category includes all karma "
331
                  "associated with the Launchpad specification tracking "
332
                  "system.", {
333
            "specpendingapproval": (
334
                15, "Specification is Pending Approval", "The user has set "
335
                "the status of the spec to PendingApproval"),
336
            "specsummarychanged": (
337
                2, "Edited Specification Summary", "The user edited the "
338
                "summary of a specification."),
339
            "spectitlechanged": (
340
                2, "Edited Specification Title", "The user edited the title "
341
                "of a specification."),
342
            "specdraft": (
343
                3, "Specification Drafting", "The user has changed the status "
344
                "of the specification to indicate that drafting has begun."),
345
            "specseries": (
346
                5, "Targeted Specification to Series", "The user has "
347
                "targetted a specification to a particular series."),
348
            "specbugadded": (
349
                10, "Linked Bug to Specification", "The user has indicated "
350
                "that a particular bug is related to a specification."),
351
            "specpriority": (
352
                5, "Updated Specification Priority", "The user has changed "
353
                "the priority of a specification to match the requirements "
354
                "of the project."),
355
            "specbugremoved": (
356
                10, "Removed Bug from Specification", "The user has indicated "
357
                "that a particular bug is not related to a specification."),
358
            "specrelease": (
359
                5, "Targeted Specification to Release", "The user has "
360
                "targetted a specification to a particular distribution "
361
                "release."),
362
            "specmilestone": (
363
                5, "Targeted Specification to Milestone", "The user has "
364
                "targetted a specification to a particular milestone."),
365
            "specurlchanged": (
366
                2, "Specification URL Updated", "The user edited the URL of a "
367
                "specification."),
368
            "specreviewed": (
369
                10, "Specification Review", "The user has completed a review "
370
                "of a specification."),
371
            "addspec": (
372
                30, "Registered Specification", "The user has registered a "
373
                "new specification in the Launchpad spec tracker.")
374
            })
375
    }
376
10998 by William Grant
Since the people and teams all tend to be alike, just define dicts.
377
    store = IStore(KarmaAction)
10987 by William Grant
Add bootstrap scripts.
378
    for cname in karmacategories:
379
        ctitle, csummary, actions = karmacategories[cname]
380
        c = KarmaCategory(name=cname, title=ctitle, summary=csummary)
381
        store.add(c)
382
        for aname in actions:
383
            apoints, atitle, asummary = actions[aname]
384
            store.add(KarmaAction(
385
                name=aname, title=atitle, summary=asummary, points=apoints,
386
                category=c))
387
10994 by William Grant
Unbitrot bootstrap-lp-db.
388
    switch_dbuser('statistician')
389
390
    launchpad_stats = getUtility(ILaunchpadStatisticSet)
391
    launchpad_stats.updateStatistics(transaction)
392
11005 by William Grant
unbitrot bootstrap-lp-db.
393
    getUtility(IPersonSet).updateStatistics()
10994 by William Grant
Unbitrot bootstrap-lp-db.
394
10987 by William Grant
Add bootstrap scripts.
395
    transaction.commit()
396
    return 0
397
398
399
if __name__ == '__main__':
400
    sys.exit(main(sys.argv[1:]))