You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

EditRepositoryPage.java 19KB

пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 12 година
пре 13 година
пре 12 година
пре 12 година
пре 12 година
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /*
  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. */
  16. package com.gitblit.wicket.pages;
  17. import java.text.MessageFormat;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Collections;
  21. import java.util.HashSet;
  22. import java.util.Iterator;
  23. import java.util.LinkedHashMap;
  24. import java.util.List;
  25. import java.util.Map;
  26. import java.util.Set;
  27. import org.apache.wicket.PageParameters;
  28. import org.apache.wicket.behavior.SimpleAttributeModifier;
  29. import org.apache.wicket.extensions.markup.html.form.palette.Palette;
  30. import org.apache.wicket.markup.html.WebMarkupContainer;
  31. import org.apache.wicket.markup.html.basic.Label;
  32. import org.apache.wicket.markup.html.form.Button;
  33. import org.apache.wicket.markup.html.form.CheckBox;
  34. import org.apache.wicket.markup.html.form.DropDownChoice;
  35. import org.apache.wicket.markup.html.form.Form;
  36. import org.apache.wicket.markup.html.form.IChoiceRenderer;
  37. import org.apache.wicket.markup.html.form.Radio;
  38. import org.apache.wicket.markup.html.form.RadioGroup;
  39. import org.apache.wicket.markup.html.form.TextField;
  40. import org.apache.wicket.markup.html.list.ListItem;
  41. import org.apache.wicket.markup.html.list.ListView;
  42. import org.apache.wicket.model.CompoundPropertyModel;
  43. import org.apache.wicket.model.IModel;
  44. import org.apache.wicket.model.Model;
  45. import org.apache.wicket.model.util.CollectionModel;
  46. import org.apache.wicket.model.util.ListModel;
  47. import com.gitblit.Constants;
  48. import com.gitblit.Constants.AccessRestrictionType;
  49. import com.gitblit.Constants.AuthorizationControl;
  50. import com.gitblit.Constants.FederationStrategy;
  51. import com.gitblit.GitBlit;
  52. import com.gitblit.GitBlitException;
  53. import com.gitblit.Keys;
  54. import com.gitblit.models.RepositoryModel;
  55. import com.gitblit.models.UserModel;
  56. import com.gitblit.utils.ArrayUtils;
  57. import com.gitblit.utils.StringUtils;
  58. import com.gitblit.wicket.GitBlitWebSession;
  59. import com.gitblit.wicket.StringChoiceRenderer;
  60. import com.gitblit.wicket.WicketUtils;
  61. import com.gitblit.wicket.panels.BulletListPanel;
  62. public class EditRepositoryPage extends RootSubPage {
  63. private final boolean isCreate;
  64. private boolean isAdmin;
  65. private IModel<String> mailingLists;
  66. public EditRepositoryPage() {
  67. // create constructor
  68. super();
  69. isCreate = true;
  70. RepositoryModel model = new RepositoryModel();
  71. String restriction = GitBlit.getString(Keys.git.defaultAccessRestriction, null);
  72. model.accessRestriction = AccessRestrictionType.fromName(restriction);
  73. String authorization = GitBlit.getString(Keys.git.defaultAuthorizationControl, null);
  74. model.authorizationControl = AuthorizationControl.fromName(authorization);
  75. setupPage(model);
  76. }
  77. public EditRepositoryPage(PageParameters params) {
  78. // edit constructor
  79. super(params);
  80. isCreate = false;
  81. String name = WicketUtils.getRepositoryName(params);
  82. RepositoryModel model = GitBlit.self().getRepositoryModel(name);
  83. setupPage(model);
  84. }
  85. protected void setupPage(final RepositoryModel repositoryModel) {
  86. // ensure this user can create or edit this repository
  87. checkPermissions(repositoryModel);
  88. List<String> indexedBranches = new ArrayList<String>();
  89. List<String> federationSets = new ArrayList<String>();
  90. List<String> repositoryUsers = new ArrayList<String>();
  91. List<String> repositoryTeams = new ArrayList<String>();
  92. List<String> preReceiveScripts = new ArrayList<String>();
  93. List<String> postReceiveScripts = new ArrayList<String>();
  94. if (isCreate) {
  95. super.setupPage(getString("gb.newRepository"), "");
  96. } else {
  97. super.setupPage(getString("gb.edit"), repositoryModel.name);
  98. if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {
  99. repositoryUsers.addAll(GitBlit.self().getRepositoryUsers(repositoryModel));
  100. repositoryTeams.addAll(GitBlit.self().getRepositoryTeams(repositoryModel));
  101. Collections.sort(repositoryUsers);
  102. }
  103. federationSets.addAll(repositoryModel.federationSets);
  104. if (!ArrayUtils.isEmpty(repositoryModel.indexedBranches)) {
  105. indexedBranches.addAll(repositoryModel.indexedBranches);
  106. }
  107. }
  108. final String oldName = repositoryModel.name;
  109. // users palette
  110. final Palette<String> usersPalette = new Palette<String>("users", new ListModel<String>(
  111. repositoryUsers), new CollectionModel<String>(GitBlit.self().getAllUsernames()),
  112. new StringChoiceRenderer(), 10, false);
  113. // teams palette
  114. final Palette<String> teamsPalette = new Palette<String>("teams", new ListModel<String>(
  115. repositoryTeams), new CollectionModel<String>(GitBlit.self().getAllTeamnames()),
  116. new StringChoiceRenderer(), 8, false);
  117. // indexed local branches palette
  118. List<String> allLocalBranches = new ArrayList<String>();
  119. allLocalBranches.add(Constants.DEFAULT_BRANCH);
  120. allLocalBranches.addAll(repositoryModel.getLocalBranches());
  121. boolean luceneEnabled = GitBlit.getBoolean(Keys.web.allowLuceneIndexing, true);
  122. final Palette<String> indexedBranchesPalette = new Palette<String>("indexedBranches", new ListModel<String>(
  123. indexedBranches), new CollectionModel<String>(allLocalBranches),
  124. new StringChoiceRenderer(), 8, false);
  125. indexedBranchesPalette.setEnabled(luceneEnabled);
  126. // federation sets palette
  127. List<String> sets = GitBlit.getStrings(Keys.federation.sets);
  128. final Palette<String> federationSetsPalette = new Palette<String>("federationSets",
  129. new ListModel<String>(federationSets), new CollectionModel<String>(sets),
  130. new StringChoiceRenderer(), 8, false);
  131. // pre-receive palette
  132. if (!ArrayUtils.isEmpty(repositoryModel.preReceiveScripts)) {
  133. preReceiveScripts.addAll(repositoryModel.preReceiveScripts);
  134. }
  135. final Palette<String> preReceivePalette = new Palette<String>("preReceiveScripts",
  136. new ListModel<String>(preReceiveScripts), new CollectionModel<String>(GitBlit
  137. .self().getPreReceiveScriptsUnused(repositoryModel)),
  138. new StringChoiceRenderer(), 12, true);
  139. // post-receive palette
  140. if (!ArrayUtils.isEmpty(repositoryModel.postReceiveScripts)) {
  141. postReceiveScripts.addAll(repositoryModel.postReceiveScripts);
  142. }
  143. final Palette<String> postReceivePalette = new Palette<String>("postReceiveScripts",
  144. new ListModel<String>(postReceiveScripts), new CollectionModel<String>(GitBlit
  145. .self().getPostReceiveScriptsUnused(repositoryModel)),
  146. new StringChoiceRenderer(), 12, true);
  147. // custom fields
  148. final Map<String, String> customFieldsMap = GitBlit.getMap(Keys.groovy.customFields);
  149. List<String> customKeys = new ArrayList<String>(customFieldsMap.keySet());
  150. final ListView<String> customFieldsListView = new ListView<String>("customFieldsListView", customKeys) {
  151. private static final long serialVersionUID = 1L;
  152. @Override
  153. protected void populateItem(ListItem<String> item) {
  154. String key = item.getModelObject();
  155. item.add(new Label("customFieldLabel", customFieldsMap.get(key)));
  156. String value = "";
  157. if (repositoryModel.customFields != null && repositoryModel.customFields.containsKey(key)) {
  158. value = repositoryModel.customFields.get(key);
  159. }
  160. TextField<String> field = new TextField<String>("customFieldValue", new Model<String>(value));
  161. item.add(field);
  162. }
  163. };
  164. customFieldsListView.setReuseItems(true);
  165. CompoundPropertyModel<RepositoryModel> model = new CompoundPropertyModel<RepositoryModel>(
  166. repositoryModel);
  167. Form<RepositoryModel> form = new Form<RepositoryModel>("editForm", model) {
  168. private static final long serialVersionUID = 1L;
  169. @Override
  170. protected void onSubmit() {
  171. try {
  172. // confirm a repository name was entered
  173. if (StringUtils.isEmpty(repositoryModel.name)) {
  174. error(getString("gb.pleaseSetRepositoryName"));
  175. return;
  176. }
  177. // automatically convert backslashes to forward slashes
  178. repositoryModel.name = repositoryModel.name.replace('\\', '/');
  179. // Automatically replace // with /
  180. repositoryModel.name = repositoryModel.name.replace("//", "/");
  181. // prohibit folder paths
  182. if (repositoryModel.name.startsWith("/")) {
  183. error(getString("gb.illegalLeadingSlash"));
  184. return;
  185. }
  186. if (repositoryModel.name.startsWith("../")) {
  187. error(getString("gb.illegalRelativeSlash"));
  188. return;
  189. }
  190. if (repositoryModel.name.contains("/../")) {
  191. error(getString("gb.illegalRelativeSlash"));
  192. return;
  193. }
  194. if (repositoryModel.name.endsWith("/")) {
  195. repositoryModel.name = repositoryModel.name.substring(0, repositoryModel.name.length() - 1);
  196. }
  197. // confirm valid characters in repository name
  198. Character c = StringUtils.findInvalidCharacter(repositoryModel.name);
  199. if (c != null) {
  200. error(MessageFormat.format(getString("gb.illegalCharacterRepositoryName"),
  201. c));
  202. return;
  203. }
  204. // confirm access restriction selection
  205. if (repositoryModel.accessRestriction == null) {
  206. error(getString("gb.selectAccessRestriction"));
  207. return;
  208. }
  209. // confirm federation strategy selection
  210. if (repositoryModel.federationStrategy == null) {
  211. error(getString("gb.selectFederationStrategy"));
  212. return;
  213. }
  214. // save federation set preferences
  215. if (repositoryModel.federationStrategy.exceeds(FederationStrategy.EXCLUDE)) {
  216. repositoryModel.federationSets.clear();
  217. Iterator<String> sets = federationSetsPalette.getSelectedChoices();
  218. while (sets.hasNext()) {
  219. repositoryModel.federationSets.add(sets.next());
  220. }
  221. }
  222. // set mailing lists
  223. String ml = mailingLists.getObject();
  224. if (!StringUtils.isEmpty(ml)) {
  225. Set<String> list = new HashSet<String>();
  226. for (String address : ml.split("(,|\\s)")) {
  227. if (StringUtils.isEmpty(address)) {
  228. continue;
  229. }
  230. list.add(address.toLowerCase());
  231. }
  232. repositoryModel.mailingLists = new ArrayList<String>(list);
  233. }
  234. // indexed branches
  235. List<String> indexedBranches = new ArrayList<String>();
  236. Iterator<String> branches = indexedBranchesPalette.getSelectedChoices();
  237. while (branches.hasNext()) {
  238. indexedBranches.add(branches.next());
  239. }
  240. repositoryModel.indexedBranches = indexedBranches;
  241. // pre-receive scripts
  242. List<String> preReceiveScripts = new ArrayList<String>();
  243. Iterator<String> pres = preReceivePalette.getSelectedChoices();
  244. while (pres.hasNext()) {
  245. preReceiveScripts.add(pres.next());
  246. }
  247. repositoryModel.preReceiveScripts = preReceiveScripts;
  248. // post-receive scripts
  249. List<String> postReceiveScripts = new ArrayList<String>();
  250. Iterator<String> post = postReceivePalette.getSelectedChoices();
  251. while (post.hasNext()) {
  252. postReceiveScripts.add(post.next());
  253. }
  254. repositoryModel.postReceiveScripts = postReceiveScripts;
  255. // custom fields
  256. repositoryModel.customFields = new LinkedHashMap<String, String>();
  257. for (int i = 0; i < customFieldsListView.size(); i++) {
  258. ListItem<String> child = (ListItem<String>) customFieldsListView.get(i);
  259. String key = child.getModelObject();
  260. TextField<String> field = (TextField<String>) child.get("customFieldValue");
  261. String value = field.getValue();
  262. repositoryModel.customFields.put(key, value);
  263. }
  264. // save the repository
  265. GitBlit.self().updateRepositoryModel(oldName, repositoryModel, isCreate);
  266. // repository access
  267. if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {
  268. // save the user access list
  269. Iterator<String> users = usersPalette.getSelectedChoices();
  270. List<String> repositoryUsers = new ArrayList<String>();
  271. while (users.hasNext()) {
  272. repositoryUsers.add(users.next());
  273. }
  274. // ensure the owner is added to the user list
  275. if (repositoryModel.owner != null
  276. && !repositoryUsers.contains(repositoryModel.owner)) {
  277. repositoryUsers.add(repositoryModel.owner);
  278. }
  279. GitBlit.self().setRepositoryUsers(repositoryModel, repositoryUsers);
  280. // save the team access list
  281. Iterator<String> teams = teamsPalette.getSelectedChoices();
  282. List<String> repositoryTeams = new ArrayList<String>();
  283. while (teams.hasNext()) {
  284. repositoryTeams.add(teams.next());
  285. }
  286. GitBlit.self().setRepositoryTeams(repositoryModel, repositoryTeams);
  287. }
  288. } catch (GitBlitException e) {
  289. error(e.getMessage());
  290. return;
  291. }
  292. setRedirect(false);
  293. setResponsePage(RepositoriesPage.class);
  294. }
  295. };
  296. // do not let the browser pre-populate these fields
  297. form.add(new SimpleAttributeModifier("autocomplete", "off"));
  298. // field names reflective match RepositoryModel fields
  299. form.add(new TextField<String>("name").setEnabled(isCreate || isAdmin));
  300. form.add(new TextField<String>("description"));
  301. form.add(new DropDownChoice<String>("owner", GitBlit.self().getAllUsernames())
  302. .setEnabled(GitBlitWebSession.get().canAdmin()));
  303. form.add(new CheckBox("allowForks"));
  304. form.add(new DropDownChoice<AccessRestrictionType>("accessRestriction", Arrays
  305. .asList(AccessRestrictionType.values()), new AccessRestrictionRenderer()));
  306. form.add(new CheckBox("isFrozen"));
  307. // TODO enable origin definition
  308. form.add(new TextField<String>("origin").setEnabled(false/* isCreate */));
  309. // allow relinking HEAD to a branch or tag other than master on edit repository
  310. List<String> availableRefs = new ArrayList<String>();
  311. if (!ArrayUtils.isEmpty(repositoryModel.availableRefs)) {
  312. availableRefs.addAll(repositoryModel.availableRefs);
  313. }
  314. form.add(new DropDownChoice<String>("HEAD", availableRefs).setEnabled(availableRefs.size() > 0));
  315. // federation strategies - remove ORIGIN choice if this repository has
  316. // no origin.
  317. List<FederationStrategy> federationStrategies = new ArrayList<FederationStrategy>(
  318. Arrays.asList(FederationStrategy.values()));
  319. if (StringUtils.isEmpty(repositoryModel.origin)) {
  320. federationStrategies.remove(FederationStrategy.FEDERATE_ORIGIN);
  321. }
  322. form.add(new DropDownChoice<FederationStrategy>("federationStrategy", federationStrategies,
  323. new FederationTypeRenderer()));
  324. form.add(new CheckBox("useTickets"));
  325. form.add(new CheckBox("useDocs"));
  326. form.add(new CheckBox("showRemoteBranches"));
  327. form.add(new CheckBox("showReadme"));
  328. form.add(new CheckBox("skipSizeCalculation"));
  329. form.add(new CheckBox("skipSummaryMetrics"));
  330. mailingLists = new Model<String>(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? ""
  331. : StringUtils.flattenStrings(repositoryModel.mailingLists, " "));
  332. form.add(new TextField<String>("mailingLists", mailingLists));
  333. form.add(indexedBranchesPalette);
  334. RadioGroup<AuthorizationControl> group = new RadioGroup<AuthorizationControl>("authorizationControl");
  335. Radio<AuthorizationControl> allowAuthenticated = new Radio<AuthorizationControl>("allowAuthenticated", new Model<AuthorizationControl>(AuthorizationControl.AUTHENTICATED));
  336. Radio<AuthorizationControl> allowNamed = new Radio<AuthorizationControl>("allowNamed", new Model<AuthorizationControl>(AuthorizationControl.NAMED));
  337. group.add(allowAuthenticated);
  338. group.add(allowNamed);
  339. form.add(group);
  340. form.add(usersPalette);
  341. form.add(teamsPalette);
  342. form.add(federationSetsPalette);
  343. form.add(preReceivePalette);
  344. form.add(new BulletListPanel("inheritedPreReceive", getString("gb.inherited"), GitBlit.self()
  345. .getPreReceiveScriptsInherited(repositoryModel)));
  346. form.add(postReceivePalette);
  347. form.add(new BulletListPanel("inheritedPostReceive", getString("gb.inherited"), GitBlit.self()
  348. .getPostReceiveScriptsInherited(repositoryModel)));
  349. WebMarkupContainer customFieldsSection = new WebMarkupContainer("customFieldsSection");
  350. customFieldsSection.add(customFieldsListView);
  351. form.add(customFieldsSection.setVisible(!GitBlit.getString(Keys.groovy.customFields, "").isEmpty()));
  352. form.add(new Button("save"));
  353. Button cancel = new Button("cancel") {
  354. private static final long serialVersionUID = 1L;
  355. @Override
  356. public void onSubmit() {
  357. setResponsePage(RepositoriesPage.class);
  358. }
  359. };
  360. cancel.setDefaultFormProcessing(false);
  361. form.add(cancel);
  362. add(form);
  363. }
  364. /**
  365. * Unfortunately must repeat part of AuthorizaitonStrategy here because that
  366. * mechanism does not take PageParameters into consideration, only page
  367. * instantiation.
  368. *
  369. * Repository Owners should be able to edit their repository.
  370. */
  371. private void checkPermissions(RepositoryModel model) {
  372. boolean authenticateAdmin = GitBlit.getBoolean(Keys.web.authenticateAdminPages, true);
  373. boolean allowAdmin = GitBlit.getBoolean(Keys.web.allowAdministration, true);
  374. GitBlitWebSession session = GitBlitWebSession.get();
  375. UserModel user = session.getUser();
  376. if (allowAdmin) {
  377. if (authenticateAdmin) {
  378. if (user == null) {
  379. // No Login Available
  380. error(getString("gb.errorAdminLoginRequired"), true);
  381. }
  382. if (isCreate) {
  383. // Create Repository
  384. if (!user.canAdmin) {
  385. // Only Administrators May Create
  386. error(getString("gb.errorOnlyAdminMayCreateRepository"), true);
  387. }
  388. } else {
  389. // Edit Repository
  390. if (user.canAdmin) {
  391. // Admins can edit everything
  392. isAdmin = true;
  393. return;
  394. } else {
  395. if (!model.owner.equalsIgnoreCase(user.username)) {
  396. // User is not an Admin nor Owner
  397. error(getString("gb.errorOnlyAdminOrOwnerMayEditRepository"), true);
  398. }
  399. }
  400. }
  401. }
  402. } else {
  403. // No Administration Permitted
  404. error(getString("gb.errorAdministrationDisabled"), true);
  405. }
  406. }
  407. private class AccessRestrictionRenderer implements IChoiceRenderer<AccessRestrictionType> {
  408. private static final long serialVersionUID = 1L;
  409. private final Map<AccessRestrictionType, String> map;
  410. public AccessRestrictionRenderer() {
  411. map = getAccessRestrictions();
  412. }
  413. @Override
  414. public String getDisplayValue(AccessRestrictionType type) {
  415. return map.get(type);
  416. }
  417. @Override
  418. public String getIdValue(AccessRestrictionType type, int index) {
  419. return Integer.toString(index);
  420. }
  421. }
  422. private class FederationTypeRenderer implements IChoiceRenderer<FederationStrategy> {
  423. private static final long serialVersionUID = 1L;
  424. private final Map<FederationStrategy, String> map;
  425. public FederationTypeRenderer() {
  426. map = getFederationTypes();
  427. }
  428. @Override
  429. public String getDisplayValue(FederationStrategy type) {
  430. return map.get(type);
  431. }
  432. @Override
  433. public String getIdValue(FederationStrategy type, int index) {
  434. return Integer.toString(index);
  435. }
  436. }
  437. }