選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

RegistrantPermissionsPanel.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /*
  2. * Copyright 2012 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.panels;
  17. import java.text.MessageFormat;
  18. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.Collections;
  21. import java.util.Iterator;
  22. import java.util.List;
  23. import java.util.Map;
  24. import org.apache.wicket.Component;
  25. import org.apache.wicket.ajax.AjaxRequestTarget;
  26. import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
  27. import org.apache.wicket.ajax.markup.html.form.AjaxButton;
  28. import org.apache.wicket.markup.html.basic.Label;
  29. import org.apache.wicket.markup.html.form.DropDownChoice;
  30. import org.apache.wicket.markup.html.form.Form;
  31. import org.apache.wicket.markup.html.form.IChoiceRenderer;
  32. import org.apache.wicket.markup.html.panel.Fragment;
  33. import org.apache.wicket.markup.repeater.Item;
  34. import org.apache.wicket.markup.repeater.OddEvenItem;
  35. import org.apache.wicket.markup.repeater.RefreshingView;
  36. import org.apache.wicket.markup.repeater.util.ModelIteratorAdapter;
  37. import org.apache.wicket.model.CompoundPropertyModel;
  38. import org.apache.wicket.model.IModel;
  39. import org.eclipse.jgit.lib.PersonIdent;
  40. import com.gitblit.Constants.AccessPermission;
  41. import com.gitblit.Constants.PermissionType;
  42. import com.gitblit.Constants.RegistrantType;
  43. import com.gitblit.GitBlit;
  44. import com.gitblit.models.RegistrantAccessPermission;
  45. import com.gitblit.models.UserModel;
  46. import com.gitblit.utils.DeepCopier;
  47. import com.gitblit.utils.StringUtils;
  48. import com.gitblit.wicket.WicketUtils;
  49. /**
  50. * Allows user to manipulate registrant access permissions.
  51. *
  52. * @author James Moger
  53. *
  54. */
  55. public class RegistrantPermissionsPanel extends BasePanel {
  56. private static final long serialVersionUID = 1L;
  57. public enum Show {
  58. specified, mutable, effective;
  59. public boolean show(RegistrantAccessPermission ap) {
  60. switch (this) {
  61. case specified:
  62. return ap.mutable || ap.isOwner();
  63. case mutable:
  64. return ap.mutable;
  65. case effective:
  66. return true;
  67. default:
  68. return true;
  69. }
  70. }
  71. }
  72. private Show activeState = Show.mutable;
  73. public RegistrantPermissionsPanel(String wicketId, RegistrantType registrantType, List<String> allRegistrants, final List<RegistrantAccessPermission> permissions, final Map<AccessPermission, String> translations) {
  74. super(wicketId);
  75. setOutputMarkupId(true);
  76. /*
  77. * Permission view toggle buttons
  78. */
  79. Form<Void> permissionToggleForm = new Form<Void>("permissionToggleForm");
  80. permissionToggleForm.add(new ShowStateButton("showSpecified", Show.specified));
  81. permissionToggleForm.add(new ShowStateButton("showMutable", Show.mutable));
  82. permissionToggleForm.add(new ShowStateButton("showEffective", Show.effective));
  83. add(permissionToggleForm);
  84. /*
  85. * Permission repeating display
  86. */
  87. RefreshingView<RegistrantAccessPermission> dataView = new RefreshingView<RegistrantAccessPermission>("permissionRow") {
  88. private static final long serialVersionUID = 1L;
  89. @Override
  90. protected Iterator<IModel<RegistrantAccessPermission>> getItemModels() {
  91. // the iterator returns RepositoryPermission objects, but we need it to
  92. // return models
  93. return new ModelIteratorAdapter<RegistrantAccessPermission>(permissions.iterator()) {
  94. @Override
  95. protected IModel<RegistrantAccessPermission> model(RegistrantAccessPermission permission) {
  96. return new CompoundPropertyModel<RegistrantAccessPermission>(permission);
  97. }
  98. };
  99. }
  100. @Override
  101. protected Item<RegistrantAccessPermission> newItem(String id, int index, IModel<RegistrantAccessPermission> model) {
  102. // this item sets markup class attribute to either 'odd' or
  103. // 'even' for decoration
  104. return new OddEvenItem<RegistrantAccessPermission>(id, index, model);
  105. }
  106. @Override
  107. public void populateItem(final Item<RegistrantAccessPermission> item) {
  108. final RegistrantAccessPermission entry = item.getModelObject();
  109. if (RegistrantType.REPOSITORY.equals(entry.registrantType)) {
  110. String repoName = StringUtils.stripDotGit(entry.registrant);
  111. if (!entry.isMissing() && StringUtils.findInvalidCharacter(repoName) == null) {
  112. // repository, strip .git and show swatch
  113. Fragment repositoryFragment = new Fragment("registrant", "repositoryRegistrant", RegistrantPermissionsPanel.this);
  114. Component swatch = new Label("repositorySwatch", "&nbsp;").setEscapeModelStrings(false);
  115. WicketUtils.setCssBackground(swatch, entry.toString());
  116. repositoryFragment.add(swatch);
  117. Label registrant = new Label("repositoryName", repoName);
  118. repositoryFragment.add(registrant);
  119. item.add(repositoryFragment);
  120. } else {
  121. // regex or missing
  122. Label label = new Label("registrant", entry.registrant);
  123. WicketUtils.setCssStyle(label, "font-weight: bold;");
  124. item.add(label);
  125. }
  126. } else if (RegistrantType.USER.equals(entry.registrantType)) {
  127. // user
  128. PersonIdent ident = new PersonIdent(entry.registrant, "");
  129. UserModel user = GitBlit.self().getUserModel(entry.registrant);
  130. if (user != null) {
  131. ident = new PersonIdent(user.getDisplayName(), user.emailAddress == null ? user.getDisplayName() : user.emailAddress);
  132. }
  133. Fragment userFragment = new Fragment("registrant", "userRegistrant", RegistrantPermissionsPanel.this);
  134. userFragment.add(new GravatarImage("userAvatar", ident, 20, false));
  135. userFragment.add(new Label("userName", entry.registrant));
  136. item.add(userFragment);
  137. } else {
  138. // team
  139. Fragment teamFragment = new Fragment("registrant", "teamRegistrant", RegistrantPermissionsPanel.this);
  140. teamFragment.add(new Label("teamName", entry.registrant));
  141. item.add(teamFragment);
  142. }
  143. switch (entry.permissionType) {
  144. case ADMINISTRATOR:
  145. Label administrator = new Label("pType", entry.source == null ? getString("gb.administrator") : entry.source);
  146. WicketUtils.setHtmlTooltip(administrator, getString("gb.administratorPermission"));
  147. WicketUtils.setCssClass(administrator, "label label-inverse");
  148. item.add(administrator);
  149. break;
  150. case OWNER:
  151. Label owner = new Label("pType", getString("gb.owner"));
  152. WicketUtils.setHtmlTooltip(owner, getString("gb.ownerPermission"));
  153. WicketUtils.setCssClass(owner, "label label-info");
  154. item.add(owner);
  155. break;
  156. case TEAM:
  157. Label team = new Label("pType", entry.source == null ? getString("gb.team") : entry.source);
  158. WicketUtils.setHtmlTooltip(team, MessageFormat.format(getString("gb.teamPermission"), entry.source));
  159. WicketUtils.setCssClass(team, "label label-success");
  160. item.add(team);
  161. break;
  162. case REGEX:
  163. Label regex = new Label("pType", "regex");
  164. if (!StringUtils.isEmpty(entry.source)) {
  165. WicketUtils.setHtmlTooltip(regex, MessageFormat.format(getString("gb.regexPermission"), entry.source));
  166. }
  167. WicketUtils.setCssClass(regex, "label");
  168. item.add(regex);
  169. break;
  170. default:
  171. if (entry.isMissing()) {
  172. // repository is missing, this permission will be removed on save
  173. Label missing = new Label("pType", getString("gb.missing"));
  174. WicketUtils.setCssClass(missing, "label label-important");
  175. WicketUtils.setHtmlTooltip(missing, getString("gb.missingPermission"));
  176. item.add(missing);
  177. } else {
  178. // standard permission
  179. item.add(new Label("pType", "").setVisible(false));
  180. }
  181. break;
  182. }
  183. item.setVisible(activeState.show(entry));
  184. // use ajax to get immediate update of permission level change
  185. // otherwise we can lose it if they change levels and then add
  186. // a new repository permission
  187. final DropDownChoice<AccessPermission> permissionChoice = new DropDownChoice<AccessPermission>(
  188. "permission", Arrays.asList(AccessPermission.values()), new AccessPermissionRenderer(translations));
  189. // only allow changing an explicitly defined permission
  190. // this is designed to prevent changing a regex permission in
  191. // a repository
  192. permissionChoice.setEnabled(entry.mutable);
  193. permissionChoice.setOutputMarkupId(true);
  194. if (entry.mutable) {
  195. permissionChoice.add(new AjaxFormComponentUpdatingBehavior("onchange") {
  196. private static final long serialVersionUID = 1L;
  197. @Override
  198. protected void onUpdate(AjaxRequestTarget target) {
  199. target.addComponent(permissionChoice);
  200. }
  201. });
  202. }
  203. item.add(permissionChoice);
  204. }
  205. };
  206. add(dataView);
  207. setOutputMarkupId(true);
  208. // filter out registrants we already have permissions for
  209. final List<String> registrants = new ArrayList<String>(allRegistrants);
  210. for (RegistrantAccessPermission rp : permissions) {
  211. if (rp.mutable) {
  212. // remove editable duplicates
  213. // this allows for specifying an explicit permission
  214. registrants.remove(rp.registrant);
  215. } else if (rp.isAdmin()) {
  216. // administrators can not have their permission changed
  217. registrants.remove(rp.registrant);
  218. } else if (rp.isOwner()) {
  219. // owners can not have their permission changed
  220. registrants.remove(rp.registrant);
  221. }
  222. }
  223. /*
  224. * Add permission form
  225. */
  226. IModel<RegistrantAccessPermission> addPermissionModel = new CompoundPropertyModel<RegistrantAccessPermission>(new RegistrantAccessPermission(registrantType));
  227. Form<RegistrantAccessPermission> addPermissionForm = new Form<RegistrantAccessPermission>("addPermissionForm", addPermissionModel);
  228. addPermissionForm.add(new DropDownChoice<String>("registrant", registrants));
  229. addPermissionForm.add(new DropDownChoice<AccessPermission>("permission", Arrays
  230. .asList(AccessPermission.NEWPERMISSIONS), new AccessPermissionRenderer(translations)));
  231. AjaxButton button = new AjaxButton("addPermissionButton", addPermissionForm) {
  232. private static final long serialVersionUID = 1L;
  233. @Override
  234. protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
  235. // add permission to our list
  236. RegistrantAccessPermission rp = (RegistrantAccessPermission) form.getModel().getObject();
  237. if (rp.permission == null) {
  238. return;
  239. }
  240. if (rp.registrant == null) {
  241. return;
  242. }
  243. RegistrantAccessPermission copy = DeepCopier.copy(rp);
  244. if (StringUtils.findInvalidCharacter(copy.registrant) != null) {
  245. copy.permissionType = PermissionType.REGEX;
  246. copy.source = copy.registrant;
  247. }
  248. permissions.add(copy);
  249. // resort permissions after insert to convey idea of eval order
  250. Collections.sort(permissions);
  251. // remove registrant from available choices
  252. registrants.remove(rp.registrant);
  253. // force the panel to refresh
  254. target.addComponent(RegistrantPermissionsPanel.this);
  255. }
  256. };
  257. addPermissionForm.add(button);
  258. // only show add permission form if we have a registrant choice
  259. add(addPermissionForm.setVisible(registrants.size() > 0));
  260. }
  261. @Override
  262. protected boolean getStatelessHint()
  263. {
  264. return false;
  265. }
  266. private class AccessPermissionRenderer implements IChoiceRenderer<AccessPermission> {
  267. private static final long serialVersionUID = 1L;
  268. private final Map<AccessPermission, String> map;
  269. public AccessPermissionRenderer(Map<AccessPermission, String> map) {
  270. this.map = map;
  271. }
  272. @Override
  273. public String getDisplayValue(AccessPermission type) {
  274. return map.get(type);
  275. }
  276. @Override
  277. public String getIdValue(AccessPermission type, int index) {
  278. return Integer.toString(index);
  279. }
  280. }
  281. private class ShowStateButton extends AjaxButton {
  282. private static final long serialVersionUID = 1L;
  283. Show buttonState;
  284. public ShowStateButton(String wicketId, Show state) {
  285. super(wicketId);
  286. this.buttonState = state;
  287. setOutputMarkupId(true);
  288. }
  289. @Override
  290. protected void onBeforeRender()
  291. {
  292. String cssClass = "btn";
  293. if (buttonState.equals(RegistrantPermissionsPanel.this.activeState)) {
  294. cssClass = "btn btn-info active";
  295. }
  296. WicketUtils.setCssClass(this, cssClass);
  297. super.onBeforeRender();
  298. }
  299. @Override
  300. protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
  301. RegistrantPermissionsPanel.this.activeState = buttonState;
  302. target.addComponent(RegistrantPermissionsPanel.this);
  303. }
  304. };
  305. }