Paul Martin
2016-04-06 018ad3913231e1aa53a60a00db40d5fea7ceb279
commit | author | age
f13c4c 1 /*
JM 2  * Copyright 2011 gitblit.com.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
f5d0ad 16 package com.gitblit.wicket.pages;
JM 17
f98825 18 import java.text.MessageFormat;
JM 19 import java.util.ArrayList;
dfb889 20 import java.util.Arrays;
00afd7 21 import java.util.Collections;
eb96ea 22 import java.util.HashSet;
f98825 23 import java.util.Iterator;
7c1cdc 24 import java.util.LinkedHashMap;
f98825 25 import java.util.List;
JM 26 import java.util.Map;
eb96ea 27 import java.util.Set;
f5d0ad 28
JM 29 import org.apache.wicket.PageParameters;
092f0a 30 import org.apache.wicket.ajax.AjaxRequestTarget;
JM 31 import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
d3ca1c 32 import org.apache.wicket.behavior.SimpleAttributeModifier;
f98825 33 import org.apache.wicket.extensions.markup.html.form.palette.Palette;
ef4a45 34 import org.apache.wicket.markup.html.WebMarkupContainer;
JC 35 import org.apache.wicket.markup.html.basic.Label;
331fbc 36 import org.apache.wicket.markup.html.form.Button;
f5d0ad 37 import org.apache.wicket.markup.html.form.CheckBox;
37d5b7 38 import org.apache.wicket.markup.html.form.ChoiceRenderer;
dfb889 39 import org.apache.wicket.markup.html.form.DropDownChoice;
f5d0ad 40 import org.apache.wicket.markup.html.form.Form;
f98825 41 import org.apache.wicket.markup.html.form.IChoiceRenderer;
f5d0ad 42 import org.apache.wicket.markup.html.form.TextField;
b4ed66 43 import org.apache.wicket.markup.html.link.Link;
ef4a45 44 import org.apache.wicket.markup.html.list.ListItem;
JC 45 import org.apache.wicket.markup.html.list.ListView;
f5d0ad 46 import org.apache.wicket.model.CompoundPropertyModel;
3a2c57 47 import org.apache.wicket.model.IModel;
JM 48 import org.apache.wicket.model.Model;
85b5d7 49 import org.apache.wicket.model.PropertyModel;
f98825 50 import org.apache.wicket.model.util.CollectionModel;
JM 51 import org.apache.wicket.model.util.ListModel;
f1b882 52 import org.eclipse.jgit.lib.Repository;
f5d0ad 53
ef4a45 54 import com.gitblit.Constants;
dfb889 55 import com.gitblit.Constants.AccessRestrictionType;
6adf56 56 import com.gitblit.Constants.AuthorizationControl;
cd9461 57 import com.gitblit.Constants.CommitMessageRenderer;
831469 58 import com.gitblit.Constants.FederationStrategy;
092f0a 59 import com.gitblit.Constants.RegistrantType;
166e6a 60 import com.gitblit.GitBlitException;
00afd7 61 import com.gitblit.Keys;
822dfe 62 import com.gitblit.models.RegistrantAccessPermission;
1f9dae 63 import com.gitblit.models.RepositoryModel;
37d5b7 64 import com.gitblit.models.UserChoice;
1f9dae 65 import com.gitblit.models.UserModel;
0db5c4 66 import com.gitblit.utils.ArrayUtils;
f98825 67 import com.gitblit.utils.StringUtils;
00afd7 68 import com.gitblit.wicket.GitBlitWebSession;
6fa6ab 69 import com.gitblit.wicket.StringChoiceRenderer;
f5d0ad 70 import com.gitblit.wicket.WicketUtils;
6a437e 71 import com.gitblit.wicket.panels.AccessPolicyPanel;
b4ed66 72 import com.gitblit.wicket.panels.BasePanel.JavascriptEventConfirmation;
004bc1 73 import com.gitblit.wicket.panels.BooleanOption;
f9e51c 74 import com.gitblit.wicket.panels.BulletListPanel;
2cf367 75 import com.gitblit.wicket.panels.ChoiceOption;
822dfe 76 import com.gitblit.wicket.panels.RegistrantPermissionsPanel;
577998 77 import com.gitblit.wicket.panels.RepositoryNamePanel;
2cf367 78 import com.gitblit.wicket.panels.TextOption;
f5d0ad 79
d376ab 80 public class EditRepositoryPage extends RootSubPage {
f5d0ad 81
JM 82     private final boolean isCreate;
577998 83
JM 84     RepositoryNamePanel namePanel;
6a437e 85
JM 86     AccessPolicyPanel accessPolicyPanel;
f5d0ad 87
2a7306 88     private boolean isAdmin;
699e71 89
092f0a 90     RepositoryModel repositoryModel;
3a2c57 91
cedf13 92     private IModel<String> metricAuthorExclusions;
699e71 93
eb96ea 94     private IModel<String> mailingLists;
2a7306 95
f5d0ad 96     public EditRepositoryPage() {
JM 97         // create constructor
98         super();
99         isCreate = true;
94dcbd 100         RepositoryModel model = new RepositoryModel();
99d0d4 101         String restriction = app().settings().getString(Keys.git.defaultAccessRestriction, "PUSH");
94dcbd 102         model.accessRestriction = AccessRestrictionType.fromName(restriction);
99d0d4 103         String authorization = app().settings().getString(Keys.git.defaultAuthorizationControl, null);
6adf56 104         model.authorizationControl = AuthorizationControl.fromName(authorization);
699e71 105
6662e3 106         GitBlitWebSession session = GitBlitWebSession.get();
JM 107         UserModel user = session.getUser();
7f7051 108         if (user != null && user.canCreate() && !user.canAdmin()) {
6662e3 109             // personal create permissions, inject personal repository path
JM 110             model.name = user.getPersonalPath() + "/";
111             model.projectPath = user.getPersonalPath();
661db6 112             model.addOwner(user.username);
6662e3 113             // personal repositories are private by default
JM 114             model.accessRestriction = AccessRestrictionType.VIEW;
115             model.authorizationControl = AuthorizationControl.NAMED;
116         }
699e71 117
94dcbd 118         setupPage(model);
97a715 119         setStatelessHint(false);
092f0a 120         setOutputMarkupId(true);
f5d0ad 121     }
JM 122
123     public EditRepositoryPage(PageParameters params) {
124         // edit constructor
125         super(params);
126         isCreate = false;
1e8390 127         String name = WicketUtils.getRepositoryName(params);
99d0d4 128         RepositoryModel model = app().repositories().getRepositoryModel(name);
1e8390 129         setupPage(model);
97a715 130         setStatelessHint(false);
092f0a 131         setOutputMarkupId(true);
f5d0ad 132     }
699e71 133
dd630f 134     @Override
JM 135     protected boolean requiresPageMap() {
136         return true;
137     }
699e71 138
6ef8d7 139     @Override
JM 140     protected Class<? extends BasePage> getRootNavPageClass() {
141         return RepositoriesPage.class;
142     }
f5d0ad 143
092f0a 144     protected void setupPage(RepositoryModel model) {
JM 145         this.repositoryModel = model;
699e71 146
00afd7 147         // ensure this user can create or edit this repository
JM 148         checkPermissions(repositoryModel);
2a7306 149
40ca5c 150         List<String> indexedBranches = new ArrayList<String>();
8f73a7 151         List<String> federationSets = new ArrayList<String>();
822dfe 152         final List<RegistrantAccessPermission> repositoryUsers = new ArrayList<RegistrantAccessPermission>();
JM 153         final List<RegistrantAccessPermission> repositoryTeams = new ArrayList<RegistrantAccessPermission>();
6cc1d4 154         List<String> preReceiveScripts = new ArrayList<String>();
JM 155         List<String> postReceiveScripts = new ArrayList<String>();
156
6662e3 157         GitBlitWebSession session = GitBlitWebSession.get();
JM 158         final UserModel user = session.getUser() == null ? UserModel.ANONYMOUS : session.getUser();
2711bc 159         final boolean allowEditName = isCreate || isAdmin || repositoryModel.isUsersPersonalRepository(user.username);
699e71 160
f5d0ad 161         if (isCreate) {
7f7051 162             if (user.canAdmin()) {
6662e3 163                 super.setupPage(getString("gb.newRepository"), "");
JM 164             } else {
165                 super.setupPage(getString("gb.newRepository"), user.getDisplayName());
166             }
f5d0ad 167         } else {
a7571b 168             super.setupPage(getString("gb.edit"), repositoryModel.name);
99d0d4 169             repositoryUsers.addAll(app().repositories().getUserAccessPermissions(repositoryModel));
JM 170             repositoryTeams.addAll(app().repositories().getTeamAccessPermissions(repositoryModel));
70e3d1 171             Collections.sort(repositoryUsers);
af6d95 172             Collections.sort(repositoryTeams);
699e71 173
8f73a7 174             federationSets.addAll(repositoryModel.federationSets);
40ca5c 175             if (!ArrayUtils.isEmpty(repositoryModel.indexedBranches)) {
JM 176                 indexedBranches.addAll(repositoryModel.indexedBranches);
177             }
3a2c57 178         }
f98825 179
8a2e9c 180         final String oldName = repositoryModel.name;
fe24a0 181
699e71 182         final RegistrantPermissionsPanel usersPalette = new RegistrantPermissionsPanel("users",
99d0d4 183                 RegistrantType.USER, app().users().getAllUsernames(), repositoryUsers, getAccessPermissions());
699e71 184         final RegistrantPermissionsPanel teamsPalette = new RegistrantPermissionsPanel("teams",
db4f6b 185                 RegistrantType.TEAM, app().users().getAllTeamNames(), repositoryTeams, getAccessPermissions());
8f73a7 186
661db6 187         // owners palette
37d5b7 188         List<UserChoice> owners = new ArrayList<UserChoice>();
dd2dc3 189         List<UserChoice> persons = new ArrayList<UserChoice>();
37d5b7 190         for (String owner : repositoryModel.owners) {
AS 191             UserModel o = app().users().getUserModel(owner);
192             if (o != null) {
193                 owners.add(new UserChoice(o.getDisplayName(), o.username, o.emailAddress));
194             } else {
dd2dc3 195                 UserChoice userChoice = new UserChoice(owner);
JM 196                 owners.add(userChoice);
197                 persons.add(userChoice);
37d5b7 198             }
AS 199         }
dd2dc3 200
37d5b7 201         for (String person : app().users().getAllUsernames()) {
AS 202             UserModel o = app().users().getUserModel(person);
203             if (o != null) {
204                 persons.add(new UserChoice(o.getDisplayName(), o.username, o.emailAddress));
205             } else {
206                 persons.add(new UserChoice(person));
207             }
208         }
209         final Palette<UserChoice> ownersPalette = new Palette<UserChoice>("owners", new ListModel<UserChoice>(owners), new CollectionModel<UserChoice>(
85b5d7 210               persons), new ChoiceRenderer<UserChoice>(null, "userId"), 12, false);
699e71 211
40ca5c 212         // indexed local branches palette
1aabf0 213         List<String> allLocalBranches = new ArrayList<String>();
JM 214         allLocalBranches.add(Constants.DEFAULT_BRANCH);
215         allLocalBranches.addAll(repositoryModel.getLocalBranches());
99d0d4 216         boolean luceneEnabled = app().settings().getBoolean(Keys.web.allowLuceneIndexing, true);
40ca5c 217         final Palette<String> indexedBranchesPalette = new Palette<String>("indexedBranches", new ListModel<String>(
JM 218                 indexedBranches), new CollectionModel<String>(allLocalBranches),
219                 new StringChoiceRenderer(), 8, false);
1aabf0 220         indexedBranchesPalette.setEnabled(luceneEnabled);
699e71 221
8f73a7 222         // federation sets palette
99d0d4 223         List<String> sets = app().settings().getStrings(Keys.federation.sets);
8f73a7 224         final Palette<String> federationSetsPalette = new Palette<String>("federationSets",
JM 225                 new ListModel<String>(federationSets), new CollectionModel<String>(sets),
40ca5c 226                 new StringChoiceRenderer(), 8, false);
6cc1d4 227
JM 228         // pre-receive palette
0db5c4 229         if (!ArrayUtils.isEmpty(repositoryModel.preReceiveScripts)) {
6cc1d4 230             preReceiveScripts.addAll(repositoryModel.preReceiveScripts);
JM 231         }
232         final Palette<String> preReceivePalette = new Palette<String>("preReceiveScripts",
99d0d4 233                 new ListModel<String>(preReceiveScripts), new CollectionModel<String>(app().repositories()
JM 234                         .getPreReceiveScriptsUnused(repositoryModel)),
6fa6ab 235                 new StringChoiceRenderer(), 12, true);
6cc1d4 236
JM 237         // post-receive palette
0db5c4 238         if (!ArrayUtils.isEmpty(repositoryModel.postReceiveScripts)) {
6cc1d4 239             postReceiveScripts.addAll(repositoryModel.postReceiveScripts);
JM 240         }
241         final Palette<String> postReceivePalette = new Palette<String>("postReceiveScripts",
99d0d4 242                 new ListModel<String>(postReceiveScripts), new CollectionModel<String>(app().repositories()
JM 243                         .getPostReceiveScriptsUnused(repositoryModel)),
6fa6ab 244                 new StringChoiceRenderer(), 12, true);
699e71 245
7c1cdc 246         // custom fields
99d0d4 247         final Map<String, String> customFieldsMap = app().settings().getMap(Keys.groovy.customFields);
7c1cdc 248         List<String> customKeys = new ArrayList<String>(customFieldsMap.keySet());
JM 249         final ListView<String> customFieldsListView = new ListView<String>("customFieldsListView", customKeys) {
699e71 250
7c1cdc 251             private static final long serialVersionUID = 1L;
JM 252
ef4a45 253             @Override
7c1cdc 254             protected void populateItem(ListItem<String> item) {
JM 255                 String key = item.getModelObject();
256                 item.add(new Label("customFieldLabel", customFieldsMap.get(key)));
699e71 257
7c1cdc 258                 String value = "";
JM 259                 if (repositoryModel.customFields != null && repositoryModel.customFields.containsKey(key)) {
260                     value = repositoryModel.customFields.get(key);
261                 }
262                 TextField<String> field = new TextField<String>("customFieldValue", new Model<String>(value));
263                 item.add(field);
ef4a45 264             }
JC 265         };
08d86d 266         customFieldsListView.setReuseItems(true);
8f73a7 267
092f0a 268         CompoundPropertyModel<RepositoryModel> rModel = new CompoundPropertyModel<RepositoryModel>(
2a7306 269                 repositoryModel);
092f0a 270         Form<RepositoryModel> form = new Form<RepositoryModel>("editForm", rModel) {
f5d0ad 271
JM 272             private static final long serialVersionUID = 1L;
273
274             @Override
275             protected void onSubmit() {
166e6a 276                 try {
577998 277                     if (!namePanel.updateModel(repositoryModel)) {
f98825 278                         return;
JM 279                     }
008322 280
f98825 281                     // confirm access restriction selection
JM 282                     if (repositoryModel.accessRestriction == null) {
6caa93 283                         error(getString("gb.selectAccessRestriction"));
f98825 284                         return;
JM 285                     }
00afd7 286
bcc616 287                     // confirm federation strategy selection
JM 288                     if (repositoryModel.federationStrategy == null) {
6caa93 289                         error(getString("gb.selectFederationStrategy"));
bcc616 290                         return;
JM 291                     }
292
8f73a7 293                     // save federation set preferences
JM 294                     if (repositoryModel.federationStrategy.exceeds(FederationStrategy.EXCLUDE)) {
295                         repositoryModel.federationSets.clear();
296                         Iterator<String> sets = federationSetsPalette.getSelectedChoices();
297                         while (sets.hasNext()) {
298                             repositoryModel.federationSets.add(sets.next());
299                         }
300                     }
301
cedf13 302                     // set author metric exclusions
JM 303                     String ax = metricAuthorExclusions.getObject();
478ba8 304                     if (StringUtils.isEmpty(ax)) {
JM 305                         repositoryModel.metricAuthorExclusions = new ArrayList<String>();
306                     } else {
cedf13 307                         Set<String> list = new HashSet<String>();
JM 308                         for (String exclusion : StringUtils.getStringsFromValue(ax,  " ")) {
309                             if (StringUtils.isEmpty(exclusion)) {
310                                 continue;
311                             }
312                             if (exclusion.indexOf(' ') > -1) {
699e71 313                                 list.add("\"" + exclusion + "\"");
cedf13 314                             } else {
JM 315                                 list.add(exclusion);
316                             }
317                         }
318                         repositoryModel.metricAuthorExclusions = new ArrayList<String>(list);
319                     }
320
eb96ea 321                     // set mailing lists
JM 322                     String ml = mailingLists.getObject();
478ba8 323                     if (StringUtils.isEmpty(ml)) {
JM 324                         repositoryModel.mailingLists = new ArrayList<String>();
325                     } else {
eb96ea 326                         Set<String> list = new HashSet<String>();
JM 327                         for (String address : ml.split("(,|\\s)")) {
328                             if (StringUtils.isEmpty(address)) {
329                                 continue;
330                             }
331                             list.add(address.toLowerCase());
332                         }
333                         repositoryModel.mailingLists = new ArrayList<String>(list);
3a2c57 334                     }
JM 335
40ca5c 336                     // indexed branches
JM 337                     List<String> indexedBranches = new ArrayList<String>();
338                     Iterator<String> branches = indexedBranchesPalette.getSelectedChoices();
339                     while (branches.hasNext()) {
340                         indexedBranches.add(branches.next());
341                     }
342                     repositoryModel.indexedBranches = indexedBranches;
343
661db6 344                     // owners
JM 345                     repositoryModel.owners.clear();
37d5b7 346                     Iterator<UserChoice> owners = ownersPalette.getSelectedChoices();
661db6 347                     while (owners.hasNext()) {
37d5b7 348                         repositoryModel.addOwner(owners.next().getUserId());
fb9813 349                     }
699e71 350
6cc1d4 351                     // pre-receive scripts
JM 352                     List<String> preReceiveScripts = new ArrayList<String>();
353                     Iterator<String> pres = preReceivePalette.getSelectedChoices();
354                     while (pres.hasNext()) {
355                         preReceiveScripts.add(pres.next());
356                     }
357                     repositoryModel.preReceiveScripts = preReceiveScripts;
358
359                     // post-receive scripts
360                     List<String> postReceiveScripts = new ArrayList<String>();
361                     Iterator<String> post = postReceivePalette.getSelectedChoices();
362                     while (post.hasNext()) {
363                         postReceiveScripts.add(post.next());
364                     }
365                     repositoryModel.postReceiveScripts = postReceiveScripts;
699e71 366
7c1cdc 367                     // custom fields
JM 368                     repositoryModel.customFields = new LinkedHashMap<String, String>();
08d86d 369                     for (int i = 0; i < customFieldsListView.size(); i++) {
7c1cdc 370                         ListItem<String> child = (ListItem<String>) customFieldsListView.get(i);
JM 371                         String key = child.getModelObject();
372
373                         TextField<String> field = (TextField<String>) child.get("customFieldValue");
374                         String value = field.getValue();
699e71 375
08d86d 376                         repositoryModel.customFields.put(key, value);
ef4a45 377                     }
699e71 378
f98825 379                     // save the repository
5e3521 380                     app().gitblit().updateRepositoryModel(oldName, repositoryModel, isCreate);
00afd7 381
97a715 382                     // repository access permissions
f98825 383                     if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {
5e3521 384                         app().gitblit().setUserAccessPermissions(repositoryModel, repositoryUsers);
JM 385                         app().gitblit().setTeamAccessPermissions(repositoryModel, repositoryTeams);
f98825 386                     }
166e6a 387                 } catch (GitBlitException e) {
JM 388                     error(e.getMessage());
389                     return;
390                 }
a098da 391                 setRedirect(false);
0047fb 392                 setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryModel.name));
f5d0ad 393             }
JM 394         };
dfb889 395
85b5d7 396         // Determine available refs & branches
90b8d7 397         List<String> availableRefs = new ArrayList<String>();
f1b882 398         List<String> availableBranches = new ArrayList<String>();
90b8d7 399         if (!ArrayUtils.isEmpty(repositoryModel.availableRefs)) {
f1b882 400             for (String ref : repositoryModel.availableRefs) {
JM 401                 if (!ref.startsWith(Constants.R_TICKET)) {
402                     availableRefs.add(ref);
403                     if (ref.startsWith(Constants.R_HEADS)) {
404                         availableBranches.add(Repository.shortenRefName(ref));
405                     }
406                 }
407             }
ddbf67 408         }
8f73a7 409
85b5d7 410         // do not let the browser pre-populate these fields
JM 411         form.add(new SimpleAttributeModifier("autocomplete", "off"));
e92c6d 412
8295dd 413
85b5d7 414         //
JM 415         //
416         // GENERAL
417         //
418         namePanel = new RepositoryNamePanel("namePanel", repositoryModel);
419         namePanel.setEditable(allowEditName);
420         form.add(namePanel);
cedf13 421
85b5d7 422         // XXX AccessPolicyPanel is defined later.
699e71 423
2cf367 424         form.add(new ChoiceOption<String>("head",
85b5d7 425                 getString("gb.headRef"),
JM 426                 getString("gb.headRefDescription"),
427                 new PropertyModel<String>(repositoryModel, "HEAD"),
428                 availableRefs));
15640f 429
85b5d7 430
JM 431         //
432         // PERMISSIONS
433         //
434         form.add(ownersPalette);
f98825 435         form.add(usersPalette);
fe24a0 436         form.add(teamsPalette);
85b5d7 437
JM 438         //
439         // TICKETS
440         //
004bc1 441         form.add(new BooleanOption("acceptNewPatchsets",
85b5d7 442                 getString("gb.acceptNewPatchsets"),
JM 443                 getString("gb.acceptNewPatchsetsDescription"),
444                 new PropertyModel<Boolean>(repositoryModel, "acceptNewPatchsets")));
445
004bc1 446         form.add(new BooleanOption("acceptNewTickets",
85b5d7 447                 getString("gb.acceptNewTickets"),
JM 448                 getString("gb.acceptNewTicketsDescription"),
b9ac86 449                 new PropertyModel<Boolean>(repositoryModel, "acceptNewTickets")));
85b5d7 450
004bc1 451         form.add(new BooleanOption("requireApproval",
85b5d7 452                 getString("gb.requireApproval"),
JM 453                 getString("gb.requireApprovalDescription"),
454                 new PropertyModel<Boolean>(repositoryModel, "requireApproval")));
455
2cf367 456         form.add(new ChoiceOption<String>("mergeTo",
85b5d7 457                 getString("gb.mergeTo"),
JM 458                 getString("gb.mergeToDescription"),
459                 new PropertyModel<String>(repositoryModel, "mergeTo"),
460                 availableBranches));
461
462         //
463         // RECEIVE
464         //
004bc1 465         form.add(new BooleanOption("isFrozen",
85b5d7 466                 getString("gb.isFrozen"),
JM 467                 getString("gb.isFrozenDescription"),
468                 new PropertyModel<Boolean>(repositoryModel, "isFrozen")));
469
004bc1 470         form.add(new BooleanOption("incrementalPushTags",
85b5d7 471                 getString("gb.enableIncrementalPushTags"),
JM 472                 getString("gb.useIncrementalPushTagsDescription"),
473                 new PropertyModel<Boolean>(repositoryModel, "useIncrementalPushTags")));
474
475         final CheckBox verifyCommitter = new CheckBox("checkbox", new PropertyModel<Boolean>(repositoryModel, "verifyCommitter"));
476         verifyCommitter.setOutputMarkupId(true);
004bc1 477         form.add(new BooleanOption("verifyCommitter",
85b5d7 478                 getString("gb.verifyCommitter"),
2cf367 479                 getString("gb.verifyCommitterDescription") + "<br/>" + getString("gb.verifyCommitterNote"),
JM 480                 verifyCommitter).setIsHtmlDescription(true));
85b5d7 481
6cc1d4 482         form.add(preReceivePalette);
99d0d4 483         form.add(new BulletListPanel("inheritedPreReceive", getString("gb.inherited"), app().repositories()
d7905a 484                 .getPreReceiveScriptsInherited(repositoryModel)));
6cc1d4 485         form.add(postReceivePalette);
99d0d4 486         form.add(new BulletListPanel("inheritedPostReceive", getString("gb.inherited"), app().repositories()
d7905a 487                 .getPostReceiveScriptsInherited(repositoryModel)));
699e71 488
7c1cdc 489         WebMarkupContainer customFieldsSection = new WebMarkupContainer("customFieldsSection");
JM 490         customFieldsSection.add(customFieldsListView);
99d0d4 491         form.add(customFieldsSection.setVisible(!app().settings().getString(Keys.groovy.customFields, "").isEmpty()));
85b5d7 492
JM 493         //
494         // FEDERATION
495         //
496         List<FederationStrategy> federationStrategies = new ArrayList<FederationStrategy>(
497                 Arrays.asList(FederationStrategy.values()));
498         // federation strategies - remove ORIGIN choice if this repository has no origin.
499         if (StringUtils.isEmpty(repositoryModel.origin)) {
500             federationStrategies.remove(FederationStrategy.FEDERATE_ORIGIN);
501         }
502
2cf367 503         form.add(new ChoiceOption<FederationStrategy>("federationStrategy",
85b5d7 504                 getString("gb.federationStrategy"),
JM 505                 getString("gb.federationStrategyDescription"),
506                 new DropDownChoice<FederationStrategy>(
507                         "choice",
508                         new PropertyModel<FederationStrategy>(repositoryModel, "federationStrategy"),
509                         federationStrategies,
510                         new FederationTypeRenderer())));
511
512         form.add(federationSetsPalette);
513
514         //
515         // SEARCH
516         //
517         form.add(indexedBranchesPalette);
518
519         //
520         // GARBAGE COLLECTION
521         //
522         boolean gcEnabled = app().settings().getBoolean(Keys.git.enableGarbageCollection, false);
523         int defaultGcPeriod = app().settings().getInteger(Keys.git.defaultGarbageCollectionPeriod, 7);
524         if (repositoryModel.gcPeriod == 0) {
525             repositoryModel.gcPeriod = defaultGcPeriod;
526         }
527         List<Integer> gcPeriods = Arrays.asList(1, 2, 3, 4, 5, 7, 10, 14 );
2cf367 528         form.add(new ChoiceOption<Integer>("gcPeriod",
85b5d7 529                 getString("gb.gcPeriod"),
JM 530                 getString("gb.gcPeriodDescription"),
531                 new DropDownChoice<Integer>("choice",
532                         new PropertyModel<Integer>(repositoryModel, "gcPeriod"),
533                         gcPeriods,
534                         new GCPeriodRenderer())).setEnabled(gcEnabled));
535
2cf367 536         form.add(new TextOption("gcThreshold",
85b5d7 537                 getString("gb.gcThreshold"),
JM 538                 getString("gb.gcThresholdDescription"),
539                 "span1",
540                 new PropertyModel<String>(repositoryModel, "gcThreshold")).setEnabled(gcEnabled));
541
542         //
543         // MISCELLANEOUS
544         //
545
2cf367 546         form.add(new TextOption("origin",
85b5d7 547                 getString("gb.origin"),
JM 548                 getString("gb.originDescription"),
549                 "span6",
550                 new PropertyModel<String>(repositoryModel, "origin")).setEnabled(false));
551
004bc1 552         form.add(new BooleanOption("showRemoteBranches",
85b5d7 553                 getString("gb.showRemoteBranches"),
JM 554                 getString("gb.showRemoteBranchesDescription"),
555                 new PropertyModel<Boolean>(repositoryModel, "showRemoteBranches")));
556
004bc1 557         form.add(new BooleanOption("skipSizeCalculation",
85b5d7 558                 getString("gb.skipSizeCalculation"),
JM 559                 getString("gb.skipSizeCalculationDescription"),
560                 new PropertyModel<Boolean>(repositoryModel, "skipSizeCalculation")));
561
004bc1 562         form.add(new BooleanOption("skipSummaryMetrics",
85b5d7 563                 getString("gb.skipSummaryMetrics"),
JM 564                 getString("gb.skipSummaryMetricsDescription"),
565                 new PropertyModel<Boolean>(repositoryModel, "skipSummaryMetrics")));
566
567         List<Integer> maxActivityCommits  = Arrays.asList(-1, 0, 25, 50, 75, 100, 150, 200, 250, 500);
2cf367 568         form.add(new ChoiceOption<Integer>("maxActivityCommits",
85b5d7 569                 getString("gb.maxActivityCommits"),
JM 570                 getString("gb.maxActivityCommitsDescription"),
571                 new DropDownChoice<Integer>("choice",
572                         new PropertyModel<Integer>(repositoryModel, "maxActivityCommits"),
573                         maxActivityCommits,
574                         new MaxActivityCommitsRenderer())));
575
576         List<CommitMessageRenderer> renderers = Arrays.asList(CommitMessageRenderer.values());
2cf367 577         form.add(new ChoiceOption<CommitMessageRenderer>("commitMessageRenderer",
85b5d7 578                 getString("gb.commitMessageRenderer"),
JM 579                 getString("gb.commitMessageRendererDescription"),
580                 new DropDownChoice<CommitMessageRenderer>("choice",
581                         new PropertyModel<CommitMessageRenderer>(repositoryModel, "commitMessageRenderer"),
582                         renderers)));
583
584         metricAuthorExclusions = new Model<String>(ArrayUtils.isEmpty(repositoryModel.metricAuthorExclusions) ? ""
585                 : StringUtils.flattenStrings(repositoryModel.metricAuthorExclusions, " "));
586
2cf367 587         form.add(new TextOption("metricAuthorExclusions",
85b5d7 588                 getString("gb.metricAuthorExclusions"),
JM 589                 getString("gb.metricAuthorExclusions"),
590                 "span6",
591                 metricAuthorExclusions));
592
593         mailingLists = new Model<String>(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? ""
594                 : StringUtils.flattenStrings(repositoryModel.mailingLists, " "));
595
2cf367 596         form.add(new TextOption("mailingLists",
85b5d7 597                 getString("gb.mailingLists"),
JM 598                 getString("gb.mailingLists"),
599                 "span6",
600                 mailingLists));
601
699e71 602
092f0a 603         // initial enable/disable of permission controls
JM 604         if (repositoryModel.accessRestriction.equals(AccessRestrictionType.NONE)) {
605             // anonymous everything, disable all controls
606             usersPalette.setEnabled(false);
607             teamsPalette.setEnabled(false);
70e3d1 608             verifyCommitter.setEnabled(false);
092f0a 609         } else {
JM 610             // authenticated something
611             // enable authorization controls
70e3d1 612             verifyCommitter.setEnabled(true);
699e71 613
092f0a 614             boolean allowFineGrainedControls = repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED);
JM 615             usersPalette.setEnabled(allowFineGrainedControls);
70e3d1 616             teamsPalette.setEnabled(allowFineGrainedControls);
092f0a 617         }
699e71 618
85b5d7 619         //
JM 620         // ACCESS POLICY PANEL (GENERAL)
621         //
6a437e 622         AjaxFormChoiceComponentUpdatingBehavior callback = new AjaxFormChoiceComponentUpdatingBehavior() {
699e71 623
092f0a 624             private static final long serialVersionUID = 1L;
f5d0ad 625
699e71 626             @Override
092f0a 627             protected void onUpdate(AjaxRequestTarget target) {
6a437e 628                 accessPolicyPanel.updateModel(repositoryModel);
JM 629
092f0a 630                 boolean allowAuthorizationControl = repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE);
70e3d1 631                 verifyCommitter.setEnabled(allowAuthorizationControl);
699e71 632
092f0a 633                 boolean allowFineGrainedControls = allowAuthorizationControl && repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED);
JM 634                 usersPalette.setEnabled(allowFineGrainedControls);
635                 teamsPalette.setEnabled(allowFineGrainedControls);
699e71 636
092f0a 637                 if (allowFineGrainedControls) {
JM 638                     repositoryModel.authorizationControl = AuthorizationControl.NAMED;
639                 }
699e71 640
70e3d1 641                 target.addComponent(verifyCommitter);
092f0a 642                 target.addComponent(usersPalette);
JM 643                 target.addComponent(teamsPalette);
644             }
6a437e 645         };
699e71 646
6a437e 647         accessPolicyPanel = new AccessPolicyPanel("accessPolicyPanel", repositoryModel, callback);
JM 648         form.add(accessPolicyPanel);
699e71 649
JM 650
85b5d7 651         //
JM 652         // FORM CONTROLS
653         //
719798 654         form.add(new Button("save"));
JM 655         Button cancel = new Button("cancel") {
331fbc 656             private static final long serialVersionUID = 1L;
JM 657
658             @Override
659             public void onSubmit() {
e86fd1 660                 if (isCreate) {
JM 661                     setResponsePage(RepositoriesPage.class);
662                 } else {
663                     setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryModel.name));
664                 }
88598b 665             }
JM 666         };
667         cancel.setDefaultFormProcessing(false);
668         form.add(cancel);
669
b4ed66 670         // the user can delete if deletions are allowed AND the user is an admin or the personal owner
JM 671         // assigned ownership is not sufficient to allow deletion
672         boolean canDelete = !isCreate && app().repositories().canDelete(repositoryModel)
673                 && (user.canAdmin() || user.isMyPersonalRepository(repositoryModel.name));
674
675         Link<Void> delete = new Link<Void>("delete") {
676
677             private static final long serialVersionUID = 1L;
678
679             @Override
680             public void onClick() {
681                 RepositoryModel latestModel = app().repositories().getRepositoryModel(repositoryModel.name);
682                 boolean canDelete = app().repositories().canDelete(latestModel);
683                 if (canDelete) {
c599bd 684                     if (app().gitblit().deleteRepositoryModel(latestModel)) {
b4ed66 685                         info(MessageFormat.format(getString("gb.repositoryDeleted"), latestModel));
0047fb 686                         if (latestModel.isPersonalRepository()) {
JM 687                             // redirect to user's profile page
688                             String prefix = app().settings().getString(Keys.git.userRepositoryPrefix, "~");
689                             String username = latestModel.projectPath.substring(prefix.length());
690                             setResponsePage(UserPage.class, WicketUtils.newUsernameParameter(username));
691                         } else {
692                             // redirect to server repositories page
693                             setResponsePage(RepositoriesPage.class);
694                         }
b4ed66 695                     } else {
JM 696                         error(MessageFormat.format(getString("gb.repositoryDeleteFailed"), latestModel));
697                     }
698                 } else {
699                     error(MessageFormat.format(getString("gb.repositoryDeleteFailed"), latestModel));
700                 }
701             }
702         };
703
704         if (canDelete) {
705             delete.add(new JavascriptEventConfirmation("onclick", MessageFormat.format(
706                 getString("gb.deleteRepository"), repositoryModel)));
707         }
708         form.add(delete.setVisible(canDelete));
709
f5d0ad 710         add(form);
JM 711     }
2a7306 712
00afd7 713     /**
JM 714      * Unfortunately must repeat part of AuthorizaitonStrategy here because that
715      * mechanism does not take PageParameters into consideration, only page
716      * instantiation.
699e71 717      *
00afd7 718      * Repository Owners should be able to edit their repository.
JM 719      */
720     private void checkPermissions(RepositoryModel model) {
99d0d4 721         boolean authenticateAdmin = app().settings().getBoolean(Keys.web.authenticateAdminPages, true);
JM 722         boolean allowAdmin = app().settings().getBoolean(Keys.web.allowAdministration, true);
00afd7 723
JM 724         GitBlitWebSession session = GitBlitWebSession.get();
725         UserModel user = session.getUser();
726
727         if (allowAdmin) {
728             if (authenticateAdmin) {
729                 if (user == null) {
730                     // No Login Available
017749 731                     error(getString("gb.errorAdminLoginRequired"), true);
00afd7 732                 }
JM 733                 if (isCreate) {
734                     // Create Repository
7f7051 735                     if (!user.canCreate() && !user.canAdmin()) {
6662e3 736                         // Only administrators or permitted users may create
017749 737                         error(getString("gb.errorOnlyAdminMayCreateRepository"), true);
00afd7 738                     }
JM 739                 } else {
740                     // Edit Repository
7f7051 741                     if (user.canAdmin()) {
00afd7 742                         // Admins can edit everything
8a2e9c 743                         isAdmin = true;
00afd7 744                         return;
JM 745                     } else {
661db6 746                         if (!model.isOwner(user.username)) {
JM 747                             // User is not an Admin nor Owner
748                             error(getString("gb.errorOnlyAdminOrOwnerMayEditRepository"), true);
00afd7 749                         }
2a7306 750                     }
00afd7 751                 }
JM 752             }
753         } else {
754             // No Administration Permitted
017749 755             error(getString("gb.errorAdministrationDisabled"), true);
912938 756         }
85b5d7 757     }
JM 758
759
831469 760     private class FederationTypeRenderer implements IChoiceRenderer<FederationStrategy> {
JM 761
762         private static final long serialVersionUID = 1L;
763
764         private final Map<FederationStrategy, String> map;
765
766         public FederationTypeRenderer() {
767             map = getFederationTypes();
768         }
769
770         @Override
771         public String getDisplayValue(FederationStrategy type) {
772             return map.get(type);
773         }
774
775         @Override
776         public String getIdValue(FederationStrategy type, int index) {
092f0a 777             return Integer.toString(index);
JM 778         }
779     }
699e71 780
e26d93 781     private class GCPeriodRenderer implements IChoiceRenderer<Integer> {
JM 782
783         private static final long serialVersionUID = 1L;
784
785         public GCPeriodRenderer() {
786         }
787
788         @Override
789         public String getDisplayValue(Integer value) {
790             if (value == 1) {
791                 return getString("gb.duration.oneDay");
792             } else {
793                 return MessageFormat.format(getString("gb.duration.days"), value);
794             }
795         }
796
797         @Override
798         public String getIdValue(Integer value, int index) {
799             return Integer.toString(index);
800         }
801     }
699e71 802
8295dd 803     private class MaxActivityCommitsRenderer implements IChoiceRenderer<Integer> {
JM 804
805         private static final long serialVersionUID = 1L;
806
807         public MaxActivityCommitsRenderer() {
808         }
809
810         @Override
811         public String getDisplayValue(Integer value) {
dab13a 812             if (value == -1) {
JM 813                 return getString("gb.excludeFromActivity");
814             } else if (value == 0) {
8295dd 815                 return getString("gb.noMaximum");
JM 816             } else {
817                 return value + " " + getString("gb.commits");
818             }
819         }
820
821         @Override
822         public String getIdValue(Integer value, int index) {
823             return Integer.toString(index);
824         }
825     }
f5d0ad 826 }