James Moger
2014-09-30 02ea71c71dbf162561f0a5d4151bc436fca38373
commit | author | age
5e3521 1 /*
JM 2  * Copyright 2014 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
18 import java.util.ArrayList;
19 import java.util.Arrays;
20 import java.util.Collections;
21 import java.util.List;
0476cf 22 import java.util.Set;
JM 23 import java.util.TreeSet;
5e3521 24
JM 25 import org.apache.wicket.PageParameters;
9d60ff 26 import org.apache.wicket.ajax.AjaxRequestTarget;
JM 27 import org.apache.wicket.ajax.markup.html.form.AjaxButton;
5e3521 28 import org.apache.wicket.markup.html.basic.Label;
JM 29 import org.apache.wicket.markup.html.form.Button;
30 import org.apache.wicket.markup.html.form.DropDownChoice;
31 import org.apache.wicket.markup.html.form.Form;
32 import org.apache.wicket.markup.html.form.TextField;
33 import org.apache.wicket.markup.html.panel.Fragment;
34 import org.apache.wicket.model.IModel;
35 import org.apache.wicket.model.Model;
cc1c3f 36 import org.eclipse.jgit.lib.Repository;
5e3521 37
cc1c3f 38 import com.gitblit.Constants;
5e3521 39 import com.gitblit.Constants.AccessPermission;
0476cf 40 import com.gitblit.Constants.AuthorizationControl;
5e3521 41 import com.gitblit.models.RegistrantAccessPermission;
JM 42 import com.gitblit.models.TicketModel;
43 import com.gitblit.models.TicketModel.Change;
44 import com.gitblit.models.TicketModel.Field;
45 import com.gitblit.models.TicketModel.Status;
46 import com.gitblit.models.UserModel;
47 import com.gitblit.tickets.TicketMilestone;
48 import com.gitblit.tickets.TicketNotifier;
49 import com.gitblit.tickets.TicketResponsible;
50 import com.gitblit.utils.StringUtils;
51 import com.gitblit.wicket.GitBlitWebSession;
52 import com.gitblit.wicket.WicketUtils;
53 import com.gitblit.wicket.panels.MarkdownTextArea;
54
55 /**
56  * Page for creating a new ticket.
57  *
58  * @author James Moger
59  *
60  */
61 public class NewTicketPage extends RepositoryPage {
62
63     private IModel<TicketModel.Type> typeModel;
64
65     private IModel<String> titleModel;
66
67     private MarkdownTextArea descriptionEditor;
68
69     private IModel<String> topicModel;
70
cc1c3f 71     private IModel<String> mergeToModel;
JM 72
5e3521 73     private IModel<TicketResponsible> responsibleModel;
JM 74
75     private IModel<TicketMilestone> milestoneModel;
76
77     private Label descriptionPreview;
78
79     public NewTicketPage(PageParameters params) {
80         super(params);
81
82         UserModel currentUser = GitBlitWebSession.get().getUser();
83         if (currentUser == null) {
84             currentUser = UserModel.ANONYMOUS;
85         }
86
87         if (!currentUser.isAuthenticated || !app().tickets().isAcceptingNewTickets(getRepositoryModel())) {
88             // tickets prohibited
89             setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName));
90         }
91
92         typeModel = Model.of(TicketModel.Type.defaultType);
a59627 93         titleModel = Model.of();
JM 94         topicModel = Model.of();
f1b882 95         mergeToModel = Model.of(Repository.shortenRefName(getRepositoryModel().mergeTo));
5e3521 96         responsibleModel = Model.of();
JM 97         milestoneModel = Model.of();
98
99         setStatelessHint(false);
100         setOutputMarkupId(true);
101
9d60ff 102         Form<Void> form = new Form<Void>("editForm");
5e3521 103         add(form);
JM 104
105         form.add(new DropDownChoice<TicketModel.Type>("type", typeModel, Arrays.asList(TicketModel.Type.choices())));
106         form.add(new TextField<String>("title", titleModel));
107         form.add(new TextField<String>("topic", topicModel));
108
a59627 109         final IModel<String> markdownPreviewModel = Model.of();
5e3521 110         descriptionPreview = new Label("descriptionPreview", markdownPreviewModel);
JM 111         descriptionPreview.setEscapeModelStrings(false);
112         descriptionPreview.setOutputMarkupId(true);
113         form.add(descriptionPreview);
114
115         descriptionEditor = new MarkdownTextArea("description", markdownPreviewModel, descriptionPreview);
116         descriptionEditor.setRepository(repositoryName);
117         form.add(descriptionEditor);
118
cc1c3f 119         if (currentUser.canAdmin(null, getRepositoryModel())) {
5e3521 120             // responsible
0476cf 121             Set<String> userlist = new TreeSet<String>();
JM 122
123             if (UserModel.ANONYMOUS.canPush(getRepositoryModel())
124                     || AuthorizationControl.AUTHENTICATED == getRepositoryModel().authorizationControl) {
125                 //     authorization is ANONYMOUS or AUTHENTICATED (i.e. all users can be set responsible)
126                 userlist.addAll(app().users().getAllUsernames());
127             } else {
128                 // authorization is by NAMED users (users with PUSH permission can be set responsible)
129                 for (RegistrantAccessPermission rp : app().repositories().getUserAccessPermissions(getRepositoryModel())) {
130                     if (rp.permission.atLeast(AccessPermission.PUSH)) {
131                         userlist.add(rp.registrant);
5e3521 132                     }
JM 133                 }
0476cf 134             }
JM 135
136             List<TicketResponsible> responsibles = new ArrayList<TicketResponsible>();
137             for (String username : userlist) {
138                 UserModel user = app().users().getUserModel(username);
139                 if (user != null && !user.disabled) {
140                     TicketResponsible responsible = new TicketResponsible(user);
141                     responsibles.add(responsible);
eb6129 142                 }
5e3521 143             }
JM 144             Collections.sort(responsibles);
145             Fragment responsible = new Fragment("responsible", "responsibleFragment", this);
146             responsible.add(new DropDownChoice<TicketResponsible>("responsible", responsibleModel, responsibles));
147             form.add(responsible.setVisible(!responsibles.isEmpty()));
148
149             // milestone
150             List<TicketMilestone> milestones = app().tickets().getMilestones(getRepositoryModel(), Status.Open);
151             Fragment milestone = new Fragment("milestone", "milestoneFragment", this);
152             milestone.add(new DropDownChoice<TicketMilestone>("milestone", milestoneModel, milestones));
153             form.add(milestone.setVisible(!milestones.isEmpty()));
cc1c3f 154
JM 155             // integration branch
156             List<String> branches = new ArrayList<String>();
157             for (String branch : getRepositoryModel().getLocalBranches()) {
158                 // exclude ticket branches
159                 if (!branch.startsWith(Constants.R_TICKET)) {
160                     branches.add(Repository.shortenRefName(branch));
161                 }
162             }
163             branches.remove(Repository.shortenRefName(getRepositoryModel().HEAD));
164             branches.add(0, Repository.shortenRefName(getRepositoryModel().HEAD));
165
166             Fragment mergeto = new Fragment("mergeto", "mergeToFragment", this);
167             mergeto.add(new DropDownChoice<String>("mergeto", mergeToModel, branches));
168             form.add(mergeto.setVisible(!branches.isEmpty()));
5e3521 169         } else {
cc1c3f 170             // user does not have permission to assign milestone, responsible, or mergeto
5e3521 171             form.add(new Label("responsible").setVisible(false));
JM 172             form.add(new Label("milestone").setVisible(false));
cc1c3f 173             form.add(new Label("mergeto").setVisible(false));
5e3521 174         }
JM 175
9d60ff 176         form.add(new AjaxButton("create") {
JM 177
178             private static final long serialVersionUID = 1L;
179
180             @Override
181             protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
182                 String title = titleModel.getObject();
183                 if (StringUtils.isEmpty(title)) {
184                     return;
185                 }
186
187                 String createdBy = GitBlitWebSession.get().getUsername();
188                 Change change = new Change(createdBy);
189                 change.setField(Field.title, title);
190                 change.setField(Field.body, descriptionEditor.getText());
191                 String topic = topicModel.getObject();
192                 if (!StringUtils.isEmpty(topic)) {
193                     change.setField(Field.topic, topic);
194                 }
195
196                 // type
197                 TicketModel.Type type = TicketModel.Type.defaultType;
198                 if (typeModel.getObject() != null) {
199                     type = typeModel.getObject();
200                 }
201                 change.setField(Field.type, type);
202
203                 // responsible
204                 TicketResponsible responsible = responsibleModel == null ? null : responsibleModel.getObject();
205                 if (responsible != null) {
206                     change.setField(Field.responsible, responsible.username);
207                 }
208
209                 // milestone
210                 TicketMilestone milestone = milestoneModel == null ? null : milestoneModel.getObject();
211                 if (milestone != null) {
212                     change.setField(Field.milestone, milestone.name);
213                 }
214
215                 // integration branch
216                 String mergeTo = mergeToModel.getObject();
217                 if (!StringUtils.isEmpty(mergeTo)) {
218                     change.setField(Field.mergeTo, mergeTo);
219                 }
220
221                 TicketModel ticket = app().tickets().createTicket(getRepositoryModel(), 0L, change);
222                 if (ticket != null) {
223                     TicketNotifier notifier = app().tickets().createNotifier();
224                     notifier.sendMailing(ticket);
2598bf 225
60bbdf 226                     redirectTo(TicketsPage.class, WicketUtils.newObjectParameter(getRepositoryModel().name, "" + ticket.number));
9d60ff 227                 } else {
JM 228                     // TODO error
229                 }
230             }
231         });
232
5e3521 233         Button cancel = new Button("cancel") {
JM 234             private static final long serialVersionUID = 1L;
235
236             @Override
237             public void onSubmit() {
238                 setResponsePage(TicketsPage.class, getPageParameters());
239             }
240         };
241         cancel.setDefaultFormProcessing(false);
242         form.add(cancel);
243
244     }
245
246     @Override
247     protected String getPageName() {
248         return getString("gb.newTicket");
249     }
250
251     @Override
252     protected Class<? extends BasePage> getRepoNavPageClass() {
253         return TicketsPage.class;
254     }
255 }