~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/code/browser/branch.py

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-08-03 11:23:34 UTC
  • mfrom: (13457.6.16 upgrade-stderr)
  • Revision ID: launchpad@pqm.canonical.com-20110803112334-acnupsa7jmzmdeet
[r=stevenk][bug=819751] Fix the implementation of several methods in
 LoggingUIFactory.

Show diffs side-by-side

added added

removed removed

Lines of Context:
45
45
    copy_field,
46
46
    use_template,
47
47
    )
48
 
from lazr.restful.utils import smartquote
49
48
from lazr.uri import URI
50
49
import pytz
51
 
from zope.app.form import CustomWidgetFactory
 
50
import simplejson
52
51
from zope.app.form.browser import TextAreaWidget
53
 
from zope.app.form.browser.boolwidgets import CheckBoxWidget
54
52
from zope.component import (
55
53
    getUtility,
56
54
    queryAdapter,
74
72
    )
75
73
from zope.traversing.interfaces import IPathAdapter
76
74
 
77
 
from lp import _
 
75
from canonical.config import config
 
76
from canonical.database.constants import UTC_NOW
 
77
from canonical.launchpad import (
 
78
    _,
 
79
    searchbuilder,
 
80
    )
 
81
from canonical.launchpad.browser.feeds import (
 
82
    BranchFeedLink,
 
83
    FeedsMixin,
 
84
    )
 
85
from canonical.launchpad.helpers import truncate_text
 
86
from canonical.launchpad.webapp import (
 
87
    canonical_url,
 
88
    ContextMenu,
 
89
    enabled_with_permission,
 
90
    LaunchpadView,
 
91
    Link,
 
92
    Navigation,
 
93
    NavigationMenu,
 
94
    stepthrough,
 
95
    stepto,
 
96
    )
 
97
from canonical.launchpad.webapp.authorization import check_permission
 
98
from canonical.launchpad.webapp.interfaces import ICanonicalUrlData
 
99
from canonical.launchpad.webapp.menu import structured
 
100
from canonical.lazr.utils import smartquote
78
101
from lp.app.browser.launchpad import Hierarchy
79
102
from lp.app.browser.launchpadform import (
80
103
    action,
82
105
    LaunchpadEditFormView,
83
106
    LaunchpadFormView,
84
107
    )
85
 
from lp.app.browser.lazrjs import EnumChoiceWidget
 
108
from lp.app.browser.lazrjs import (
 
109
    EnumChoiceWidget,
 
110
    )
86
111
from lp.app.errors import NotFoundError
87
112
from lp.app.interfaces.launchpad import ILaunchpadCelebrities
88
113
from lp.app.widgets.itemswidgets import LaunchpadRadioWidgetWithDescription
107
132
from lp.code.errors import (
108
133
    BranchCreationForbidden,
109
134
    BranchExists,
110
 
    CannotUpgradeBranch,
111
135
    CodeImportAlreadyRequested,
112
136
    CodeImportAlreadyRunning,
113
137
    CodeImportNotInReviewedState,
128
152
    )
129
153
from lp.registry.interfaces.productseries import IProductSeries
130
154
from lp.registry.vocabularies import UserTeamsParticipationPlusSelfVocabulary
131
 
from lp.services import searchbuilder
132
 
from lp.services.config import config
133
 
from lp.services.database.constants import UTC_NOW
134
 
from lp.services.feeds.browser import (
135
 
    BranchFeedLink,
136
 
    FeedsMixin,
137
 
    )
138
 
from lp.services.helpers import truncate_text
139
155
from lp.services.propertycache import cachedproperty
140
 
from lp.services.webapp import (
141
 
    canonical_url,
142
 
    ContextMenu,
143
 
    enabled_with_permission,
144
 
    LaunchpadView,
145
 
    Link,
146
 
    Navigation,
147
 
    NavigationMenu,
148
 
    stepthrough,
149
 
    stepto,
150
 
    )
151
 
from lp.services.webapp.authorization import (
152
 
    check_permission,
153
 
    precache_permission_for_objects,
154
 
    )
155
 
from lp.services.webapp.interfaces import ICanonicalUrlData
156
 
from lp.services.webapp.menu import structured
157
156
from lp.translations.interfaces.translationtemplatesbuild import (
158
157
    ITranslationTemplatesBuildSource,
159
158
    )
441
440
    def initialize(self):
442
441
        self.branch = self.context
443
442
        self.notices = []
444
 
        # Cache permission so private team owner can be rendered.
445
 
        # The security adaptor will do the job also but we don't want or need
446
 
        # the expense of running several complex SQL queries.
447
 
        authorised_people = [self.branch.owner]
448
 
        if self.user is not None:
449
 
            precache_permission_for_objects(
450
 
                self.request, "launchpad.LimitedView", authorised_people)
451
443
        # Replace our context with a decorated branch, if it is not already
452
444
        # decorated.
453
445
        if not isinstance(self.context, DecoratedBranch):
647
639
               (RevisionControlSystems.SVN, RevisionControlSystems.BZR_SVN)
648
640
 
649
641
    @property
650
 
    def url_is_web(self):
651
 
        """True if an imported branch's URL is HTTP or HTTPS."""
652
 
        # You should only be calling this if it's an SVN, BZR, GIT or HG code
653
 
        # import
 
642
    def svn_url_is_web(self):
 
643
        """True if an imported branch's SVN URL is HTTP or HTTPS."""
 
644
        # You should only be calling this if it's an SVN code import
654
645
        assert self.context.code_import
655
646
        url = self.context.code_import.url
656
647
        assert url
722
713
        'lifecycle_status',
723
714
        'whiteboard',
724
715
        ])
725
 
    explicitly_private = copy_field(
726
 
        IBranch['explicitly_private'], readonly=False)
 
716
    private = copy_field(IBranch['private'], readonly=False)
727
717
    reviewer = copy_field(IBranch['reviewer'], required=True)
728
718
    owner = copy_field(IBranch['owner'], readonly=False)
729
719
 
766
756
                    "The branch owner has been changed to %s (%s)"
767
757
                    % (new_owner.displayname, new_owner.name))
768
758
        if 'private' in data:
769
 
            # Read only for display.
770
 
            data.pop('private')
771
 
        if 'explicitly_private' in data:
772
 
            private = data.pop('explicitly_private')
773
 
            if (private != self.context.private
774
 
                and self.context.private == self.context.explicitly_private):
 
759
            private = data.pop('private')
 
760
            if private != self.context.private:
775
761
                # We only want to show notifications if it actually changed.
776
762
                self.context.setPrivate(private, self.user)
777
763
                changed = True
852
838
    def mirror_of_ssh(self):
853
839
        """True if this a mirror branch with an sftp or bzr+ssh URL."""
854
840
        if not self.context.url:
855
 
            return False  # not a mirror branch
 
841
            return False # not a mirror branch
856
842
        uri = URI(self.context.url)
857
843
        return uri.scheme in ('sftp', 'bzr+ssh')
858
844
 
1008
994
 
1009
995
    @action('Upgrade', name='upgrade_branch')
1010
996
    def upgrade_branch_action(self, action, data):
1011
 
        try:
1012
 
            self.context.requestUpgrade(self.user)
1013
 
        except CannotUpgradeBranch as e:
1014
 
            self.request.response.addErrorNotification(e)
 
997
        self.context.requestUpgrade()
1015
998
 
1016
999
 
1017
1000
class BranchEditView(BranchEditFormView, BranchNameValidationMixin):
1018
1001
    """The main branch view for editing the branch attributes."""
1019
1002
 
1020
1003
    field_names = [
1021
 
        'owner', 'name', 'explicitly_private', 'url', 'description',
1022
 
        'lifecycle_status']
 
1004
        'owner', 'name', 'private', 'url', 'description', 'lifecycle_status']
1023
1005
 
1024
1006
    custom_widget('lifecycle_status', LaunchpadRadioWidgetWithDescription)
1025
1007
 
1035
1017
        if branch.private:
1036
1018
            # If the branch is private, and can be public, show the field.
1037
1019
            show_private_field = policy.canBranchesBePublic()
1038
 
 
1039
 
            # If this branch is public but is deemed private because it is
1040
 
            # stacked on a private branch, disable the field.
1041
 
            if not branch.explicitly_private:
1042
 
                show_private_field = False
1043
 
                private_info = Bool(
1044
 
                    __name__="private",
1045
 
                    title=_("Branch is confidential"),
1046
 
                    description=_(
1047
 
                        "This branch is confidential because it is stacked "
1048
 
                        "on a private branch."))
1049
 
                private_info_field = form.Fields(
1050
 
                    private_info, render_context=self.render_context)
1051
 
                self.form_fields = self.form_fields.omit('private')
1052
 
                self.form_fields = private_info_field + self.form_fields
1053
 
                self.form_fields['private'].custom_widget = (
1054
 
                    CustomWidgetFactory(
1055
 
                        CheckBoxWidget, extra='disabled="disabled"'))
1056
1020
        else:
1057
1021
            # If the branch is public, and can be made private, show the
1058
1022
            # field.  Users with special access rights to branches can set
1062
1026
                user_has_special_branch_access(self.user))
1063
1027
 
1064
1028
        if not show_private_field:
1065
 
            self.form_fields = self.form_fields.omit('explicitly_private')
 
1029
            self.form_fields = self.form_fields.omit('private')
1066
1030
 
1067
1031
        # If the user can administer branches, then they should be able to
1068
1032
        # assign the ownership of the branch to any valid person or team.
1153
1117
 
1154
1118
    class schema(Interface):
1155
1119
        use_template(
1156
 
            IBranch, include=['owner', 'name', 'lifecycle_status'])
 
1120
            IBranch, include=['owner', 'name', 'url', 'lifecycle_status'])
 
1121
        branch_type = copy_field(
 
1122
            IBranch['branch_type'], vocabulary=UICreatableBranchType)
1157
1123
 
1158
1124
    for_input = True
1159
 
    field_names = ['owner', 'name', 'lifecycle_status']
 
1125
    field_names = ['owner', 'name', 'branch_type', 'url', 'lifecycle_status']
1160
1126
 
1161
1127
    branch = None
 
1128
    custom_widget('branch_type', LaunchpadRadioWidgetWithDescription)
1162
1129
    custom_widget('lifecycle_status', LaunchpadRadioWidgetWithDescription)
1163
1130
 
1164
1131
    initial_focus_widget = 'name'
1187
1154
        """
1188
1155
        return IPerson(self.context, self.user)
1189
1156
 
 
1157
    def showOptionalMarker(self, field_name):
 
1158
        """Don't show the optional marker for url."""
 
1159
        if field_name == 'url':
 
1160
            return False
 
1161
        else:
 
1162
            return LaunchpadFormView.showOptionalMarker(self, field_name)
 
1163
 
1190
1164
    @action('Register Branch', name='add')
1191
1165
    def add_action(self, action, data):
1192
1166
        """Handle a request to create a new branch for this product."""
1193
1167
        try:
 
1168
            ui_branch_type = data['branch_type']
1194
1169
            namespace = self.target.getNamespace(data['owner'])
1195
1170
            self.branch = namespace.createBranch(
1196
 
                branch_type=BranchType.HOSTED,
 
1171
                branch_type=BranchType.items[ui_branch_type.name],
1197
1172
                name=data['name'],
1198
1173
                registrant=self.user,
1199
 
                url=None,
 
1174
                url=data.get('url'),
1200
1175
                lifecycle_status=data['lifecycle_status'])
 
1176
            if self.branch.branch_type == BranchType.MIRRORED:
 
1177
                self.branch.requestMirror()
1201
1178
        except BranchCreationForbidden:
1202
1179
            self.addError(
1203
1180
                "You are not allowed to create branches in %s." %
1215
1192
                'owner',
1216
1193
                'You are not a member of %s' % owner.displayname)
1217
1194
 
 
1195
        branch_type = data.get('branch_type')
 
1196
        # If branch_type failed to validate, then the rest of the method
 
1197
        # doesn't make any sense.
 
1198
        if branch_type is None:
 
1199
            return
 
1200
 
 
1201
        # If the branch is a MIRRORED branch, then the url
 
1202
        # must be supplied, and if HOSTED the url must *not*
 
1203
        # be supplied.
 
1204
        url = data.get('url')
 
1205
        if branch_type == UICreatableBranchType.MIRRORED:
 
1206
            if url is None:
 
1207
                # If the url is not set due to url validation errors,
 
1208
                # there will be an error set for it.
 
1209
                error = self.getFieldError('url')
 
1210
                if not error:
 
1211
                    self.setFieldError(
 
1212
                        'url',
 
1213
                        'Branch URLs are required for Mirrored branches.')
 
1214
        elif branch_type == UICreatableBranchType.HOSTED:
 
1215
            if url is not None:
 
1216
                self.setFieldError(
 
1217
                    'url',
 
1218
                    'Branch URLs cannot be set for Hosted branches.')
 
1219
        elif branch_type == UICreatableBranchType.REMOTE:
 
1220
            # A remote location can, but doesn't have to be set.
 
1221
            pass
 
1222
        else:
 
1223
            raise AssertionError('Unknown branch type')
 
1224
 
1218
1225
    @property
1219
1226
    def cancel_url(self):
1220
1227
        return canonical_url(self.context)