From ce048e750f7ae986dddfc8ab9b57750114d2b7b9 Mon Sep 17 00:00:00 2001 From: James Moger Date: Fri, 25 Apr 2014 23:52:30 -0400 Subject: Create and update milestone pages with rename support --- .../java/com/gitblit/tickets/ITicketService.java | 31 +++- src/main/java/com/gitblit/tickets/TicketLabel.java | 7 +- .../java/com/gitblit/tickets/TicketMilestone.java | 4 + .../java/com/gitblit/wicket/GitBlitWebApp.java | 4 + .../com/gitblit/wicket/GitBlitWebApp.properties | 4 +- .../gitblit/wicket/pages/EditMilestonePage.html | 38 +++++ .../gitblit/wicket/pages/EditMilestonePage.java | 166 +++++++++++++++++++++ .../com/gitblit/wicket/pages/NewMilestonePage.html | 37 +++++ .../com/gitblit/wicket/pages/NewMilestonePage.java | 123 +++++++++++++++ .../java/com/gitblit/wicket/pages/TicketsPage.html | 5 +- .../java/com/gitblit/wicket/pages/TicketsPage.java | 21 ++- 11 files changed, 430 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html create mode 100644 src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java create mode 100644 src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html create mode 100644 src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java diff --git a/src/main/java/com/gitblit/tickets/ITicketService.java b/src/main/java/com/gitblit/tickets/ITicketService.java index c2f3283e..e1a377a6 100644 --- a/src/main/java/com/gitblit/tickets/ITicketService.java +++ b/src/main/java/com/gitblit/tickets/ITicketService.java @@ -49,6 +49,7 @@ import com.gitblit.models.TicketModel.Field; import com.gitblit.models.TicketModel.Patchset; import com.gitblit.models.TicketModel.Status; import com.gitblit.tickets.TicketIndexer.Lucene; +import com.gitblit.utils.DeepCopier; import com.gitblit.utils.DiffUtils; import com.gitblit.utils.DiffUtils.DiffStat; import com.gitblit.utils.StringUtils; @@ -556,9 +557,10 @@ public abstract class ITicketService { public TicketMilestone getMilestone(RepositoryModel repository, String milestone) { for (TicketMilestone ms : getMilestones(repository)) { if (ms.name.equalsIgnoreCase(milestone)) { + TicketMilestone tm = DeepCopier.copy(ms); String q = QueryBuilder.q(Lucene.rid.matches(repository.getRID())).and(Lucene.milestone.matches(milestone)).build(); - ms.tickets = indexer.queryFor(q, 1, 0, Lucene.number.name(), true); - return ms; + tm.tickets = indexer.queryFor(q, 1, 0, Lucene.number.name(), true); + return tm; } } return null; @@ -639,6 +641,21 @@ public abstract class ITicketService { * @since 1.4.0 */ public synchronized boolean renameMilestone(RepositoryModel repository, String oldName, String newName, String createdBy) { + return renameMilestone(repository, oldName, newName, createdBy, true); + } + + /** + * Renames a milestone. + * + * @param repository + * @param oldName + * @param newName + * @param createdBy + * @param send ticket notifications + * @return true if successful + * @since 1.6.0 + */ + public synchronized boolean renameMilestone(RepositoryModel repository, String oldName, String newName, String createdBy, boolean notify) { if (StringUtils.isEmpty(newName)) { throw new IllegalArgumentException("new milestone can not be empty!"); } @@ -651,7 +668,7 @@ public abstract class ITicketService { config.setString(MILESTONE, newName, STATUS, milestone.status.name()); config.setString(MILESTONE, newName, COLOR, milestone.color); if (milestone.due != null) { - config.setString(MILESTONE, milestone.name, DUE, + config.setString(MILESTONE, newName, DUE, new SimpleDateFormat(DUE_DATE_PATTERN).format(milestone.due)); } config.save(); @@ -663,9 +680,13 @@ public abstract class ITicketService { Change change = new Change(createdBy); change.setField(Field.milestone, newName); TicketModel ticket = updateTicket(repository, qr.number, change); - notifier.queueMailing(ticket); + if (notify && ticket.isOpen()) { + notifier.queueMailing(ticket); + } + } + if (notify) { + notifier.sendAll(); } - notifier.sendAll(); return true; } catch (IOException e) { diff --git a/src/main/java/com/gitblit/tickets/TicketLabel.java b/src/main/java/com/gitblit/tickets/TicketLabel.java index 686ce88b..a7f0ebec 100644 --- a/src/main/java/com/gitblit/tickets/TicketLabel.java +++ b/src/main/java/com/gitblit/tickets/TicketLabel.java @@ -30,14 +30,17 @@ public class TicketLabel implements Serializable { private static final long serialVersionUID = 1L; - public final String name; + public String name; public String color; public List tickets; - public TicketLabel(String name) { + setName(name); + } + + public void setName(String name) { this.name = name; this.color = StringUtils.getColor(name); } diff --git a/src/main/java/com/gitblit/tickets/TicketMilestone.java b/src/main/java/com/gitblit/tickets/TicketMilestone.java index c6b4fcca..680615a9 100644 --- a/src/main/java/com/gitblit/tickets/TicketMilestone.java +++ b/src/main/java/com/gitblit/tickets/TicketMilestone.java @@ -37,6 +37,10 @@ public class TicketMilestone extends TicketLabel { super(name); status = Status.Open; } + + public void setDue(Date due) { + this.due = due; + } public int getProgress() { int total = getTotalTickets(); diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java index c4fdeda5..d4c1bc40 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java @@ -51,6 +51,7 @@ import com.gitblit.wicket.pages.CommitPage; import com.gitblit.wicket.pages.ComparePage; import com.gitblit.wicket.pages.DocPage; import com.gitblit.wicket.pages.DocsPage; +import com.gitblit.wicket.pages.EditMilestonePage; import com.gitblit.wicket.pages.EditTicketPage; import com.gitblit.wicket.pages.ExportTicketPage; import com.gitblit.wicket.pages.FederationRegistrationPage; @@ -63,6 +64,7 @@ import com.gitblit.wicket.pages.LogoutPage; import com.gitblit.wicket.pages.LuceneSearchPage; import com.gitblit.wicket.pages.MetricsPage; import com.gitblit.wicket.pages.MyDashboardPage; +import com.gitblit.wicket.pages.NewMilestonePage; import com.gitblit.wicket.pages.NewTicketPage; import com.gitblit.wicket.pages.OverviewPage; import com.gitblit.wicket.pages.PatchPage; @@ -187,6 +189,8 @@ public class GitBlitWebApp extends WebApplication { mount("/tickets/new", NewTicketPage.class, "r"); mount("/tickets/edit", EditTicketPage.class, "r", "h"); mount("/tickets/export", ExportTicketPage.class, "r", "h"); + mount("/milestones/new", NewMilestonePage.class, "r"); + mount("/milestones/edit", EditMilestonePage.class, "r", "h"); // setup the markup document urls mount("/docs", DocsPage.class, "r"); diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index aeb2d9ef..ce4c0b22 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -671,4 +671,6 @@ gb.serverDoesNotAcceptPatchsets = This server does not accept patchsets. gb.ticketIsClosed = This ticket is closed. gb.mergeToDescription = default integration branch for merging ticket patchsets gb.anonymousCanNotPropose = Anonymous users can not propose patchsets. -gb.youDoNotHaveClonePermission = You are not permitted to clone this repository. \ No newline at end of file +gb.youDoNotHaveClonePermission = You are not permitted to clone this repository. +gb.newMilestone = new milestone +gb.editMilestone = edit milestone \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html new file mode 100644 index 00000000..66b47848 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html @@ -0,0 +1,38 @@ + + + + + + +
+ +
+ +
+ +
+
+
+ + + + + +
*
+
+
+ +
+
+
 
+
+
+
+
+ + +
+ \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java new file mode 100644 index 00000000..44077884 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java @@ -0,0 +1,166 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.pages; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.RestartResponseException; +import org.apache.wicket.extensions.markup.html.form.DateTextField; +import org.apache.wicket.markup.html.form.Button; +import org.apache.wicket.markup.html.form.DropDownChoice; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.parboiled.common.StringUtils; + +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.TicketModel; +import com.gitblit.models.TicketModel.Status; +import com.gitblit.models.UserModel; +import com.gitblit.tickets.TicketMilestone; +import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.WicketUtils; + +/** + * Page for creating a new milestone. + * + * @author James Moger + * + */ +public class EditMilestonePage extends RepositoryPage { + + private final String oldName; + + private IModel nameModel; + + private IModel dueModel; + + private IModel statusModel; + + private IModel notificationModel; + + public EditMilestonePage(PageParameters params) { + super(params); + + RepositoryModel model = getRepositoryModel(); + if (!app().tickets().isAcceptingTicketUpdates(model)) { + // ticket service is read-only + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + + UserModel currentUser = GitBlitWebSession.get().getUser(); + if (currentUser == null) { + currentUser = UserModel.ANONYMOUS; + } + + if (!currentUser.isAuthenticated || !currentUser.canAdmin(model)) { + // administration prohibited + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + + oldName = WicketUtils.getObject(params); + if (StringUtils.isEmpty(oldName)) { + // milestone not specified + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + + TicketMilestone tm = app().tickets().getMilestone(getRepositoryModel(), oldName); + if (tm == null) { + // milestone does not exist + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + + setStatelessHint(false); + setOutputMarkupId(true); + + Form form = new Form("editForm") { + + private static final long serialVersionUID = 1L; + + @Override + protected void onSubmit() { + + String name = nameModel.getObject(); + if (StringUtils.isEmpty(name)) { + return; + } + + Date due = dueModel.getObject(); + Status status = statusModel.getObject(); + boolean rename = !name.equals(oldName); + boolean notify = notificationModel.getObject(); + + UserModel currentUser = GitBlitWebSession.get().getUser(); + String createdBy = currentUser.username; + + TicketMilestone tm = app().tickets().getMilestone(getRepositoryModel(), oldName); + tm.setName(name); + tm.setDue(due); + tm.status = status; + + boolean success = true; + if (rename) { + success = app().tickets().renameMilestone(getRepositoryModel(), oldName, name, createdBy, notify); + } + + if (success && app().tickets().updateMilestone(getRepositoryModel(), tm, createdBy)) { + setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(getRepositoryModel().name)); + } else { + // TODO error + } + } + }; + add(form); + + nameModel = Model.of(tm.name); + dueModel = Model.of(tm.due); + statusModel = Model.of(tm.status); + notificationModel = Model.of(true); + + form.add(new TextField("name", nameModel)); + form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + + List statusChoices = Arrays.asList(Status.Open, Status.Closed); + form.add(new DropDownChoice("status", statusModel, statusChoices)); + + form.add(new Button("save")); + Button cancel = new Button("cancel") { + private static final long serialVersionUID = 1L; + + @Override + public void onSubmit() { + setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + }; + cancel.setDefaultFormProcessing(false); + form.add(cancel); + + } + + @Override + protected String getPageName() { + return getString("gb.editMilestone"); + } + + @Override + protected Class getRepoNavPageClass() { + return TicketsPage.class; + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html new file mode 100644 index 00000000..1b7e11ae --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html @@ -0,0 +1,37 @@ + + + + + + +
+ +
+ +
+ +
+
+
+ + + + +
+
+
+ +
+
+
 
+
+
+
+
+ + +
+ \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java new file mode 100644 index 00000000..2c95f018 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java @@ -0,0 +1,123 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.pages; + +import java.util.Date; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.RestartResponseException; +import org.apache.wicket.extensions.markup.html.form.DateTextField; +import org.apache.wicket.markup.html.form.Button; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; + +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.UserModel; +import com.gitblit.tickets.TicketMilestone; +import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.WicketUtils; + +/** + * Page for creating a new milestone. + * + * @author James Moger + * + */ +public class NewMilestonePage extends RepositoryPage { + + private IModel nameModel; + + private IModel dueModel; + + public NewMilestonePage(PageParameters params) { + super(params); + + RepositoryModel model = getRepositoryModel(); + if (!app().tickets().isAcceptingTicketUpdates(model)) { + // ticket service is read-only + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + + UserModel currentUser = GitBlitWebSession.get().getUser(); + if (currentUser == null) { + currentUser = UserModel.ANONYMOUS; + } + + if (!currentUser.isAuthenticated || !currentUser.canAdmin(model)) { + // administration prohibited + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + + setStatelessHint(false); + setOutputMarkupId(true); + + Form form = new Form("editForm") { + + private static final long serialVersionUID = 1L; + + @Override + protected void onSubmit() { + + String name = nameModel.getObject(); + Date due = dueModel.getObject(); + + UserModel currentUser = GitBlitWebSession.get().getUser(); + String createdBy = currentUser.username; + + TicketMilestone milestone = app().tickets().createMilestone(getRepositoryModel(), name, createdBy); + if (milestone != null) { + milestone.due = due; + app().tickets().updateMilestone(getRepositoryModel(), milestone, createdBy); + throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(getRepositoryModel().name)); + } else { + // TODO error + } + } + }; + add(form); + + nameModel = Model.of(""); + dueModel = Model.of(new Date()); + + form.add(new TextField("name", nameModel)); + form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + + form.add(new Button("create")); + Button cancel = new Button("cancel") { + private static final long serialVersionUID = 1L; + + @Override + public void onSubmit() { + setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } + }; + cancel.setDefaultFormProcessing(false); + form.add(cancel); + + } + + @Override + protected String getPageName() { + return getString("gb.newMilestone"); + } + + @Override + protected Class getRepoNavPageClass() { + return TicketsPage.class; + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html index 7d13852b..e144bea1 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html @@ -138,10 +138,13 @@
+
+ +

- +
diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java index ca509e28..984b3754 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java @@ -42,6 +42,7 @@ import com.gitblit.Constants; import com.gitblit.Constants.AccessPermission; import com.gitblit.Keys; import com.gitblit.models.RegistrantAccessPermission; +import com.gitblit.models.RepositoryModel; import com.gitblit.models.TicketModel; import com.gitblit.models.TicketModel.Status; import com.gitblit.models.UserModel; @@ -646,7 +647,19 @@ public class TicketsPage extends TicketBasePage { }; add(ticketsView); - List allMilestones = app().tickets().getMilestones(getRepositoryModel()); + // new milestone link + RepositoryModel repositoryModel = getRepositoryModel(); + final boolean acceptingUpdates = app().tickets().isAcceptingTicketUpdates(repositoryModel) + && user != null && user.canAdmin(getRepositoryModel()); + if (acceptingUpdates) { + add(new LinkPanel("newMilestone", null, getString("gb.newMilestone"), + NewMilestonePage.class, WicketUtils.newRepositoryParameter(repositoryName))); + } else { + add(new Label("newMilestone").setVisible(false)); + } + + // milestones list + List allMilestones = app().tickets().getMilestones(repositoryModel); ListDataProvider allMilestonesDp = new ListDataProvider(allMilestones); DataView milestonesList = new DataView("milestoneList", allMilestonesDp) { private static final long serialVersionUID = 1L; @@ -675,6 +688,12 @@ public class TicketsPage extends TicketBasePage { } else { item.add(WicketUtils.createDatestampLabel("milestoneDue", tm.due, getTimeZone(), getTimeUtils())); } + if (acceptingUpdates) { + item.add(new LinkPanel("editMilestone", null, getString("gb.edit"), EditMilestonePage.class, + WicketUtils.newObjectParameter(repositoryName, tm.name))); + } else { + item.add(new Label("editMilestone").setVisible(false)); + } } }; add(milestonesList); -- cgit v1.2.3 From 01995873731e7efa517ca66246547b3084f8d529 Mon Sep 17 00:00:00 2001 From: James Moger Date: Sat, 26 Apr 2014 13:51:39 -0400 Subject: Allow milestone deletion within the edit milestone page --- .../java/com/gitblit/tickets/ITicketService.java | 11 +++++- src/main/java/com/gitblit/tickets/QueryResult.java | 8 ++++ .../gitblit/wicket/pages/EditMilestonePage.html | 2 +- .../gitblit/wicket/pages/EditMilestonePage.java | 45 +++++++++++++++------- .../com/gitblit/wicket/pages/NewMilestonePage.java | 18 ++++++--- 5 files changed, 62 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/gitblit/tickets/ITicketService.java b/src/main/java/com/gitblit/tickets/ITicketService.java index e1a377a6..cce805ed 100644 --- a/src/main/java/com/gitblit/tickets/ITicketService.java +++ b/src/main/java/com/gitblit/tickets/ITicketService.java @@ -643,7 +643,7 @@ public abstract class ITicketService { public synchronized boolean renameMilestone(RepositoryModel repository, String oldName, String newName, String createdBy) { return renameMilestone(repository, oldName, newName, createdBy, true); } - + /** * Renames a milestone. * @@ -714,6 +714,7 @@ public abstract class ITicketService { } Repository db = null; try { + TicketMilestone tm = getMilestone(repository, milestone); db = repositoryManager.getRepository(repository.name); StoredConfig config = db.getConfig(); config.unsetSection(MILESTONE, milestone); @@ -721,6 +722,14 @@ public abstract class ITicketService { milestonesCache.remove(repository.name); + for (QueryResult qr : tm.tickets) { + if (qr.isOpen()) { + // reset the milestone only for open tickets + Change change = new Change(createdBy); + change.setField(Field.milestone, ""); + TicketModel ticket = updateTicket(repository, qr.number, change); + } + } return true; } catch (IOException e) { log.error("failed to delete milestone " + milestone + " in " + repository, e); diff --git a/src/main/java/com/gitblit/tickets/QueryResult.java b/src/main/java/com/gitblit/tickets/QueryResult.java index 9f5d3a55..7a2b1abe 100644 --- a/src/main/java/com/gitblit/tickets/QueryResult.java +++ b/src/main/java/com/gitblit/tickets/QueryResult.java @@ -74,6 +74,14 @@ public class QueryResult implements Serializable { return type != null && Type.Proposal == type; } + public boolean isOpen() { + return !status.isClosed(); + } + + public boolean isClosed() { + return status.isClosed(); + } + public boolean isMerged() { return Status.Merged == status && !StringUtils.isEmpty(mergeSha); } diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html index 66b47848..31f76f1c 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html @@ -27,7 +27,7 @@
-
 
+
   
diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java index 44077884..b92ba8ba 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java @@ -28,13 +28,13 @@ import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; -import org.parboiled.common.StringUtils; import com.gitblit.models.RepositoryModel; import com.gitblit.models.TicketModel; import com.gitblit.models.TicketModel.Status; import com.gitblit.models.UserModel; import com.gitblit.tickets.TicketMilestone; +import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; @@ -47,13 +47,13 @@ import com.gitblit.wicket.WicketUtils; public class EditMilestonePage extends RepositoryPage { private final String oldName; - + private IModel nameModel; private IModel dueModel; - + private IModel statusModel; - + private IModel notificationModel; public EditMilestonePage(PageParameters params) { @@ -64,7 +64,7 @@ public class EditMilestonePage extends RepositoryPage { // ticket service is read-only throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); } - + UserModel currentUser = GitBlitWebSession.get().getUser(); if (currentUser == null) { currentUser = UserModel.ANONYMOUS; @@ -74,13 +74,13 @@ public class EditMilestonePage extends RepositoryPage { // administration prohibited throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); } - + oldName = WicketUtils.getObject(params); if (StringUtils.isEmpty(oldName)) { // milestone not specified throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); } - + TicketMilestone tm = app().tickets().getMilestone(getRepositoryModel(), oldName); if (tm == null) { // milestone does not exist @@ -96,30 +96,30 @@ public class EditMilestonePage extends RepositoryPage { @Override protected void onSubmit() { - + String name = nameModel.getObject(); if (StringUtils.isEmpty(name)) { return; } - + Date due = dueModel.getObject(); Status status = statusModel.getObject(); boolean rename = !name.equals(oldName); boolean notify = notificationModel.getObject(); - + UserModel currentUser = GitBlitWebSession.get().getUser(); String createdBy = currentUser.username; - + TicketMilestone tm = app().tickets().getMilestone(getRepositoryModel(), oldName); tm.setName(name); tm.setDue(due); tm.status = status; - + boolean success = true; if (rename) { success = app().tickets().renameMilestone(getRepositoryModel(), oldName, name, createdBy, notify); } - + if (success && app().tickets().updateMilestone(getRepositoryModel(), tm, createdBy)) { setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(getRepositoryModel().name)); } else { @@ -133,7 +133,7 @@ public class EditMilestonePage extends RepositoryPage { dueModel = Model.of(tm.due); statusModel = Model.of(tm.status); notificationModel = Model.of(true); - + form.add(new TextField("name", nameModel)); form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); @@ -152,6 +152,23 @@ public class EditMilestonePage extends RepositoryPage { cancel.setDefaultFormProcessing(false); form.add(cancel); + Button delete = new Button("delete") { + private static final long serialVersionUID = 1L; + + @Override + public void onSubmit() { + UserModel currentUser = GitBlitWebSession.get().getUser(); + String createdBy = currentUser.username; + + if (app().tickets().deleteMilestone(getRepositoryModel(), oldName, createdBy)) { + setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); + } else { + // TODO error processing + } + } + }; + delete.setDefaultFormProcessing(false); + form.add(delete); } @Override diff --git a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java index 2c95f018..4c393786 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java +++ b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java @@ -29,6 +29,8 @@ import org.apache.wicket.model.Model; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.tickets.TicketMilestone; +import com.gitblit.utils.StringUtils; +import com.gitblit.utils.TimeUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; @@ -43,7 +45,7 @@ public class NewMilestonePage extends RepositoryPage { private IModel nameModel; private IModel dueModel; - + public NewMilestonePage(PageParameters params) { super(params); @@ -52,7 +54,7 @@ public class NewMilestonePage extends RepositoryPage { // ticket service is read-only throw new RestartResponseException(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); } - + UserModel currentUser = GitBlitWebSession.get().getUser(); if (currentUser == null) { currentUser = UserModel.ANONYMOUS; @@ -72,13 +74,17 @@ public class NewMilestonePage extends RepositoryPage { @Override protected void onSubmit() { - + String name = nameModel.getObject(); + if (StringUtils.isEmpty(name)) { + return; + } + Date due = dueModel.getObject(); UserModel currentUser = GitBlitWebSession.get().getUser(); String createdBy = currentUser.username; - + TicketMilestone milestone = app().tickets().createMilestone(getRepositoryModel(), name, createdBy); if (milestone != null) { milestone.due = due; @@ -92,8 +98,8 @@ public class NewMilestonePage extends RepositoryPage { add(form); nameModel = Model.of(""); - dueModel = Model.of(new Date()); - + dueModel = Model.of(new Date(System.currentTimeMillis() + TimeUtils.ONEDAY)); + form.add(new TextField("name", nameModel)); form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); -- cgit v1.2.3 From 6209dc4fd442887e18e3dd6fe7056f4b842091c2 Mon Sep 17 00:00:00 2001 From: James Moger Date: Sun, 27 Apr 2014 19:49:33 -0400 Subject: Use ajax buttons in the New|Edit Milestone pages --- .../gitblit/wicket/pages/EditMilestonePage.java | 37 +++++++++++----------- .../com/gitblit/wicket/pages/NewMilestonePage.java | 26 ++++++++------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java index b92ba8ba..967d8f35 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java @@ -21,6 +21,8 @@ import java.util.List; import org.apache.wicket.PageParameters; import org.apache.wicket.RestartResponseException; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.extensions.markup.html.form.DateTextField; import org.apache.wicket.markup.html.form.Button; import org.apache.wicket.markup.html.form.DropDownChoice; @@ -90,13 +92,26 @@ public class EditMilestonePage extends RepositoryPage { setStatelessHint(false); setOutputMarkupId(true); - Form form = new Form("editForm") { + Form form = new Form("editForm"); + add(form); + + nameModel = Model.of(tm.name); + dueModel = Model.of(tm.due); + statusModel = Model.of(tm.status); + notificationModel = Model.of(true); + + form.add(new TextField("name", nameModel)); + form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + + List statusChoices = Arrays.asList(Status.Open, Status.Closed); + form.add(new DropDownChoice("status", statusModel, statusChoices)); + + form.add(new AjaxButton("save") { private static final long serialVersionUID = 1L; @Override - protected void onSubmit() { - + protected void onSubmit(AjaxRequestTarget target, Form form) { String name = nameModel.getObject(); if (StringUtils.isEmpty(name)) { return; @@ -126,21 +141,7 @@ public class EditMilestonePage extends RepositoryPage { // TODO error } } - }; - add(form); - - nameModel = Model.of(tm.name); - dueModel = Model.of(tm.due); - statusModel = Model.of(tm.status); - notificationModel = Model.of(true); - - form.add(new TextField("name", nameModel)); - form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); - - List statusChoices = Arrays.asList(Status.Open, Status.Closed); - form.add(new DropDownChoice("status", statusModel, statusChoices)); - - form.add(new Button("save")); + }); Button cancel = new Button("cancel") { private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java index 4c393786..d6e34cb0 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java +++ b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java @@ -19,6 +19,8 @@ import java.util.Date; import org.apache.wicket.PageParameters; import org.apache.wicket.RestartResponseException; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.extensions.markup.html.form.DateTextField; import org.apache.wicket.markup.html.form.Button; import org.apache.wicket.markup.html.form.Form; @@ -68,13 +70,21 @@ public class NewMilestonePage extends RepositoryPage { setStatelessHint(false); setOutputMarkupId(true); - Form form = new Form("editForm") { + Form form = new Form("editForm"); + add(form); + + nameModel = Model.of(""); + dueModel = Model.of(new Date(System.currentTimeMillis() + TimeUtils.ONEDAY)); + + form.add(new TextField("name", nameModel)); + form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + + form.add(new AjaxButton("create") { private static final long serialVersionUID = 1L; @Override - protected void onSubmit() { - + protected void onSubmit(AjaxRequestTarget target, Form form) { String name = nameModel.getObject(); if (StringUtils.isEmpty(name)) { return; @@ -94,16 +104,8 @@ public class NewMilestonePage extends RepositoryPage { // TODO error } } - }; - add(form); - - nameModel = Model.of(""); - dueModel = Model.of(new Date(System.currentTimeMillis() + TimeUtils.ONEDAY)); - - form.add(new TextField("name", nameModel)); - form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + }); - form.add(new Button("create")); Button cancel = new Button("cancel") { private static final long serialVersionUID = 1L; -- cgit v1.2.3 From 667163976e4e51fc3ebf191525e44d97c8a724dc Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 28 Apr 2014 11:08:50 -0400 Subject: Overdue labeling, notify changed tickets control --- .../java/com/gitblit/tickets/ITicketService.java | 38 +++++++++++++++++----- .../java/com/gitblit/tickets/TicketMilestone.java | 10 +++++- .../com/gitblit/wicket/GitBlitWebApp.properties | 4 ++- .../gitblit/wicket/pages/EditMilestonePage.html | 3 +- .../gitblit/wicket/pages/EditMilestonePage.java | 7 +++- .../com/gitblit/wicket/pages/NewMilestonePage.html | 2 +- .../com/gitblit/wicket/pages/NewMilestonePage.java | 11 ++++++- .../java/com/gitblit/wicket/pages/TicketsPage.java | 26 ++++++++++++--- 8 files changed, 82 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/gitblit/tickets/ITicketService.java b/src/main/java/com/gitblit/tickets/ITicketService.java index cce805ed..3261ca96 100644 --- a/src/main/java/com/gitblit/tickets/ITicketService.java +++ b/src/main/java/com/gitblit/tickets/ITicketService.java @@ -651,11 +651,12 @@ public abstract class ITicketService { * @param oldName * @param newName * @param createdBy - * @param send ticket notifications + * @param notifyOpenTickets * @return true if successful * @since 1.6.0 */ - public synchronized boolean renameMilestone(RepositoryModel repository, String oldName, String newName, String createdBy, boolean notify) { + public synchronized boolean renameMilestone(RepositoryModel repository, String oldName, + String newName, String createdBy, boolean notifyOpenTickets) { if (StringUtils.isEmpty(newName)) { throw new IllegalArgumentException("new milestone can not be empty!"); } @@ -680,11 +681,11 @@ public abstract class ITicketService { Change change = new Change(createdBy); change.setField(Field.milestone, newName); TicketModel ticket = updateTicket(repository, qr.number, change); - if (notify && ticket.isOpen()) { + if (notifyOpenTickets && ticket.isOpen()) { notifier.queueMailing(ticket); } } - if (notify) { + if (notifyOpenTickets) { notifier.sendAll(); } @@ -709,6 +710,21 @@ public abstract class ITicketService { * @since 1.4.0 */ public synchronized boolean deleteMilestone(RepositoryModel repository, String milestone, String createdBy) { + return deleteMilestone(repository, milestone, createdBy, true); + } + + /** + * Deletes a milestone. + * + * @param repository + * @param milestone + * @param createdBy + * @param notifyOpenTickets + * @return true if successful + * @since 1.6.0 + */ + public synchronized boolean deleteMilestone(RepositoryModel repository, String milestone, + String createdBy, boolean notifyOpenTickets) { if (StringUtils.isEmpty(milestone)) { throw new IllegalArgumentException("milestone can not be empty!"); } @@ -722,14 +738,18 @@ public abstract class ITicketService { milestonesCache.remove(repository.name); + TicketNotifier notifier = createNotifier(); for (QueryResult qr : tm.tickets) { - if (qr.isOpen()) { - // reset the milestone only for open tickets - Change change = new Change(createdBy); - change.setField(Field.milestone, ""); - TicketModel ticket = updateTicket(repository, qr.number, change); + Change change = new Change(createdBy); + change.setField(Field.milestone, ""); + TicketModel ticket = updateTicket(repository, qr.number, change); + if (notifyOpenTickets && ticket.isOpen()) { + notifier.queueMailing(ticket); } } + if (notifyOpenTickets) { + notifier.sendAll(); + } return true; } catch (IOException e) { log.error("failed to delete milestone " + milestone + " in " + repository, e); diff --git a/src/main/java/com/gitblit/tickets/TicketMilestone.java b/src/main/java/com/gitblit/tickets/TicketMilestone.java index 680615a9..dacedda6 100644 --- a/src/main/java/com/gitblit/tickets/TicketMilestone.java +++ b/src/main/java/com/gitblit/tickets/TicketMilestone.java @@ -37,7 +37,15 @@ public class TicketMilestone extends TicketLabel { super(name); status = Status.Open; } - + + public boolean isOpen() { + return status == Status.Open; + } + + public boolean isOverdue() { + return due == null ? false : System.currentTimeMillis() > due.getTime(); + } + public void setDue(Date due) { this.due = due; } diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index ce4c0b22..e66e53a7 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -673,4 +673,6 @@ gb.mergeToDescription = default integration branch for merging ticket patchsets gb.anonymousCanNotPropose = Anonymous users can not propose patchsets. gb.youDoNotHaveClonePermission = You are not permitted to clone this repository. gb.newMilestone = new milestone -gb.editMilestone = edit milestone \ No newline at end of file +gb.editMilestone = edit milestone +gb.notifyChangedOpenTickets = send notification for changed open tickets +gb.overdue = overdue \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html index 31f76f1c..0897ebee 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.html @@ -19,8 +19,9 @@ - + +
 
*
diff --git a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java index 967d8f35..b844442a 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditMilestonePage.java @@ -24,7 +24,9 @@ import org.apache.wicket.RestartResponseException; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.extensions.markup.html.form.DateTextField; +import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Button; +import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.TextField; @@ -102,6 +104,8 @@ public class EditMilestonePage extends RepositoryPage { form.add(new TextField("name", nameModel)); form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + form.add(new Label("dueFormat", "yyyy-MM-dd")); + form.add(new CheckBox("notify", notificationModel)); List statusChoices = Arrays.asList(Status.Open, Status.Closed); form.add(new DropDownChoice("status", statusModel, statusChoices)); @@ -160,8 +164,9 @@ public class EditMilestonePage extends RepositoryPage { public void onSubmit() { UserModel currentUser = GitBlitWebSession.get().getUser(); String createdBy = currentUser.username; + boolean notify = notificationModel.getObject(); - if (app().tickets().deleteMilestone(getRepositoryModel(), oldName, createdBy)) { + if (app().tickets().deleteMilestone(getRepositoryModel(), oldName, createdBy, notify)) { setResponsePage(TicketsPage.class, WicketUtils.newRepositoryParameter(repositoryName)); } else { // TODO error processing diff --git a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html index 1b7e11ae..2ba5d5cc 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html +++ b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.html @@ -19,7 +19,7 @@ - +
 
diff --git a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java index d6e34cb0..a9f76d3a 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java +++ b/src/main/java/com/gitblit/wicket/pages/NewMilestonePage.java @@ -22,6 +22,7 @@ import org.apache.wicket.RestartResponseException; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.extensions.markup.html.form.DateTextField; +import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Button; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.TextField; @@ -78,6 +79,7 @@ public class NewMilestonePage extends RepositoryPage { form.add(new TextField("name", nameModel)); form.add(new DateTextField("due", dueModel, "yyyy-MM-dd")); + form.add(new Label("dueFormat", "yyyy-MM-dd")); form.add(new AjaxButton("create") { @@ -87,6 +89,13 @@ public class NewMilestonePage extends RepositoryPage { protected void onSubmit(AjaxRequestTarget target, Form form) { String name = nameModel.getObject(); if (StringUtils.isEmpty(name)) { + // invalid name + return; + } + + TicketMilestone milestone = app().tickets().getMilestone(getRepositoryModel(), name); + if (milestone != null) { + // milestone already exists return; } @@ -95,7 +104,7 @@ public class NewMilestonePage extends RepositoryPage { UserModel currentUser = GitBlitWebSession.get().getUser(); String createdBy = currentUser.username; - TicketMilestone milestone = app().tickets().createMilestone(getRepositoryModel(), name, createdBy); + milestone = app().tickets().createMilestone(getRepositoryModel(), name, createdBy); if (milestone != null) { milestone.due = due; app().tickets().updateMilestone(getRepositoryModel(), milestone, createdBy); diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java index 984b3754..b7e392a2 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java @@ -20,6 +20,7 @@ import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Set; import java.util.TreeSet; @@ -657,9 +658,20 @@ public class TicketsPage extends TicketBasePage { } else { add(new Label("newMilestone").setVisible(false)); } - + // milestones list - List allMilestones = app().tickets().getMilestones(repositoryModel); + List allMilestones = new ArrayList(app().tickets().getMilestones(repositoryModel)); + Collections.sort(allMilestones, new Comparator() { + @Override + public int compare(TicketMilestone o1, TicketMilestone o2) { + if (o2.isOpen() && !o1.isOpen()) { + return 1; + } else if (o1.isOpen() && !o2.isOpen()) { + return -1; + } + return o2.due.compareTo(o1.due); + } + }); ListDataProvider allMilestonesDp = new ListDataProvider(allMilestones); DataView milestonesList = new DataView("milestoneList", allMilestonesDp) { private static final long serialVersionUID = 1L; @@ -671,15 +683,21 @@ public class TicketsPage extends TicketBasePage { item.add(new LinkPanel("milestoneName", null, tm.name, TicketsPage.class, params).setRenderBodyOnly(true)); String css; + String status = tm.status.name(); switch (tm.status) { case Open: - css = "aui-lozenge aui-lozenge-subtle"; + if (tm.isOverdue()) { + css = "aui-lozenge aui-lozenge-subtle aui-lozenge-error"; + status = "overdue"; + } else { + css = "aui-lozenge aui-lozenge-subtle"; + } break; default: css = "aui-lozenge"; break; } - Label stateLabel = new Label("milestoneState", tm.status.name()); + Label stateLabel = new Label("milestoneState", status); WicketUtils.setCssClass(stateLabel, css); item.add(stateLabel); -- cgit v1.2.3 From 8d2caa7e81fcd995f0a5c07fa4454ae2f8e86e6e Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 30 Apr 2014 17:15:31 -0400 Subject: Show open milestone progress and change milestones list layout --- .../com/gitblit/wicket/GitBlitWebApp.properties | 4 +- .../java/com/gitblit/wicket/pages/TicketsPage.html | 40 ++++++++++- .../java/com/gitblit/wicket/pages/TicketsPage.java | 81 +++++++++++++++++----- 3 files changed, 104 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index e66e53a7..1394890f 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -675,4 +675,6 @@ gb.youDoNotHaveClonePermission = You are not permitted to clone this repository. gb.newMilestone = new milestone gb.editMilestone = edit milestone gb.notifyChangedOpenTickets = send notification for changed open tickets -gb.overdue = overdue \ No newline at end of file +gb.overdue = overdue +gb.openMilestones = open milestones +gb.closedMilestones = closed milestones \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html index e144bea1..a40d3126 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.html @@ -141,15 +141,49 @@
+ +
+

+

+
+
+
+
+
+
+
-
-

- +

+

+
+
+
+
+
+ +

+ +
+
+ + +
+
+
+
+
+ , + , + +
+
+
+ diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java index b7e392a2..5973d473 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java @@ -660,27 +660,49 @@ public class TicketsPage extends TicketBasePage { } // milestones list - List allMilestones = new ArrayList(app().tickets().getMilestones(repositoryModel)); - Collections.sort(allMilestones, new Comparator() { + List openMilestones = new ArrayList(); + List closedMilestones = new ArrayList(); + for (TicketMilestone milestone : app().tickets().getMilestones(repositoryModel)) { + if (milestone.isOpen()) { + openMilestones.add(milestone); + } else { + closedMilestones.add(milestone); + } + } + Collections.sort(openMilestones, new Comparator() { + @Override + public int compare(TicketMilestone o1, TicketMilestone o2) { + return o2.due.compareTo(o1.due); + } + }); + + Collections.sort(closedMilestones, new Comparator() { @Override public int compare(TicketMilestone o1, TicketMilestone o2) { - if (o2.isOpen() && !o1.isOpen()) { - return 1; - } else if (o1.isOpen() && !o2.isOpen()) { - return -1; - } return o2.due.compareTo(o1.due); } }); - ListDataProvider allMilestonesDp = new ListDataProvider(allMilestones); - DataView milestonesList = new DataView("milestoneList", allMilestonesDp) { + + DataView openMilestonesList = milestoneList("openMilestonesList", openMilestones, acceptingUpdates); + add(openMilestonesList); + + DataView closedMilestonesList = milestoneList("closedMilestonesList", closedMilestones, acceptingUpdates); + add(closedMilestonesList); + } + + protected DataView milestoneList(String wicketId, List milestones, final boolean acceptingUpdates) { + ListDataProvider milestonesDp = new ListDataProvider(milestones); + DataView milestonesList = new DataView(wicketId, milestonesDp) { private static final long serialVersionUID = 1L; @Override public void populateItem(final Item item) { + Fragment entryPanel = new Fragment("entryPanel", "milestoneListFragment", this); + item.add(entryPanel); + final TicketMilestone tm = item.getModelObject(); - PageParameters params = queryParameters(null, tm.name, null, null, null, desc, 1); - item.add(new LinkPanel("milestoneName", null, tm.name, TicketsPage.class, params).setRenderBodyOnly(true)); + PageParameters params = queryParameters(null, tm.name, null, null, null, true, 1); + entryPanel.add(new LinkPanel("milestoneName", null, tm.name, TicketsPage.class, params).setRenderBodyOnly(true)); String css; String status = tm.status.name(); @@ -699,22 +721,47 @@ public class TicketsPage extends TicketBasePage { } Label stateLabel = new Label("milestoneState", status); WicketUtils.setCssClass(stateLabel, css); - item.add(stateLabel); + entryPanel.add(stateLabel); if (tm.due == null) { - item.add(new Label("milestoneDue", getString("gb.notSpecified"))); + entryPanel.add(new Label("milestoneDue", getString("gb.notSpecified"))); } else { - item.add(WicketUtils.createDatestampLabel("milestoneDue", tm.due, getTimeZone(), getTimeUtils())); + entryPanel.add(WicketUtils.createDatestampLabel("milestoneDue", tm.due, getTimeZone(), getTimeUtils())); } if (acceptingUpdates) { - item.add(new LinkPanel("editMilestone", null, getString("gb.edit"), EditMilestonePage.class, + entryPanel.add(new LinkPanel("editMilestone", null, getString("gb.edit"), EditMilestonePage.class, WicketUtils.newObjectParameter(repositoryName, tm.name))); } else { - item.add(new Label("editMilestone").setVisible(false)); + entryPanel.add(new Label("editMilestone").setVisible(false)); + } + + if (tm.isOpen()) { + // re-load milestone with query results + TicketMilestone m = app().tickets().getMilestone(getRepositoryModel(), tm.name); + + Fragment milestonePanel = new Fragment("milestonePanel", "openMilestoneFragment", this); + Label label = new Label("progress"); + WicketUtils.setCssStyle(label, "width:" + tm.getProgress() + "%;"); + milestonePanel.add(label); + + milestonePanel.add(new LinkPanel("openTickets", null, + MessageFormat.format(getString("gb.nOpenTickets"), m.getOpenTickets()), + TicketsPage.class, + queryParameters(null, tm.name, openStatii, null, null, true, 1))); + + milestonePanel.add(new LinkPanel("closedTickets", null, + MessageFormat.format(getString("gb.nClosedTickets"), m.getClosedTickets()), + TicketsPage.class, + queryParameters(null, tm.name, closedStatii, null, null, true, 1))); + + milestonePanel.add(new Label("totalTickets", MessageFormat.format(getString("gb.nTotalTickets"), m.getTotalTickets()))); + entryPanel.add(milestonePanel); + } else { + entryPanel.add(new Label("milestonePanel").setVisible(false)); } } }; - add(milestonesList); + return milestonesList; } protected PageParameters queryParameters( -- cgit v1.2.3 From 98cee046a95b92b7608fb4bb4371f4af55f1bf38 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 1 May 2014 14:42:57 -0400 Subject: Reset build identifier to next milestone snapshot --- build.moxie | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.moxie b/build.moxie index e0e152c7..6d80c50f 100644 --- a/build.moxie +++ b/build.moxie @@ -10,7 +10,7 @@ name: Gitblit description: pure Java Git solution groupId: com.gitblit artifactId: gitblit -version: 1.5.1-SNAPSHOT +version: 1.6.0-SNAPSHOT inceptionYear: 2011 # Current stable release -- cgit v1.2.3 From 3380373c3123f875f50e48b0290c84dfae0519e4 Mon Sep 17 00:00:00 2001 From: BUISSON Christian Date: Tue, 15 Apr 2014 15:21:33 +0200 Subject: First Step in My Tickets --- .../com/gitblit/tickets/FileTicketService.java | 116 +++++++++++-------- .../java/com/gitblit/tickets/ITicketService.java | 11 +- .../java/com/gitblit/wicket/GitBlitWebApp.java | 2 + .../com/gitblit/wicket/GitBlitWebApp.properties | 3 +- .../com/gitblit/wicket/GitBlitWebApp_fr.properties | 1 + .../com/gitblit/wicket/pages/MyTicketsPage.html | 50 ++++++++ .../com/gitblit/wicket/pages/MyTicketsPage.java | 128 +++++++++++++++++++++ .../java/com/gitblit/wicket/pages/RootPage.java | 1 + 8 files changed, 262 insertions(+), 50 deletions(-) create mode 100644 src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html create mode 100644 src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java diff --git a/src/main/java/com/gitblit/tickets/FileTicketService.java b/src/main/java/com/gitblit/tickets/FileTicketService.java index 4386020f..ea5d065f 100644 --- a/src/main/java/com/gitblit/tickets/FileTicketService.java +++ b/src/main/java/com/gitblit/tickets/FileTicketService.java @@ -207,62 +207,82 @@ public class FileTicketService extends ITicketService { @Override public List getTickets(RepositoryModel repository, TicketFilter filter) { List list = new ArrayList(); - - Repository db = repositoryManager.getRepository(repository.name); - try { - // Collect the set of all json files - File dir = new File(db.getDirectory(), TICKETS_PATH); - List journals = findAll(dir, JOURNAL); - - // Deserialize each ticket and optionally filter out unwanted tickets - for (File journal : journals) { - String json = null; - try { - json = new String(FileUtils.readContent(journal), Constants.ENCODING); - } catch (Exception e) { - log.error(null, e); - } - if (StringUtils.isEmpty(json)) { - // journal was touched but no changes were written - continue; - } - try { - // Reconstruct ticketId from the path - // id/26/326/journal.json - String path = FileUtils.getRelativePath(dir, journal); - String tid = path.split("/")[1]; - long ticketId = Long.parseLong(tid); - List changes = TicketSerializer.deserializeJournal(json); - if (ArrayUtils.isEmpty(changes)) { - log.warn("Empty journal for {}:{}", repository, journal); + List databases = new ArrayList(); + List models = new ArrayList(); + + if(repository == null) + { + List allRepo = repositoryManager.getRepositoryList(); + for(int i = 0; i < allRepo.size(); i++) + { + databases.add(repositoryManager.getRepository(allRepo.get(i))); + models.add(repositoryManager.getRepositoryModel(allRepo.get(i))); + } + } + else + { + databases.add(repositoryManager.getRepository(repository.name)); + models.add(repository); + } + + for(int i = 0; i < databases.size(); i++) + { + Repository db = databases.get(i); + try { + // Collect the set of all json files + File dir = new File(db.getDirectory(), TICKETS_PATH); + List journals = findAll(dir, JOURNAL); + + // Deserialize each ticket and optionally filter out unwanted tickets + for (File journal : journals) { + String json = null; + try { + json = new String(FileUtils.readContent(journal), Constants.ENCODING); + } catch (Exception e) { + log.error(null, e); + } + if (StringUtils.isEmpty(json)) { + // journal was touched but no changes were written continue; } - TicketModel ticket = TicketModel.buildTicket(changes); - ticket.project = repository.projectPath; - ticket.repository = repository.name; - ticket.number = ticketId; - - // add the ticket, conditionally, to the list - if (filter == null) { - list.add(ticket); - } else { - if (filter.accept(ticket)) { + try { + // Reconstruct ticketId from the path + // id/26/326/journal.json + String path = FileUtils.getRelativePath(dir, journal); + String tid = path.split("/")[1]; + long ticketId = Long.parseLong(tid); + List changes = TicketSerializer.deserializeJournal(json); + if (ArrayUtils.isEmpty(changes)) { + log.warn("Empty journal for {}:{}", models.get(i), journal); + continue; + } + TicketModel ticket = TicketModel.buildTicket(changes); + ticket.project = models.get(i).projectPath; + ticket.repository = models.get(i).name; + ticket.number = ticketId; + + // add the ticket, conditionally, to the list + if (filter == null) { list.add(ticket); + } else { + if (filter.accept(ticket)) { + list.add(ticket); + } } + } catch (Exception e) { + log.error("failed to deserialize {}/{}\n{}", + new Object [] { models.get(i), journal, e.getMessage()}); + log.error(null, e); } - } catch (Exception e) { - log.error("failed to deserialize {}/{}\n{}", - new Object [] { repository, journal, e.getMessage()}); - log.error(null, e); } + } finally { + db.close(); } - - // sort the tickets by creation - Collections.sort(list); - return list; - } finally { - db.close(); } + + // sort the tickets by creation + Collections.sort(list); + return list; } private List findAll(File dir, String filename) { diff --git a/src/main/java/com/gitblit/tickets/ITicketService.java b/src/main/java/com/gitblit/tickets/ITicketService.java index 3261ca96..e7b4c71d 100644 --- a/src/main/java/com/gitblit/tickets/ITicketService.java +++ b/src/main/java/com/gitblit/tickets/ITicketService.java @@ -779,12 +779,21 @@ public abstract class ITicketService { * @since 1.4.0 */ public abstract boolean hasTicket(RepositoryModel repository, long ticketId); + + /** + * Returns all tickets. This is not a Lucene search! + * + * @return all tickets + */ + public List getTickets() { + return getTickets(null, null); + } /** * Returns all tickets. This is not a Lucene search! * * @param repository - * @return all tickets + * @return all tickets of a given repository * @since 1.4.0 */ public List getTickets(RepositoryModel repository) { diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java index d4c1bc40..9f002d2b 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java @@ -81,6 +81,7 @@ import com.gitblit.wicket.pages.TicketsPage; import com.gitblit.wicket.pages.TreePage; import com.gitblit.wicket.pages.UserPage; import com.gitblit.wicket.pages.UsersPage; +import com.gitblit.wicket.pages.MyTicketsPage; public class GitBlitWebApp extends WebApplication { @@ -191,6 +192,7 @@ public class GitBlitWebApp extends WebApplication { mount("/tickets/export", ExportTicketPage.class, "r", "h"); mount("/milestones/new", NewMilestonePage.class, "r"); mount("/milestones/edit", EditMilestonePage.class, "r", "h"); + mount("/mytickets", MyTicketsPage.class, "r", "h"); // setup the markup document urls mount("/docs", DocsPage.class, "r"); diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 1394890f..030c5ebe 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -677,4 +677,5 @@ gb.editMilestone = edit milestone gb.notifyChangedOpenTickets = send notification for changed open tickets gb.overdue = overdue gb.openMilestones = open milestones -gb.closedMilestones = closed milestones \ No newline at end of file +gb.closedMilestones = closed milestones +gb.mytickets = my tickets \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties index 8a725cf4..75a3ab7a 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_fr.properties @@ -670,3 +670,4 @@ gb.repositoryDoesNotAcceptPatchsets = Ce d gb.serverDoesNotAcceptPatchsets = Ce serveur n'accepte pas de patchsets. gb.ticketIsClosed = Ce ticket est clos. gb.mergeToDescription = default integration branch for merging ticket patchsets +gb.mytickets = mes tickets diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html new file mode 100644 index 00000000..bbb2b96b --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -0,0 +1,50 @@ + + + + + +
+ Responsible Tickets + + + + + + +
+ + + Author Tickets + + + + + + +
+ + + Voted Tickets + + + + + + +
+ + + Watched Tickets + + + + + + +
+ + + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java new file mode 100644 index 00000000..509b00ca --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -0,0 +1,128 @@ +package com.gitblit.wicket.pages; + +import java.util.ArrayList; +import java.util.List; + +import com.gitblit.models.UserModel; +import com.gitblit.models.TicketModel; +import com.gitblit.tickets.ITicketService; +import com.gitblit.wicket.GitBlitWebApp; +import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.panels.LinkPanel; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.PageParameters; + +public class MyTicketsPage extends RootPage { + + public MyTicketsPage(PageParameters params) + { + this(); + } + + public MyTicketsPage() + { + super(); + setupPage("", ""); + + UserModel currentUser = GitBlitWebSession.get().getUser(); + if (currentUser == null) { + currentUser = UserModel.ANONYMOUS; + } + String username = currentUser.getName(); + + ITicketService tickets = GitBlitWebApp.get().tickets(); + List returnedTickets = tickets.getTickets(null); + + List responsibleTickets = new ArrayList(); + List authorTickets = new ArrayList(); + List votedTickets = new ArrayList(); + List watchedTickets = new ArrayList(); + for(int i = 0; i < returnedTickets.size(); i++) + { + TicketModel ticket = returnedTickets.get(i); + if(ticket.isOpen()) + { + if(ticket.isResponsible(username)) + { + responsibleTickets.add(ticket); + } + if(ticket.isAuthor(username)) + { + authorTickets.add(ticket); + } + if(ticket.isVoter(username)) + { + votedTickets.add(ticket); + } + if(ticket.isWatching(username)) + { + watchedTickets.add(ticket); + } + } + } + + ListView responsibleView = new ListView("responsibleTickets", responsibleTickets) + { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final ListItem item) + { + final TicketModel ticket = item.getModelObject(); + String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); + item.add(new Label("ticketDescription", ticket.body)); + } + }; + + ListView authorView = new ListView("authorTickets", authorTickets) + { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final ListItem item) + { + final TicketModel ticket = item.getModelObject(); + String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); + item.add(new Label("ticketDescription", ticket.body)); + } + }; + + ListView votedView = new ListView("votedTickets", votedTickets) + { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final ListItem item) + { + final TicketModel ticket = item.getModelObject(); + String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); + item.add(new Label("ticketDescription", ticket.body)); + } + }; + + ListView watchedView = new ListView("watchedTickets", watchedTickets) + { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final ListItem item) + { + final TicketModel ticket = item.getModelObject(); + String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); + item.add(new Label("ticketDescription", ticket.body)); + } + }; + + add(responsibleView); + add(authorView); + add(votedView); + add(watchedView); + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index 5ccc3a4c..ec413b19 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -173,6 +173,7 @@ public abstract class RootPage extends BasePage { pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters())); + pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); if (app().settings().getBoolean(Keys.web.allowLuceneIndexing, true)) { pages.add(new PageRegistration("gb.search", LuceneSearchPage.class)); } -- cgit v1.2.3 From 47bfbe3b1da6629655f49b32b917dccb21b83809 Mon Sep 17 00:00:00 2001 From: BUISSON Christian Date: Tue, 15 Apr 2014 15:45:34 +0200 Subject: Deactivate the navbar button for My Tickets (until it is finalized). --- src/main/java/com/gitblit/wicket/pages/RootPage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index ec413b19..f43dc45e 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -173,7 +173,7 @@ public abstract class RootPage extends BasePage { pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters())); - pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); + //pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); if (app().settings().getBoolean(Keys.web.allowLuceneIndexing, true)) { pages.add(new PageRegistration("gb.search", LuceneSearchPage.class)); } -- cgit v1.2.3 From 556a5853fb7145adc20b2e718eca2e921f3d7399 Mon Sep 17 00:00:00 2001 From: BUISSON Christian Date: Wed, 16 Apr 2014 16:10:51 +0200 Subject: Ajout du nom du repository sur la page "MyTickets". --- .../com/gitblit/wicket/pages/MyTicketsPage.html | 86 ++++++++++++---------- .../com/gitblit/wicket/pages/MyTicketsPage.java | 8 ++ 2 files changed, 55 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html index bbb2b96b..5222c35c 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -6,45 +6,53 @@ - - Responsible Tickets - - - - - - -
- - - Author Tickets - - - - - - -
- - - Voted Tickets - - - - - - -
- - - Watched Tickets - - - - - - -
+
+
[my tickets message]
+ + + Responsible Tickets + + + + + + + +
+ + + Author Tickets + + + + + + + +
+ + + Voted Tickets + + + + + + + +
+ + + Watched Tickets + + + + + + + +
+
\ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 509b00ca..6e656ae4 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -3,6 +3,7 @@ package com.gitblit.wicket.pages; import java.util.ArrayList; import java.util.List; +import com.gitblit.Keys; import com.gitblit.models.UserModel; import com.gitblit.models.TicketModel; import com.gitblit.tickets.ITicketService; @@ -33,6 +34,9 @@ public class MyTicketsPage extends RootPage { } String username = currentUser.getName(); + String message = "Welcome on GitBlit"; + this.add(new Label("myTicketsMessage", message)); + ITicketService tickets = GitBlitWebApp.get().tickets(); List returnedTickets = tickets.getTickets(null); @@ -73,6 +77,7 @@ public class MyTicketsPage extends RootPage { { final TicketModel ticket = item.getModelObject(); String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new Label("repositoryName", ticket.repository)); item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); item.add(new Label("ticketDescription", ticket.body)); } @@ -87,6 +92,7 @@ public class MyTicketsPage extends RootPage { { final TicketModel ticket = item.getModelObject(); String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new Label("repositoryName", ticket.repository)); item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); item.add(new Label("ticketDescription", ticket.body)); } @@ -101,6 +107,7 @@ public class MyTicketsPage extends RootPage { { final TicketModel ticket = item.getModelObject(); String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new Label("repositoryName", ticket.repository)); item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); item.add(new Label("ticketDescription", ticket.body)); } @@ -115,6 +122,7 @@ public class MyTicketsPage extends RootPage { { final TicketModel ticket = item.getModelObject(); String ticketUrl = app().tickets().getTicketUrl(ticket); + item.add(new Label("repositoryName", ticket.repository)); item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); item.add(new Label("ticketDescription", ticket.body)); } -- cgit v1.2.3 From 7d19224c99f118351ad15a77942762e74940536f Mon Sep 17 00:00:00 2001 From: Hybris95 Date: Wed, 16 Apr 2014 16:42:18 +0200 Subject: Implementation of the getTickets capability of recovering all tickets from a nullable RepositoryModel --- .../com/gitblit/tickets/BranchTicketService.java | 114 ++++++++++++--------- .../com/gitblit/tickets/FileTicketService.java | 9 +- .../com/gitblit/tickets/RedisTicketService.java | 85 +++++++++------ 3 files changed, 124 insertions(+), 84 deletions(-) diff --git a/src/main/java/com/gitblit/tickets/BranchTicketService.java b/src/main/java/com/gitblit/tickets/BranchTicketService.java index 284b1be1..7d6926df 100644 --- a/src/main/java/com/gitblit/tickets/BranchTicketService.java +++ b/src/main/java/com/gitblit/tickets/BranchTicketService.java @@ -436,64 +436,84 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi @Override public List getTickets(RepositoryModel repository, TicketFilter filter) { List list = new ArrayList(); - - Repository db = repositoryManager.getRepository(repository.name); - try { - RefModel ticketsBranch = getTicketsBranch(db); - if (ticketsBranch == null) { - return list; + List databases = new ArrayList(); + List models = new ArrayList(); + + if(repository == null) + { + List allRepo = repositoryManager.getRepositoryList(); + for(int i = 0; i < allRepo.size(); i++) + { + databases.add(repositoryManager.getRepository(allRepo.get(i))); + models.add(repositoryManager.getRepositoryModel(allRepo.get(i))); } + } + else + { + databases.add(repositoryManager.getRepository(repository.name)); + models.add(repository); + } - // Collect the set of all json files - List paths = JGitUtils.getDocuments(db, Arrays.asList("json"), BRANCH); - - // Deserialize each ticket and optionally filter out unwanted tickets - for (PathModel path : paths) { - String name = path.name.substring(path.name.lastIndexOf('/') + 1); - if (!JOURNAL.equals(name)) { - continue; - } - String json = readTicketsFile(db, path.path); - if (StringUtils.isEmpty(json)) { - // journal was touched but no changes were written - continue; + for(int i = 0; i < databases.size(); i++) + { + Repository db = databases.get(i); + try { + RefModel ticketsBranch = getTicketsBranch(db); + if (ticketsBranch == null) { + return list; } - try { - // Reconstruct ticketId from the path - // id/26/326/journal.json - String tid = path.path.split("/")[2]; - long ticketId = Long.parseLong(tid); - List changes = TicketSerializer.deserializeJournal(json); - if (ArrayUtils.isEmpty(changes)) { - log.warn("Empty journal for {}:{}", repository, path.path); + + // Collect the set of all json files + List paths = JGitUtils.getDocuments(db, Arrays.asList("json"), BRANCH); + + // Deserialize each ticket and optionally filter out unwanted tickets + for (PathModel path : paths) { + String name = path.name.substring(path.name.lastIndexOf('/') + 1); + if (!JOURNAL.equals(name)) { + continue; + } + String json = readTicketsFile(db, path.path); + if (StringUtils.isEmpty(json)) { + // journal was touched but no changes were written continue; } - TicketModel ticket = TicketModel.buildTicket(changes); - ticket.project = repository.projectPath; - ticket.repository = repository.name; - ticket.number = ticketId; - - // add the ticket, conditionally, to the list - if (filter == null) { - list.add(ticket); - } else { - if (filter.accept(ticket)) { + try { + // Reconstruct ticketId from the path + // id/26/326/journal.json + String tid = path.path.split("/")[2]; + long ticketId = Long.parseLong(tid); + List changes = TicketSerializer.deserializeJournal(json); + if (ArrayUtils.isEmpty(changes)) { + log.warn("Empty journal for {}:{}", models.get(i), path.path); + continue; + } + TicketModel ticket = TicketModel.buildTicket(changes); + ticket.project = models.get(i).projectPath; + ticket.repository = models.get(i).name; + ticket.number = ticketId; + + // add the ticket, conditionally, to the list + if (filter == null) { list.add(ticket); + } else { + if (filter.accept(ticket)) { + list.add(ticket); + } } + } catch (Exception e) { + log.error("failed to deserialize {}/{}\n{}", + new Object [] { repository, path.path, e.getMessage()}); + log.error(null, e); } - } catch (Exception e) { - log.error("failed to deserialize {}/{}\n{}", - new Object [] { repository, path.path, e.getMessage()}); - log.error(null, e); } + } finally { + db.close(); } - - // sort the tickets by creation - Collections.sort(list); - return list; - } finally { - db.close(); } + + // sort the tickets by creation + Collections.sort(list); + return list; } /** diff --git a/src/main/java/com/gitblit/tickets/FileTicketService.java b/src/main/java/com/gitblit/tickets/FileTicketService.java index ea5d065f..7fd9675f 100644 --- a/src/main/java/com/gitblit/tickets/FileTicketService.java +++ b/src/main/java/com/gitblit/tickets/FileTicketService.java @@ -228,6 +228,7 @@ public class FileTicketService extends ITicketService { for(int i = 0; i < databases.size(); i++) { Repository db = databases.get(i); + RepositoryModel model = models.get(i); try { // Collect the set of all json files File dir = new File(db.getDirectory(), TICKETS_PATH); @@ -253,12 +254,12 @@ public class FileTicketService extends ITicketService { long ticketId = Long.parseLong(tid); List changes = TicketSerializer.deserializeJournal(json); if (ArrayUtils.isEmpty(changes)) { - log.warn("Empty journal for {}:{}", models.get(i), journal); + log.warn("Empty journal for {}:{}", model, journal); continue; } TicketModel ticket = TicketModel.buildTicket(changes); - ticket.project = models.get(i).projectPath; - ticket.repository = models.get(i).name; + ticket.project = model.projectPath; + ticket.repository = model.name; ticket.number = ticketId; // add the ticket, conditionally, to the list @@ -271,7 +272,7 @@ public class FileTicketService extends ITicketService { } } catch (Exception e) { log.error("failed to deserialize {}/{}\n{}", - new Object [] { models.get(i), journal, e.getMessage()}); + new Object [] { model, journal, e.getMessage()}); log.error(null, e); } } diff --git a/src/main/java/com/gitblit/tickets/RedisTicketService.java b/src/main/java/com/gitblit/tickets/RedisTicketService.java index 2c5b181f..48256b2b 100644 --- a/src/main/java/com/gitblit/tickets/RedisTicketService.java +++ b/src/main/java/com/gitblit/tickets/RedisTicketService.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Set; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; +import org.eclipse.jgit.lib.Repository; import redis.clients.jedis.Client; import redis.clients.jedis.Jedis; @@ -228,47 +229,65 @@ public class RedisTicketService extends ITicketService { public List getTickets(RepositoryModel repository, TicketFilter filter) { Jedis jedis = pool.getResource(); List list = new ArrayList(); + List models = new ArrayList(); + + if(repository == null) + { + List allRepo = repositoryManager.getRepositoryList(); + for(int i = 0; i < allRepo.size(); i++) + { + models.add(repositoryManager.getRepositoryModel(allRepo.get(i))); + } + } + else + { + models.add(repository); + } + if (jedis == null) { return list; } - try { - // Deserialize each journal, build the ticket, and optionally filter - Set keys = jedis.keys(key(repository, KeyType.journal, "*")); - for (String key : keys) { - // {repo}:journal:{id} - String id = key.split(":")[2]; - long ticketId = Long.parseLong(id); - List changes = getJournal(jedis, repository, ticketId); - if (ArrayUtils.isEmpty(changes)) { - log.warn("Empty journal for {}:{}", repository, ticketId); - continue; - } - TicketModel ticket = TicketModel.buildTicket(changes); - ticket.project = repository.projectPath; - ticket.repository = repository.name; - ticket.number = ticketId; - - // add the ticket, conditionally, to the list - if (filter == null) { - list.add(ticket); - } else { - if (filter.accept(ticket)) { + for(int i = 0; i < models.size(); i++) + { + RepositoryModel model = models.get(i); + try { + // Deserialize each journal, build the ticket, and optionally filter + Set keys = jedis.keys(key(model, KeyType.journal, "*")); + for (String key : keys) { + // {repo}:journal:{id} + String id = key.split(":")[2]; + long ticketId = Long.parseLong(id); + List changes = getJournal(jedis, model, ticketId); + if (ArrayUtils.isEmpty(changes)) { + log.warn("Empty journal for {}:{}", model, ticketId); + continue; + } + TicketModel ticket = TicketModel.buildTicket(changes); + ticket.project = model.projectPath; + ticket.repository = model.name; + ticket.number = ticketId; + + // add the ticket, conditionally, to the list + if (filter == null) { list.add(ticket); + } else { + if (filter.accept(ticket)) { + list.add(ticket); + } } } - } - - // sort the tickets by creation - Collections.sort(list); - } catch (JedisException e) { - log.error("failed to retrieve tickets from Redis @ " + getUrl(), e); - pool.returnBrokenResource(jedis); - jedis = null; - } finally { - if (jedis != null) { - pool.returnResource(jedis); + } catch (JedisException e) { + log.error("failed to retrieve tickets from Redis @ " + getUrl(), e); + pool.returnBrokenResource(jedis); + jedis = null; + } finally { + if (jedis != null) { + pool.returnResource(jedis); + } } } + // sort the tickets by creation + Collections.sort(list); return list; } -- cgit v1.2.3 From 75796a0e2798e256a94f725961c9676746fc107a Mon Sep 17 00:00:00 2001 From: Hybris95 Date: Thu, 17 Apr 2014 15:44:16 +0200 Subject: Added git stylesheets to MyTickets. Added links to Repositories containing the tickets. --- .../com/gitblit/wicket/pages/MyTicketsPage.html | 69 +++++------ .../com/gitblit/wicket/pages/MyTicketsPage.java | 137 +++++++++------------ src/main/resources/gitblit.css | 48 ++++++++ 3 files changed, 135 insertions(+), 119 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html index 5222c35c..5d11fbbb 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -9,49 +9,36 @@
[my tickets message]
- - Responsible Tickets +
+ - - - - - - -
- - - Author Tickets - - - - - - - -
- - - Voted Tickets - - - - - - - -
- - - Watched Tickets - - - - - - - + + + +
+ + + + + + Repository + + Ticket + Description + Responsible + + + + + + + [repository name] + + [ticket name] + [ticket description] + [ticket responsible] +
diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 6e656ae4..6cd80a3f 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -1,19 +1,28 @@ package com.gitblit.wicket.pages; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; -import com.gitblit.Keys; +import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.models.TicketModel; import com.gitblit.tickets.ITicketService; import com.gitblit.wicket.GitBlitWebApp; import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.LinkPanel; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.markup.html.panel.Fragment; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.data.DataView; +import org.apache.wicket.markup.repeater.data.IDataProvider; +import org.apache.wicket.markup.repeater.data.ListDataProvider; +import org.apache.wicket.model.IModel; +import org.apache.wicket.Component; import org.apache.wicket.PageParameters; public class MyTicketsPage extends RootPage { @@ -34,103 +43,75 @@ public class MyTicketsPage extends RootPage { } String username = currentUser.getName(); + // TODO - Recover the Welcome message String message = "Welcome on GitBlit"; - this.add(new Label("myTicketsMessage", message)); + this.add(new Label("myTicketsMessage", message)); + + Fragment fragment = new Fragment("headerContent", "ticketsHeader", this); + add(fragment); ITicketService tickets = GitBlitWebApp.get().tickets(); List returnedTickets = tickets.getTickets(null); + List yourTickets = new ArrayList(); - List responsibleTickets = new ArrayList(); - List authorTickets = new ArrayList(); - List votedTickets = new ArrayList(); - List watchedTickets = new ArrayList(); for(int i = 0; i < returnedTickets.size(); i++) { TicketModel ticket = returnedTickets.get(i); if(ticket.isOpen()) { - if(ticket.isResponsible(username)) - { - responsibleTickets.add(ticket); - } - if(ticket.isAuthor(username)) - { - authorTickets.add(ticket); - } - if(ticket.isVoter(username)) + if(ticket.isResponsible(username) || ticket.isAuthor(username) + || ticket.isVoter(username) || ticket.isWatching(username)) { - votedTickets.add(ticket); - } - if(ticket.isWatching(username)) - { - watchedTickets.add(ticket); + yourTickets.add(ticket); } } } - ListView responsibleView = new ListView("responsibleTickets", responsibleTickets) - { - private static final long serialVersionUID = 1L; - - @Override - public void populateItem(final ListItem item) - { - final TicketModel ticket = item.getModelObject(); - String ticketUrl = app().tickets().getTicketUrl(ticket); - item.add(new Label("repositoryName", ticket.repository)); - item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); - item.add(new Label("ticketDescription", ticket.body)); - } - }; + final ListDataProvider dp = new ListDataProvider(yourTickets); - ListView authorView = new ListView("authorTickets", authorTickets) - { + DataView dataView = new DataView("row", dp) { private static final long serialVersionUID = 1L; - - @Override - public void populateItem(final ListItem item) - { - final TicketModel ticket = item.getModelObject(); - String ticketUrl = app().tickets().getTicketUrl(ticket); - item.add(new Label("repositoryName", ticket.repository)); - item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); - item.add(new Label("ticketDescription", ticket.body)); - } - }; - - ListView votedView = new ListView("votedTickets", votedTickets) - { - private static final long serialVersionUID = 1L; - - @Override - public void populateItem(final ListItem item) - { - final TicketModel ticket = item.getModelObject(); - String ticketUrl = app().tickets().getTicketUrl(ticket); - item.add(new Label("repositoryName", ticket.repository)); - item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); - item.add(new Label("ticketDescription", ticket.body)); - } - }; - - ListView watchedView = new ListView("watchedTickets", watchedTickets) - { - private static final long serialVersionUID = 1L; - + @Override - public void populateItem(final ListItem item) - { - final TicketModel ticket = item.getModelObject(); - String ticketUrl = app().tickets().getTicketUrl(ticket); - item.add(new Label("repositoryName", ticket.repository)); - item.add(new LinkPanel("ticketName", "", ticket.title, ticketUrl)); - item.add(new Label("ticketDescription", ticket.body)); + protected void populateItem(Item item) { + TicketModel ticketModel = item.getModelObject(); + RepositoryModel repository = app().repositories().getRepositoryModel(ticketModel.repository); + + Fragment row = new Fragment("rowContent", "ticketRow", this); + item.add(row); + + Component swatch; + if(repository.isBare) + { + swatch = new Label("repositorySwatch", " ").setEscapeModelStrings(false); + } + else + { + swatch = new Label("repositorySwatch", "!"); + WicketUtils.setHtmlTooltip(swatch, getString("gb.workingCopyWarning")); + } + WicketUtils.setCssBackground(swatch, repository.toString()); + row.add(swatch); + + PageParameters pp = WicketUtils.newRepositoryParameter(repository.name); + Class linkPage; + if (repository.hasCommits) { + // repository has content + linkPage = SummaryPage.class; + } else { + // new/empty repository OR proposed repository + linkPage = EmptyRepositoryPage.class; + } + + String ticketUrl = app().tickets().getTicketUrl(ticketModel); + + row.add(new LinkPanel("repositoryName", "list", repository.name, linkPage, pp)); + row.add(new LinkPanel("ticketName", "list", ticketModel.title, ticketUrl)); + row.add(new LinkPanel("ticketDescription", "list", ticketModel.body, ticketUrl)); + row.add(new Label("ticketResponsible", ticketModel.responsible)); } }; - add(responsibleView); - add(authorView); - add(votedView); - add(watchedView); + add(dataView); } } diff --git a/src/main/resources/gitblit.css b/src/main/resources/gitblit.css index 748a3198..ea663a66 100644 --- a/src/main/resources/gitblit.css +++ b/src/main/resources/gitblit.css @@ -1599,6 +1599,54 @@ table.repositories tr.group td a { color: black; } +table.tickets { + border:1px solid #ddd; + border-spacing: 0px; + width: 100%; +} + +table.tickets th { + padding: 4px; + border:0; +} + +table.tickets th.right { + border-right: 1px solid #ddd; +} + +table.tickets td { + padding: 2px; + border-left: 0; +} + +table.tickets td.rightAlign { + text-align: right; + border-right: 1px solid #ddd; +} + +table.tickets td.icon img { + vertical-align: top; +} + +table.tickets tr.group { + background-color: #ccc; + border-left: 1px solid #ccc; + border-right: 1px solid #ccc; +} + +table.tickets tr.group td { + font-weight: bold; + color: black; + background-color: #ddd; + padding-left: 5px; + border-top: 1px solid #aaa; + border-bottom: 1px solid #aaa; +} + +table.tickets tr.group td a { + color: black; +} + table.palette { border:0; width: 0 !important; } table.palette td.header { font-weight: bold; -- cgit v1.2.3 From f3b1e099e6ae252f1f1296ce5415b85fef6361cf Mon Sep 17 00:00:00 2001 From: Hybris95 Date: Fri, 18 Apr 2014 10:53:24 +0200 Subject: Added back the "my tickets" button in the navbar. --- src/main/java/com/gitblit/wicket/pages/RootPage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index f43dc45e..ec413b19 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -173,7 +173,7 @@ public abstract class RootPage extends BasePage { pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters())); - //pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); + pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); if (app().settings().getBoolean(Keys.web.allowLuceneIndexing, true)) { pages.add(new PageRegistration("gb.search", LuceneSearchPage.class)); } -- cgit v1.2.3 From e1fa9b763cadcdc44943f805aba83698acafa613 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 21 Apr 2014 21:55:48 -0400 Subject: Revisions demonstrating the direction I'd like this to go --- .../com/gitblit/wicket/pages/MyTicketsPage.html | 55 +++-- .../com/gitblit/wicket/pages/MyTicketsPage.java | 227 ++++++++++++++------- 2 files changed, 180 insertions(+), 102 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html index 5d11fbbb..063e7511 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -7,38 +7,35 @@
-
[my tickets message]
- - + + + + + + + + - - - - + + + + + + + +
+ + Repository + TicketStatusResponsible
+ + [repository name] + + [ticket icon] + [ticket title] + (#[ticket number]) + [ticket responsible]
- - - - - - Repository - - Ticket - Description - Responsible - - - - - - - [repository name] - - [ticket name] - [ticket description] - [ticket responsible] -
diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 6cd80a3f..2c57a051 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -1,41 +1,41 @@ package com.gitblit.wicket.pages; -import java.util.ArrayList; -import java.util.Iterator; import java.util.List; +import org.apache.wicket.Component; +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.data.DataView; +import org.apache.wicket.markup.repeater.data.ListDataProvider; + import com.gitblit.models.RepositoryModel; -import com.gitblit.models.UserModel; import com.gitblit.models.TicketModel; +import com.gitblit.models.UserModel; +import com.gitblit.models.TicketModel.Status; +import com.gitblit.models.TicketModel.Type; import com.gitblit.tickets.ITicketService; +import com.gitblit.tickets.QueryBuilder; +import com.gitblit.tickets.QueryResult; +import com.gitblit.tickets.TicketIndexer.Lucene; +import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebApp; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.panels.GravatarImage; import com.gitblit.wicket.panels.LinkPanel; -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.list.ListItem; -import org.apache.wicket.markup.html.list.ListView; -import org.apache.wicket.markup.html.panel.Fragment; -import org.apache.wicket.markup.repeater.Item; -import org.apache.wicket.markup.repeater.data.DataView; -import org.apache.wicket.markup.repeater.data.IDataProvider; -import org.apache.wicket.markup.repeater.data.ListDataProvider; -import org.apache.wicket.model.IModel; -import org.apache.wicket.Component; -import org.apache.wicket.PageParameters; - public class MyTicketsPage extends RootPage { - public MyTicketsPage(PageParameters params) + public MyTicketsPage() { - this(); + this(null); } - public MyTicketsPage() + public MyTicketsPage(PageParameters params) { super(); - setupPage("", ""); + setupPage("", getString("gb.mytickets")); UserModel currentUser = GitBlitWebSession.get().getUser(); if (currentUser == null) { @@ -43,75 +43,156 @@ public class MyTicketsPage extends RootPage { } String username = currentUser.getName(); - // TODO - Recover the Welcome message - String message = "Welcome on GitBlit"; - this.add(new Label("myTicketsMessage", message)); - - Fragment fragment = new Fragment("headerContent", "ticketsHeader", this); - add(fragment); + QueryBuilder qb = QueryBuilder + .q(Lucene.createdby.matches(username)) + .or(Lucene.responsible.matches(username)) + .or(Lucene.watchedby.matches(username)); ITicketService tickets = GitBlitWebApp.get().tickets(); - List returnedTickets = tickets.getTickets(null); - List yourTickets = new ArrayList(); - - for(int i = 0; i < returnedTickets.size(); i++) - { - TicketModel ticket = returnedTickets.get(i); - if(ticket.isOpen()) - { - if(ticket.isResponsible(username) || ticket.isAuthor(username) - || ticket.isVoter(username) || ticket.isWatching(username)) - { - yourTickets.add(ticket); - } - } - } + List results = tickets.queryFor(qb.build(), 0, 0, Lucene.updated.name(), true); - final ListDataProvider dp = new ListDataProvider(yourTickets); + final ListDataProvider dp = new ListDataProvider(results); - DataView dataView = new DataView("row", dp) { + DataView dataView = new DataView("row", dp) { private static final long serialVersionUID = 1L; @Override - protected void populateItem(Item item) { - TicketModel ticketModel = item.getModelObject(); - RepositoryModel repository = app().repositories().getRepositoryModel(ticketModel.repository); - - Fragment row = new Fragment("rowContent", "ticketRow", this); - item.add(row); + protected void populateItem(Item item) { + QueryResult ticket = item.getModelObject(); + RepositoryModel repository = app().repositories().getRepositoryModel(ticket.repository); - Component swatch; - if(repository.isBare) - { - swatch = new Label("repositorySwatch", " ").setEscapeModelStrings(false); - } - else - { - swatch = new Label("repositorySwatch", "!"); - WicketUtils.setHtmlTooltip(swatch, getString("gb.workingCopyWarning")); - } + Component swatch = new Label("repositorySwatch", " ").setEscapeModelStrings(false); WicketUtils.setCssBackground(swatch, repository.toString()); - row.add(swatch); + item.add(swatch); - PageParameters pp = WicketUtils.newRepositoryParameter(repository.name); - Class linkPage; - if (repository.hasCommits) { - // repository has content - linkPage = SummaryPage.class; - } else { - // new/empty repository OR proposed repository - linkPage = EmptyRepositoryPage.class; - } + PageParameters rp = WicketUtils.newRepositoryParameter(ticket.repository); + PageParameters tp = WicketUtils.newObjectParameter(ticket.repository, "" + ticket.number); + item.add(new LinkPanel("repositoryName", "list", StringUtils.stripDotGit(ticket.repository), SummaryPage.class, rp)); - String ticketUrl = app().tickets().getTicketUrl(ticketModel); + item.add(getStateIcon("ticketIcon", ticket.type, ticket.status)); + item.add(new Label("ticketNumber", "" + ticket.number)); + item.add(new LinkPanel("ticketTitle", "list", ticket.title, TicketsPage.class, tp)); + + // votes indicator + Label v = new Label("ticketVotes", "" + ticket.votesCount); + WicketUtils.setHtmlTooltip(v, getString("gb.votes")); + item.add(v.setVisible(ticket.votesCount > 0)); + + Label ticketStatus = new Label("ticketStatus", ticket.status.toString()); + String statusClass = getStatusClass(ticket.status); + WicketUtils.setCssClass(ticketStatus, statusClass); + item.add(ticketStatus); - row.add(new LinkPanel("repositoryName", "list", repository.name, linkPage, pp)); - row.add(new LinkPanel("ticketName", "list", ticketModel.title, ticketUrl)); - row.add(new LinkPanel("ticketDescription", "list", ticketModel.body, ticketUrl)); - row.add(new Label("ticketResponsible", ticketModel.responsible)); + UserModel responsible = app().users().getUserModel(ticket.responsible); + if (responsible == null) { + if (ticket.responsible == null) { + item.add(new Label("ticketResponsibleImg").setVisible(false)); + } else { + item.add(new GravatarImage("ticketResponsibleImg", ticket.responsible, ticket.responsible, null, 16, true)); + } + item.add(new Label("ticketResponsible", ticket.responsible)); + } else { + item.add(new GravatarImage("ticketResponsibleImg", responsible, null, 16, true)); + item.add(new LinkPanel("ticketResponsible", null, responsible.getDisplayName(), UserPage.class, WicketUtils.newUsernameParameter(ticket.responsible))); + } } }; add(dataView); } + + protected Label getStateIcon(String wicketId, TicketModel ticket) { + return getStateIcon(wicketId, ticket.type, ticket.status); + } + + protected Label getStateIcon(String wicketId, Type type, Status state) { + Label label = new Label(wicketId); + if (type == null) { + type = Type.defaultType; + } + switch (type) { + case Proposal: + WicketUtils.setCssClass(label, "fa fa-code-fork"); + break; + case Bug: + WicketUtils.setCssClass(label, "fa fa-bug"); + break; + case Enhancement: + WicketUtils.setCssClass(label, "fa fa-magic"); + break; + case Question: + WicketUtils.setCssClass(label, "fa fa-question"); + break; + default: + // standard ticket + WicketUtils.setCssClass(label, "fa fa-ticket"); + } + WicketUtils.setHtmlTooltip(label, getTypeState(type, state)); + return label; + } + + protected String getTypeState(Type type, Status state) { + return state.toString() + " " + type.toString(); + } + + protected String getLozengeClass(Status status, boolean subtle) { + if (status == null) { + status = Status.New; + } + String css = ""; + switch (status) { + case Declined: + case Duplicate: + case Invalid: + case Wontfix: + case Abandoned: + css = "aui-lozenge-error"; + break; + case Fixed: + case Merged: + case Resolved: + css = "aui-lozenge-success"; + break; + case New: + css = "aui-lozenge-complete"; + break; + case On_Hold: + css = "aui-lozenge-current"; + break; + default: + css = ""; + break; + } + + return "aui-lozenge" + (subtle ? " aui-lozenge-subtle": "") + (css.isEmpty() ? "" : " ") + css; + } + + protected String getStatusClass(Status status) { + String css = ""; + switch (status) { + case Declined: + case Duplicate: + case Invalid: + case Wontfix: + case Abandoned: + css = "resolution-error"; + break; + case Fixed: + case Merged: + case Resolved: + css = "resolution-success"; + break; + case New: + css = "resolution-complete"; + break; + case On_Hold: + css = "resolution-current"; + break; + default: + css = ""; + break; + } + + return "resolution" + (css.isEmpty() ? "" : " ") + css; + } } -- cgit v1.2.3 From 4640f1b689684b805f08a5a937e91dfc65ae977f Mon Sep 17 00:00:00 2001 From: Hybris95 Date: Tue, 22 Apr 2014 12:23:03 +0200 Subject: Now only shows the "my tickets" button in the navbar if you are connected. Redirects to the main page if you try going on "/mytickets" when not connected (or if you disconnect while being on "/mytickets"). --- .../java/com/gitblit/wicket/pages/MyTicketsPage.java | 6 ++++-- src/main/java/com/gitblit/wicket/pages/RootPage.java | 17 +++++++++++------ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 2c57a051..9be3b125 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -34,12 +34,14 @@ public class MyTicketsPage extends RootPage { public MyTicketsPage(PageParameters params) { - super(); + super(params); setupPage("", getString("gb.mytickets")); UserModel currentUser = GitBlitWebSession.get().getUser(); if (currentUser == null) { - currentUser = UserModel.ANONYMOUS; + setRedirect(true); + setResponsePage(getApplication().getHomePage()); + return; } String username = currentUser.getName(); diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index ec413b19..a4d2353d 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -134,6 +134,8 @@ public abstract class RootPage extends BasePage { boolean authenticateView = app().settings().getBoolean(Keys.web.authenticateViewPages, false); boolean authenticateAdmin = app().settings().getBoolean(Keys.web.authenticateAdminPages, true); boolean allowAdmin = app().settings().getBoolean(Keys.web.allowAdministration, true); + boolean allowLucene = app().settings().getBoolean(Keys.web.allowLuceneIndexing, true); + boolean isLoggedIn = GitBlitWebSession.get().isLoggedIn(); if (authenticateAdmin) { showAdmin = allowAdmin && GitBlitWebSession.get().canAdmin(); @@ -151,7 +153,7 @@ public abstract class RootPage extends BasePage { } if (authenticateView || authenticateAdmin) { - if (GitBlitWebSession.get().isLoggedIn()) { + if (isLoggedIn) { UserMenu userFragment = new UserMenu("userPanel", "userMenuFragment", RootPage.this); add(userFragment); } else { @@ -167,14 +169,17 @@ public abstract class RootPage extends BasePage { // navigation links List pages = new ArrayList(); - if (!authenticateView || (authenticateView && GitBlitWebSession.get().isLoggedIn())) { - pages.add(new PageRegistration(GitBlitWebSession.get().isLoggedIn() ? "gb.myDashboard" : "gb.dashboard", MyDashboardPage.class, + if (!authenticateView || (authenticateView && isLoggedIn)) { + pages.add(new PageRegistration(isLoggedIn ? "gb.myDashboard" : "gb.dashboard", MyDashboardPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters())); - pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); - if (app().settings().getBoolean(Keys.web.allowLuceneIndexing, true)) { + if(isLoggedIn) + { + pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); + } + if (allowLucene) { pages.add(new PageRegistration("gb.search", LuceneSearchPage.class)); } if (showAdmin) { @@ -184,7 +189,7 @@ public abstract class RootPage extends BasePage { pages.add(new PageRegistration("gb.federation", FederationPage.class)); } - if (!authenticateView || (authenticateView && GitBlitWebSession.get().isLoggedIn())) { + if (!authenticateView || (authenticateView && isLoggedIn)) { addDropDownMenus(pages); } } -- cgit v1.2.3 From e7f65dfe56b5b6325a7d7b42f877ae8d63fa4f71 Mon Sep 17 00:00:00 2001 From: Hybris95 Date: Tue, 22 Apr 2014 16:21:35 +0200 Subject: Advanced "my tickets" page. Using filters and search. --- .../com/gitblit/wicket/pages/MyTicketsPage.html | 117 +++++-- .../com/gitblit/wicket/pages/MyTicketsPage.java | 370 ++++++++++++++++++++- 2 files changed, 452 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html index 063e7511..459d2551 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -7,35 +7,94 @@
- - - - - - - - - - - - - - - - - - -
- - Repository - TicketStatusResponsible
- - [repository name] - - [ticket icon] - [ticket title] - (#[ticket number]) - [ticket responsible]
+ + +
+ +
+ + +
+
+
+ +
+
+ +
+
+ + +
+
+
+ : + +
+ +
+ : + +
+ +
+ +
+
+ + + + + + + + + + +
+ + [repository name] + + [ticket icon] + [ticket title] + (#[ticket number]) + [ticket responsible]
+
+
+
+
diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 9be3b125..01a30181 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -1,14 +1,24 @@ package com.gitblit.wicket.pages; +import java.io.Serializable; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.apache.wicket.Component; import org.apache.wicket.PageParameters; import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.markup.html.link.BookmarkablePageLink; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.data.DataView; import org.apache.wicket.markup.repeater.data.ListDataProvider; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.target.basic.RedirectRequestTarget; +import com.gitblit.Keys; import com.gitblit.models.RepositoryModel; import com.gitblit.models.TicketModel; import com.gitblit.models.UserModel; @@ -18,14 +28,20 @@ import com.gitblit.tickets.ITicketService; import com.gitblit.tickets.QueryBuilder; import com.gitblit.tickets.QueryResult; import com.gitblit.tickets.TicketIndexer.Lucene; +import com.gitblit.utils.ArrayUtils; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebApp; import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.SessionlessForm; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.GravatarImage; import com.gitblit.wicket.panels.LinkPanel; public class MyTicketsPage extends RootPage { + + public static final String [] openStatii = new String [] { Status.New.name().toLowerCase(), Status.Open.name().toLowerCase() }; + + public static final String [] closedStatii = new String [] { "!" + Status.New.name().toLowerCase(), "!" + Status.Open.name().toLowerCase() }; public MyTicketsPage() { @@ -43,15 +59,205 @@ public class MyTicketsPage extends RootPage { setResponsePage(getApplication().getHomePage()); return; } - String username = currentUser.getName(); - QueryBuilder qb = QueryBuilder - .q(Lucene.createdby.matches(username)) - .or(Lucene.responsible.matches(username)) - .or(Lucene.watchedby.matches(username)); + final String username = currentUser.getName(); + final String[] statiiParam = (params == null) ? new String[0] : params.getStringArray(Lucene.status.name()); + final String assignedToParam = (params == null) ? "" : params.getString(Lucene.responsible.name(), null); + final String milestoneParam = (params == null) ? "" : params.getString(Lucene.milestone.name(), null); + final String queryParam = (params == null || StringUtils.isEmpty(params.getString("q", null))) ? "watchedby:" + username : params.getString("q", null); + final String searchParam = (params == null) ? "" : params.getString("s", null); + final String sortBy = (params == null) ? "" : Lucene.fromString(params.getString("sort", Lucene.created.name())).name(); + final boolean desc = (params == null) ? true : !"asc".equals(params.getString("direction", "desc")); + + // add search form + TicketSearchForm searchForm = new TicketSearchForm("ticketSearchForm", searchParam); + add(searchForm); + searchForm.setTranslatedAttributes(); + + // standard queries + add(new BookmarkablePageLink("changesQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Proposal.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink("bugsQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Bug.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink("enhancementsQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Enhancement.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink("tasksQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Task.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink("questionsQuery", MyTicketsPage.class, + queryParameters( + Lucene.type.matches(TicketModel.Type.Question.name()), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink("resetQuery", MyTicketsPage.class, + queryParameters( + null, + milestoneParam, + openStatii, + null, + null, + true, + 1))); + + add(new Label("userDivider")); + add(new BookmarkablePageLink("createdQuery", MyTicketsPage.class, + queryParameters( + Lucene.createdby.matches(username), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + add(new BookmarkablePageLink("watchedQuery", MyTicketsPage.class, + queryParameters( + Lucene.watchedby.matches(username), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + add(new BookmarkablePageLink("mentionsQuery", MyTicketsPage.class, + queryParameters( + Lucene.mentions.matches(username), + milestoneParam, + statiiParam, + assignedToParam, + sortBy, + desc, + 1))); + + // states + if (ArrayUtils.isEmpty(statiiParam)) { + add(new Label("selectedStatii", getString("gb.all"))); + } else { + add(new Label("selectedStatii", StringUtils.flattenStrings(Arrays.asList(statiiParam), ","))); + } + add(new BookmarkablePageLink("openTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, openStatii, assignedToParam, sortBy, desc, 1))); + add(new BookmarkablePageLink("closedTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, closedStatii, assignedToParam, sortBy, desc, 1))); + add(new BookmarkablePageLink("allTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, null, assignedToParam, sortBy, desc, 1))); + + // by status + List statii = new ArrayList(Arrays.asList(Status.values())); + statii.remove(Status.Closed); + ListDataProvider resolutionsDp = new ListDataProvider(statii); + DataView statiiLinks = new DataView("statii", resolutionsDp) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item item) { + final Status status = item.getModelObject(); + PageParameters p = queryParameters(queryParam, milestoneParam, new String [] { status.name().toLowerCase() }, assignedToParam, sortBy, desc, 1); + String css = getStatusClass(status); + item.add(new LinkPanel("statusLink", css, status.toString(), MyTicketsPage.class, p).setRenderBodyOnly(true)); + } + }; + add(statiiLinks); + + List sortChoices = new ArrayList(); + sortChoices.add(new TicketSort(getString("gb.sortNewest"), Lucene.created.name(), true)); + sortChoices.add(new TicketSort(getString("gb.sortOldest"), Lucene.created.name(), false)); + sortChoices.add(new TicketSort(getString("gb.sortMostRecentlyUpdated"), Lucene.updated.name(), true)); + sortChoices.add(new TicketSort(getString("gb.sortLeastRecentlyUpdated"), Lucene.updated.name(), false)); + sortChoices.add(new TicketSort(getString("gb.sortMostComments"), Lucene.comments.name(), true)); + sortChoices.add(new TicketSort(getString("gb.sortLeastComments"), Lucene.comments.name(), false)); + sortChoices.add(new TicketSort(getString("gb.sortMostPatchsetRevisions"), Lucene.patchsets.name(), true)); + sortChoices.add(new TicketSort(getString("gb.sortLeastPatchsetRevisions"), Lucene.patchsets.name(), false)); + sortChoices.add(new TicketSort(getString("gb.sortMostVotes"), Lucene.votes.name(), true)); + sortChoices.add(new TicketSort(getString("gb.sortLeastVotes"), Lucene.votes.name(), false)); + + TicketSort currentSort = sortChoices.get(0); + for (TicketSort ts : sortChoices) { + if (ts.sortBy.equals(sortBy) && desc == ts.desc) { + currentSort = ts; + break; + } + } + add(new Label("currentSort", currentSort.name)); + + ListDataProvider sortChoicesDp = new ListDataProvider(sortChoices); + DataView sortMenu = new DataView("sort", sortChoicesDp) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item item) { + final TicketSort ts = item.getModelObject(); + PageParameters params = queryParameters(queryParam, milestoneParam, statiiParam, assignedToParam, ts.sortBy, ts.desc, 1); + item.add(new LinkPanel("sortLink", null, ts.name, MyTicketsPage.class, params).setRenderBodyOnly(true)); + } + }; + add(sortMenu); + + // Build Query here + QueryBuilder qb = new QueryBuilder(queryParam); + if (!qb.containsField(Lucene.responsible.name())) { + // specify the responsible + qb.and(Lucene.responsible.matches(assignedToParam)); + } + if (!qb.containsField(Lucene.milestone.name())) { + // specify the milestone + qb.and(Lucene.milestone.matches(milestoneParam)); + } + if (!qb.containsField(Lucene.status.name()) && !ArrayUtils.isEmpty(statiiParam)) { + // specify the states + boolean not = false; + QueryBuilder q = new QueryBuilder(); + for (String state : statiiParam) { + if (state.charAt(0) == '!') { + not = true; + q.and(Lucene.status.doesNotMatch(state.substring(1))); + } else { + q.or(Lucene.status.matches(state)); + } + } + if (not) { + qb.and(q.toString()); + } else { + qb.and(q.toSubquery().toString()); + } + } + final String luceneQuery = qb.build(); ITicketService tickets = GitBlitWebApp.get().tickets(); - List results = tickets.queryFor(qb.build(), 0, 0, Lucene.updated.name(), true); + List results = tickets.queryFor(luceneQuery, 0, 0, Lucene.updated.name(), true); final ListDataProvider dp = new ListDataProvider(results); @@ -100,6 +306,12 @@ public class MyTicketsPage extends RootPage { } }; + // paging links + int page = (params != null) ? Math.max(1, WicketUtils.getPage(params)) : 1; + int pageSize = app().settings().getInteger(Keys.tickets.perPage, 25); + int totalResults = results.size() == 0 ? 0 : results.get(0).totalResults; + buildPager(queryParam, milestoneParam, statiiParam, assignedToParam, sortBy, desc, page, pageSize, results.size(), totalResults); + add(dataView); } @@ -197,4 +409,150 @@ public class MyTicketsPage extends RootPage { return "resolution" + (css.isEmpty() ? "" : " ") + css; } + + private class TicketSort implements Serializable { + + private static final long serialVersionUID = 1L; + + final String name; + final String sortBy; + final boolean desc; + + TicketSort(String name, String sortBy, boolean desc) { + this.name = name; + this.sortBy = sortBy; + this.desc = desc; + } + } + + private class TicketSearchForm extends SessionlessForm implements Serializable { + private static final long serialVersionUID = 1L; + + private final IModel searchBoxModel;; + + public TicketSearchForm(String id, String text) { + super(id, MyTicketsPage.this.getClass(), MyTicketsPage.this.getPageParameters()); + + this.searchBoxModel = new Model(text == null ? "" : text); + + TextField searchBox = new TextField("ticketSearchBox", searchBoxModel); + add(searchBox); + } + + void setTranslatedAttributes() { + WicketUtils.setHtmlTooltip(get("ticketSearchBox"), + MessageFormat.format(getString("gb.searchTicketsTooltip"), "")); + WicketUtils.setInputPlaceholder(get("ticketSearchBox"), getString("gb.searchTickets")); + } + + @Override + public void onSubmit() { + String searchString = searchBoxModel.getObject(); + if (StringUtils.isEmpty(searchString)) { + // redirect to self to avoid wicket page update bug + String absoluteUrl = getCanonicalUrl(); + getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl)); + return; + } + + // use an absolute url to workaround Wicket-Tomcat problems with + // mounted url parameters (issue-111) + PageParameters params = WicketUtils.newRepositoryParameter(""); + params.add("s", searchString); + String absoluteUrl = getCanonicalUrl(MyTicketsPage.class, params); + getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl)); + } + } + + protected PageParameters queryParameters( + String query, + String milestone, + String[] states, + String assignedTo, + String sort, + boolean descending, + int page) { + + PageParameters params = WicketUtils.newRepositoryParameter(""); + if (!StringUtils.isEmpty(query)) { + params.add("q", query); + } + if (!StringUtils.isEmpty(milestone)) { + params.add(Lucene.milestone.name(), milestone); + } + if (!ArrayUtils.isEmpty(states)) { + for (String state : states) { + params.add(Lucene.status.name(), state); + } + } + if (!StringUtils.isEmpty(assignedTo)) { + params.add(Lucene.responsible.name(), assignedTo); + } + if (!StringUtils.isEmpty(sort)) { + params.add("sort", sort); + } + if (!descending) { + params.add("direction", "asc"); + } + if (page > 1) { + params.add("pg", "" + page); + } + return params; + } + + protected void buildPager( + final String query, + final String milestone, + final String [] states, + final String assignedTo, + final String sort, + final boolean desc, + final int page, + int pageSize, + int count, + int total) { + + boolean showNav = total > (2 * pageSize); + boolean allowPrev = page > 1; + boolean allowNext = (pageSize * (page - 1) + count) < total; + add(new BookmarkablePageLink("prevLink", TicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page - 1)).setEnabled(allowPrev).setVisible(showNav)); + add(new BookmarkablePageLink("nextLink", TicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page + 1)).setEnabled(allowNext).setVisible(showNav)); + + if (total <= pageSize) { + add(new Label("pageLink").setVisible(false)); + return; + } + + // determine page numbers to display + int pages = count == 0 ? 0 : ((total / pageSize) + (total % pageSize == 0 ? 0 : 1)); + // preferred number of pagelinks + int segments = 5; + if (pages < segments) { + // not enough data for preferred number of page links + segments = pages; + } + int minpage = Math.min(Math.max(1, page - 2), pages - (segments - 1)); + int maxpage = Math.min(pages, minpage + (segments - 1)); + List sequence = new ArrayList(); + for (int i = minpage; i <= maxpage; i++) { + sequence.add(i); + } + + ListDataProvider pagesDp = new ListDataProvider(sequence); + DataView pagesView = new DataView("pageLink", pagesDp) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item item) { + final Integer i = item.getModelObject(); + LinkPanel link = new LinkPanel("page", null, "" + i, TicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, i)); + link.setRenderBodyOnly(true); + if (i == page) { + WicketUtils.setCssClass(item, "active"); + } + item.add(link); + } + }; + add(pagesView); + } } -- cgit v1.2.3 From 3f5b8f5d9203aa7ffb7fbe9cdbaf9dba3da6cae6 Mon Sep 17 00:00:00 2001 From: Hybris95 Date: Tue, 22 Apr 2014 17:10:33 +0200 Subject: Fixes sort, page building and search functions on "my tickets" page. --- .../com/gitblit/wicket/pages/MyTicketsPage.java | 30 ++++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 01a30181..32cdaec3 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -61,7 +61,7 @@ public class MyTicketsPage extends RootPage { } final String username = currentUser.getName(); - final String[] statiiParam = (params == null) ? new String[0] : params.getStringArray(Lucene.status.name()); + final String[] statiiParam = (params == null) ? openStatii : params.getStringArray(Lucene.status.name()); final String assignedToParam = (params == null) ? "" : params.getString(Lucene.responsible.name(), null); final String milestoneParam = (params == null) ? "" : params.getString(Lucene.milestone.name(), null); final String queryParam = (params == null || StringUtils.isEmpty(params.getString("q", null))) ? "watchedby:" + username : params.getString("q", null); @@ -256,8 +256,22 @@ public class MyTicketsPage extends RootPage { } final String luceneQuery = qb.build(); + // paging links + int page = (params != null) ? Math.max(1, WicketUtils.getPage(params)) : 1; + int pageSize = app().settings().getInteger(Keys.tickets.perPage, 25); + ITicketService tickets = GitBlitWebApp.get().tickets(); - List results = tickets.queryFor(luceneQuery, 0, 0, Lucene.updated.name(), true); + List results; + if(StringUtils.isEmpty(searchParam)) + { + results = tickets.queryFor(luceneQuery, page, pageSize, sortBy, desc); + } + else + { + results = tickets.searchFor(null, searchParam, page, pageSize); + } + int totalResults = results.size() == 0 ? 0 : results.get(0).totalResults; + buildPager(queryParam, milestoneParam, statiiParam, assignedToParam, sortBy, desc, page, pageSize, results.size(), totalResults); final ListDataProvider dp = new ListDataProvider(results); @@ -306,12 +320,6 @@ public class MyTicketsPage extends RootPage { } }; - // paging links - int page = (params != null) ? Math.max(1, WicketUtils.getPage(params)) : 1; - int pageSize = app().settings().getInteger(Keys.tickets.perPage, 25); - int totalResults = results.size() == 0 ? 0 : results.get(0).totalResults; - buildPager(queryParam, milestoneParam, statiiParam, assignedToParam, sortBy, desc, page, pageSize, results.size(), totalResults); - add(dataView); } @@ -515,8 +523,8 @@ public class MyTicketsPage extends RootPage { boolean showNav = total > (2 * pageSize); boolean allowPrev = page > 1; boolean allowNext = (pageSize * (page - 1) + count) < total; - add(new BookmarkablePageLink("prevLink", TicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page - 1)).setEnabled(allowPrev).setVisible(showNav)); - add(new BookmarkablePageLink("nextLink", TicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page + 1)).setEnabled(allowNext).setVisible(showNav)); + add(new BookmarkablePageLink("prevLink", MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page - 1)).setEnabled(allowPrev).setVisible(showNav)); + add(new BookmarkablePageLink("nextLink", MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page + 1)).setEnabled(allowNext).setVisible(showNav)); if (total <= pageSize) { add(new Label("pageLink").setVisible(false)); @@ -545,7 +553,7 @@ public class MyTicketsPage extends RootPage { @Override public void populateItem(final Item item) { final Integer i = item.getModelObject(); - LinkPanel link = new LinkPanel("page", null, "" + i, TicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, i)); + LinkPanel link = new LinkPanel("page", null, "" + i, MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, i)); link.setRenderBodyOnly(true); if (i == page) { WicketUtils.setCssClass(item, "active"); -- cgit v1.2.3 From 6f9908aa9ebcdfbb32e8305b157be177071abe56 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 24 Apr 2014 14:05:36 -0400 Subject: Do not display My Tickets link if ticket service is not ready --- src/main/java/com/gitblit/wicket/pages/RootPage.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index a4d2353d..fb68208f 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -172,13 +172,12 @@ public abstract class RootPage extends BasePage { if (!authenticateView || (authenticateView && isLoggedIn)) { pages.add(new PageRegistration(isLoggedIn ? "gb.myDashboard" : "gb.dashboard", MyDashboardPage.class, getRootPageParameters())); + if (isLoggedIn && app().tickets().isReady()) { + pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class)); + } pages.add(new PageRegistration("gb.repositories", RepositoriesPage.class, getRootPageParameters())); pages.add(new PageRegistration("gb.activity", ActivityPage.class, getRootPageParameters())); - if(isLoggedIn) - { - pages.add(new PageRegistration("gb.mytickets", MyTicketsPage.class, getRootPageParameters())); - } if (allowLucene) { pages.add(new PageRegistration("gb.search", LuceneSearchPage.class)); } -- cgit v1.2.3 From b3f70e7ed4b4c59fc578f529411f41e3fd6b192f Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 24 Apr 2014 14:06:36 -0400 Subject: Improve generated Lucene query to only show relevant My Tickets results --- .../com/gitblit/wicket/pages/MyTicketsPage.java | 67 ++++++++++++---------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java index 32cdaec3..083526b6 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java @@ -21,9 +21,9 @@ import org.apache.wicket.request.target.basic.RedirectRequestTarget; import com.gitblit.Keys; import com.gitblit.models.RepositoryModel; import com.gitblit.models.TicketModel; -import com.gitblit.models.UserModel; import com.gitblit.models.TicketModel.Status; import com.gitblit.models.TicketModel.Type; +import com.gitblit.models.UserModel; import com.gitblit.tickets.ITicketService; import com.gitblit.tickets.QueryBuilder; import com.gitblit.tickets.QueryResult; @@ -42,24 +42,24 @@ public class MyTicketsPage extends RootPage { public static final String [] openStatii = new String [] { Status.New.name().toLowerCase(), Status.Open.name().toLowerCase() }; public static final String [] closedStatii = new String [] { "!" + Status.New.name().toLowerCase(), "!" + Status.Open.name().toLowerCase() }; - + public MyTicketsPage() { - this(null); + this(null); } - + public MyTicketsPage(PageParameters params) { super(params); setupPage("", getString("gb.mytickets")); - + UserModel currentUser = GitBlitWebSession.get().getUser(); if (currentUser == null) { setRedirect(true); setResponsePage(getApplication().getHomePage()); return; } - + final String username = currentUser.getName(); final String[] statiiParam = (params == null) ? openStatii : params.getStringArray(Lucene.status.name()); final String assignedToParam = (params == null) ? "" : params.getString(Lucene.responsible.name(), null); @@ -68,12 +68,12 @@ public class MyTicketsPage extends RootPage { final String searchParam = (params == null) ? "" : params.getString("s", null); final String sortBy = (params == null) ? "" : Lucene.fromString(params.getString("sort", Lucene.created.name())).name(); final boolean desc = (params == null) ? true : !"asc".equals(params.getString("direction", "desc")); - + // add search form TicketSearchForm searchForm = new TicketSearchForm("ticketSearchForm", searchParam); add(searchForm); searchForm.setTranslatedAttributes(); - + // standard queries add(new BookmarkablePageLink("changesQuery", MyTicketsPage.class, queryParameters( @@ -164,7 +164,7 @@ public class MyTicketsPage extends RootPage { sortBy, desc, 1))); - + // states if (ArrayUtils.isEmpty(statiiParam)) { add(new Label("selectedStatii", getString("gb.all"))); @@ -174,7 +174,7 @@ public class MyTicketsPage extends RootPage { add(new BookmarkablePageLink("openTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, openStatii, assignedToParam, sortBy, desc, 1))); add(new BookmarkablePageLink("closedTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, closedStatii, assignedToParam, sortBy, desc, 1))); add(new BookmarkablePageLink("allTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, null, assignedToParam, sortBy, desc, 1))); - + // by status List statii = new ArrayList(Arrays.asList(Status.values())); statii.remove(Status.Closed); @@ -225,17 +225,9 @@ public class MyTicketsPage extends RootPage { } }; add(sortMenu); - + // Build Query here QueryBuilder qb = new QueryBuilder(queryParam); - if (!qb.containsField(Lucene.responsible.name())) { - // specify the responsible - qb.and(Lucene.responsible.matches(assignedToParam)); - } - if (!qb.containsField(Lucene.milestone.name())) { - // specify the milestone - qb.and(Lucene.milestone.matches(milestoneParam)); - } if (!qb.containsField(Lucene.status.name()) && !ArrayUtils.isEmpty(statiiParam)) { // specify the states boolean not = false; @@ -254,12 +246,27 @@ public class MyTicketsPage extends RootPage { qb.and(q.toSubquery().toString()); } } - final String luceneQuery = qb.build(); - + + final String luceneQuery; + if (qb.containsField(Lucene.createdby.name()) + || qb.containsField(Lucene.responsible.name()) + || qb.containsField(Lucene.watchedby.name())) { + // focused "my tickets" query + luceneQuery = qb.build(); + } else { + // general "my tickets" query + QueryBuilder myQuery = new QueryBuilder(); + myQuery.or(Lucene.createdby.matches(username)); + myQuery.or(Lucene.responsible.matches(username)); + myQuery.or(Lucene.watchedby.matches(username)); + myQuery.and(qb.toSubquery().toString()); + luceneQuery = myQuery.build(); + } + // paging links int page = (params != null) ? Math.max(1, WicketUtils.getPage(params)) : 1; int pageSize = app().settings().getInteger(Keys.tickets.perPage, 25); - + ITicketService tickets = GitBlitWebApp.get().tickets(); List results; if(StringUtils.isEmpty(searchParam)) @@ -272,9 +279,9 @@ public class MyTicketsPage extends RootPage { } int totalResults = results.size() == 0 ? 0 : results.get(0).totalResults; buildPager(queryParam, milestoneParam, statiiParam, assignedToParam, sortBy, desc, page, pageSize, results.size(), totalResults); - + final ListDataProvider dp = new ListDataProvider(results); - + DataView dataView = new DataView("row", dp) { private static final long serialVersionUID = 1L; @@ -282,15 +289,15 @@ public class MyTicketsPage extends RootPage { protected void populateItem(Item item) { QueryResult ticket = item.getModelObject(); RepositoryModel repository = app().repositories().getRepositoryModel(ticket.repository); - + Component swatch = new Label("repositorySwatch", " ").setEscapeModelStrings(false); WicketUtils.setCssBackground(swatch, repository.toString()); item.add(swatch); - + PageParameters rp = WicketUtils.newRepositoryParameter(ticket.repository); PageParameters tp = WicketUtils.newObjectParameter(ticket.repository, "" + ticket.number); item.add(new LinkPanel("repositoryName", "list", StringUtils.stripDotGit(ticket.repository), SummaryPage.class, rp)); - + item.add(getStateIcon("ticketIcon", ticket.type, ticket.status)); item.add(new Label("ticketNumber", "" + ticket.number)); item.add(new LinkPanel("ticketTitle", "list", ticket.title, TicketsPage.class, tp)); @@ -304,7 +311,7 @@ public class MyTicketsPage extends RootPage { String statusClass = getStatusClass(ticket.status); WicketUtils.setCssClass(ticketStatus, statusClass); item.add(ticketStatus); - + UserModel responsible = app().users().getUserModel(ticket.responsible); if (responsible == null) { if (ticket.responsible == null) { @@ -319,10 +326,10 @@ public class MyTicketsPage extends RootPage { } } }; - + add(dataView); } - + protected Label getStateIcon(String wicketId, TicketModel ticket) { return getStateIcon(wicketId, ticket.type, ticket.status); } -- cgit v1.2.3 From 4062e46eb07c4202d8872ecc02eb246304dda01e Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 24 Apr 2014 15:16:51 -0400 Subject: Revise My Tickets layout and styling --- .../com/gitblit/wicket/pages/MyTicketsPage.html | 183 ++++++++++-------- .../com/gitblit/wicket/pages/MyTicketsPage.java | 209 ++++++++++++++++++--- src/main/resources/gitblit.css | 48 ----- 3 files changed, 290 insertions(+), 150 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html index 459d2551..9ecc4b6e 100644 --- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html +++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html @@ -8,94 +8,123 @@
- -
- @@ -41,9 +40,6 @@ This is what you should download if you want to go from zero to Git in less than ### WAR: For Your Servlet Container *Gitblit WAR* is what you should download if you already have a servlet container available that you wish to use. Jetty 6/7/8 and Tomcat 6/7 are known to work. Generally, any Servlet 2.5 or Servlet 3.0 container should work. -### Express: For the Cloud -*Gitblit Express* is a prepared distribution for [RedHat's OpenShift][rhcloud] cloud service. - ### You decide how to use Gitblit Gitblit can be used as a dumb repository viewer with no administrative controls or user accounts. @@ -81,4 +77,3 @@ Gitblit requires a Java 7 Runtime Environment (JRE) or a Java 7 Development Kit [jgit]: http://eclipse.org/jgit "Eclipse JGit Site" [git]: http://git-scm.com "Official Git Site" -[rhcloud]: https://openshift.redhat.com/app "RedHat OpenShift" diff --git a/src/site/upgrade_express.mkd b/src/site/upgrade_express.mkd deleted file mode 100644 index 9e1eed9d..00000000 --- a/src/site/upgrade_express.mkd +++ /dev/null @@ -1,23 +0,0 @@ -## Upgrading Gitblit Express - -1. Make a backup copy of */deployments/ROOT.war/WEB-INF/web.xml* -2. Delete your */deployments/ROOT.war* and then copy the new */deployments/ROOT.war* from the archive. -3. Diff your backup copy of web.xml with the pristine one you copied as part of */deployments/ROOT.war* and apply any necessary changes. - -These steps are necessary to ensure that you end up using the specified libraries and resources for the new version. Otherwise you could end up with a hybrid filesystem that would make it difficult to troubleshoot. It is important to note that the web.xml file contains both your default settings AND application configuration. Not updating the web.xml is just a likely to create problems as making a hybrid filesystem. - -### 1.3.1 web.xml - -- Changed *WicketFilter* to *GitblitWicketFilter* to handle optional, smart cache-control updates (issue-274) - -### 1.3.0 web.xml - -- Added LogoServlet -- Added SparkleShareInviteServlet -- Added EnforceAuthenticationFilter -- Moved GitServlet - -### 1.4.0 web.xml - -- Changed baseFolder from a context-parameter to a JNDI env-entry -- Added pt servlet \ No newline at end of file -- cgit v1.2.3 From b5e11d843b83261376552dd6fc26d346c82402a4 Mon Sep 17 00:00:00 2001 From: James Moger Date: Fri, 23 May 2014 11:39:06 -0400 Subject: Do not directly link to the EmptyRepositoryPage --- .../java/com/gitblit/wicket/panels/RepositoriesPanel.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java index d8e23bea..dd208e23 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java @@ -52,7 +52,6 @@ import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.pages.BasePage; import com.gitblit.wicket.pages.EditRepositoryPage; -import com.gitblit.wicket.pages.EmptyRepositoryPage; import com.gitblit.wicket.pages.ProjectPage; import com.gitblit.wicket.pages.RepositoriesPage; import com.gitblit.wicket.pages.SummaryPage; @@ -204,15 +203,7 @@ public class RepositoriesPanel extends BasePanel { swatch.setVisible(showSwatch); if (linksActive) { - Class linkPage; - if (entry.hasCommits) { - // repository has content - linkPage = SummaryPage.class; - } else { - // new/empty repository OR proposed repository - linkPage = EmptyRepositoryPage.class; - } - + Class linkPage = SummaryPage.class; PageParameters pp = WicketUtils.newRepositoryParameter(entry.name); row.add(new LinkPanel("repositoryName", "list", repoName, linkPage, pp)); row.add(new LinkPanel("repositoryDescription", "list", entry.description, -- cgit v1.2.3 From 099a5d0e70db99467dab25f9be11d6fd136e1906 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 29 May 2014 10:50:32 -0400 Subject: Documentation --- releases.moxie | 2 ++ 1 file changed, 2 insertions(+) diff --git a/releases.moxie b/releases.moxie index 1ca462ea..6d02997c 100644 --- a/releases.moxie +++ b/releases.moxie @@ -16,6 +16,8 @@ r24: { - Fix repository cache refresh after ref deletion/addition (issue-433, ticket-82) - Fixed cache miss on repository model retrieval (pr-185, ticket-83) - Fixed GitBlit static singleton reference in localclone.groovy (issue-436, ticket-84) + - Removed Ticket responsible team permission exclusion (ticket-87) + - Fixed Ticket responsible selections not considering the AUTHENTICATED authorization control (ticket-91) changes: - Split the pages servlet into a raw servlet and a pages servlet. All raw links now use the raw servlet (issue-413, ticket-49) - Drop deprecated --set-upstream syntax for -u (ticket-59) -- cgit v1.2.3 From 4bdf5a568311796772b46efc6e6ce30e10a01757 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 29 May 2014 12:26:39 -0400 Subject: Documentation --- releases.moxie | 1 + 1 file changed, 1 insertion(+) diff --git a/releases.moxie b/releases.moxie index 6d02997c..34f855bc 100644 --- a/releases.moxie +++ b/releases.moxie @@ -17,6 +17,7 @@ r24: { - Fixed cache miss on repository model retrieval (pr-185, ticket-83) - Fixed GitBlit static singleton reference in localclone.groovy (issue-436, ticket-84) - Removed Ticket responsible team permission exclusion (ticket-87) + - Fixed SSH daemon thread exhaustion (ticket-89) - Fixed Ticket responsible selections not considering the AUTHENTICATED authorization control (ticket-91) changes: - Split the pages servlet into a raw servlet and a pages servlet. All raw links now use the raw servlet (issue-413, ticket-49) -- cgit v1.2.3 From fb9cd5968346045e1129406ca54639075316a396 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 29 May 2014 12:40:35 -0400 Subject: Add setting to control thread pool size for default work queue --- releases.moxie | 2 ++ src/main/distrib/data/gitblit.properties | 6 ++++++ src/main/java/com/gitblit/manager/ServicesManager.java | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/releases.moxie b/releases.moxie index 34f855bc..4332238d 100644 --- a/releases.moxie +++ b/releases.moxie @@ -38,6 +38,7 @@ r24: { - Add setting to allow STARTTLS without requiring SMTPS (pr-183) - Added an extension point for monitoring onStartup and onShutdown (ticket-79) - Tag server-side merges when incremental push tags are enabled (issue-432, ticket-85) + - Add setting to control default thread pool size for miscellaneous background tasks (ticket-92) dependencyChanges: - Update to javax.mail 1.5.1 (issue-417, ticket-58) contributors: @@ -53,6 +54,7 @@ r24: { settings: - { name: 'web.allowDeletingNonEmptyRepositories', defaultValue: 'true' } - { name: 'mail.starttls', defaultValue: 'false' } + - { name: 'execution.defaultThreadPoolSize', defaultValue: '1' } } # diff --git a/src/main/distrib/data/gitblit.properties b/src/main/distrib/data/gitblit.properties index 7d74c281..b27395c3 100644 --- a/src/main/distrib/data/gitblit.properties +++ b/src/main/distrib/data/gitblit.properties @@ -613,6 +613,12 @@ plugins.folder = ${baseFolder}/plugins # SINCE 1.5.0 plugins.registry = http://plugins.gitblit.com/plugins.json +# Number of threads used to handle miscellaneous tasks in the background. +# +# SINCE 1.6.0 +# RESTART REQUIRED +execution.defaultThreadPoolSize = 1 + # # Groovy Integration # diff --git a/src/main/java/com/gitblit/manager/ServicesManager.java b/src/main/java/com/gitblit/manager/ServicesManager.java index b1c97ba4..755d8bac 100644 --- a/src/main/java/com/gitblit/manager/ServicesManager.java +++ b/src/main/java/com/gitblit/manager/ServicesManager.java @@ -80,8 +80,9 @@ public class ServicesManager implements IManager { public ServicesManager(IGitblit gitblit) { this.settings = gitblit.getSettings(); this.gitblit = gitblit; + int defaultThreadPoolSize = settings.getInteger(Keys.execution.defaultThreadPoolSize, 1); this.idGenerator = new IdGenerator(); - this.workQueue = new WorkQueue(idGenerator, 1); + this.workQueue = new WorkQueue(idGenerator, defaultThreadPoolSize); } @Override -- cgit v1.2.3 From 9eff8aa74221277d878c174840e4cefdc9e954d8 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 29 May 2014 17:14:58 -0400 Subject: Clarify server.threadPoolSize documentation --- src/main/distrib/data/gitblit.properties | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/distrib/data/gitblit.properties b/src/main/distrib/data/gitblit.properties index b27395c3..6f55a3eb 100644 --- a/src/main/distrib/data/gitblit.properties +++ b/src/main/distrib/data/gitblit.properties @@ -1795,7 +1795,8 @@ realm.ldap.removeDeletedUsers = true realm.redmine.url = http://example.com/redmine # -# Server Settings +# Gitblit GO Server Settings +# The following settings only affect the integrated GO variant. # # The temporary folder to decompress the embedded gitblit webapp. @@ -1805,7 +1806,9 @@ realm.redmine.url = http://example.com/redmine # BASEFOLDER server.tempFolder = ${baseFolder}/temp -# Specify the maximum number of concurrent http/https worker threads to allow. +# Specify the maximum number of concurrent http/https Jetty worker +# threads to allow. This setting does not affect other threaded +# daemons and components of Gitblit. # # SINCE 1.3.0 # RESTART REQUIRED -- cgit v1.2.3 From 0047fbba99b804d268a66ed7504a568596de6168 Mon Sep 17 00:00:00 2001 From: James Moger Date: Tue, 27 May 2014 18:13:30 -0400 Subject: Simplified repository creation with a NewRepositoryPage --- .gitmodules | 3 + build.xml | 6 + releases.moxie | 2 + src/main/distrib/data/gitblit.properties | 5 + src/main/distrib/data/gitignore | 1 + src/main/java/com/gitblit/Constants.java | 8 + .../java/com/gitblit/servlet/GitblitContext.java | 16 + .../java/com/gitblit/wicket/GitBlitWebApp.java | 10 + .../com/gitblit/wicket/GitBlitWebApp.properties | 17 +- .../gitblit/wicket/pages/EditRepositoryPage.java | 16 +- .../gitblit/wicket/pages/NewRepositoryPage.html | 98 ++++ .../gitblit/wicket/pages/NewRepositoryPage.java | 493 +++++++++++++++++++++ .../java/com/gitblit/wicket/pages/RootPage.java | 2 +- .../java/com/gitblit/wicket/pages/UserPage.java | 4 +- .../wicket/panels/FilterableRepositoryList.java | 3 +- .../gitblit/wicket/panels/RepositoriesPanel.java | 5 +- 16 files changed, 674 insertions(+), 15 deletions(-) create mode 100644 .gitmodules create mode 160000 src/main/distrib/data/gitignore create mode 100644 src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html create mode 100644 src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..01eaa2c8 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/main/distrib/data/gitignore"] + path = src/main/distrib/data/gitignore + url = https://github.com/github/gitignore.git diff --git a/build.xml b/build.xml index f45c4ca9..be6f1dd2 100644 --- a/build.xml +++ b/build.xml @@ -919,6 +919,12 @@ + + + + + + diff --git a/releases.moxie b/releases.moxie index 4332238d..5aa207fa 100644 --- a/releases.moxie +++ b/releases.moxie @@ -36,6 +36,7 @@ r24: { - Add FORK_REPOSITORY RPC request type (issue-371, pr-161, ticket-65) - Add object type (ot) parameter for RSS queries to retrieve tag details (pr-165, ticket-66) - Add setting to allow STARTTLS without requiring SMTPS (pr-183) + - Simplified repository creation, offer simple README generation, and insertion of a pre-defined .gitignore file (ticket-76) - Added an extension point for monitoring onStartup and onShutdown (ticket-79) - Tag server-side merges when incremental push tags are enabled (issue-432, ticket-85) - Add setting to control default thread pool size for miscellaneous background tasks (ticket-92) @@ -55,6 +56,7 @@ r24: { - { name: 'web.allowDeletingNonEmptyRepositories', defaultValue: 'true' } - { name: 'mail.starttls', defaultValue: 'false' } - { name: 'execution.defaultThreadPoolSize', defaultValue: '1' } + - { name: 'git.gitignoreFolder', defaultValue: '${baseFolder}/gitignore' } } # diff --git a/src/main/distrib/data/gitblit.properties b/src/main/distrib/data/gitblit.properties index 6f55a3eb..d5623cd5 100644 --- a/src/main/distrib/data/gitblit.properties +++ b/src/main/distrib/data/gitblit.properties @@ -271,6 +271,11 @@ git.defaultIncrementalPushTagPrefix = r # SINCE 1.4.0 git.createRepositoriesShared = false +# Directory for gitignore templates used during repository creation. +# +# SINCE 1.6.0 +git.gitignoreFolder = ${baseFolder}/gitignore + # Enable JGit-based garbage collection. (!!EXPERIMENTAL!!) # # USE AT YOUR OWN RISK! diff --git a/src/main/distrib/data/gitignore b/src/main/distrib/data/gitignore new file mode 160000 index 00000000..097db81c --- /dev/null +++ b/src/main/distrib/data/gitignore @@ -0,0 +1 @@ +Subproject commit 097db81c08b138dea7cb031eb18eeb16afe44bdf diff --git a/src/main/java/com/gitblit/Constants.java b/src/main/java/com/gitblit/Constants.java index 95eb944a..3e307537 100644 --- a/src/main/java/com/gitblit/Constants.java +++ b/src/main/java/com/gitblit/Constants.java @@ -122,6 +122,14 @@ public class Constants { public static final String R_TICKETS_PATCHSETS = "refs/tickets/"; + public static final String R_MASTER = "refs/heads/master"; + + public static final String MASTER = "master"; + + public static final String R_DEVELOP = "refs/heads/develop"; + + public static final String DEVELOP = "develop"; + public static String getVersion() { String v = Constants.class.getPackage().getImplementationVersion(); if (v == null) { diff --git a/src/main/java/com/gitblit/servlet/GitblitContext.java b/src/main/java/com/gitblit/servlet/GitblitContext.java index 110e553c..50f22d5a 100644 --- a/src/main/java/com/gitblit/servlet/GitblitContext.java +++ b/src/main/java/com/gitblit/servlet/GitblitContext.java @@ -372,6 +372,22 @@ public class GitblitContext extends DaggerContext { } } + // Copy the included gitignore files to the configured gitignore folder + String gitignorePath = webxmlSettings.getString(Keys.git.gitignoreFolder, "gitignore"); + File localGitignores = com.gitblit.utils.FileUtils.resolveParameter(Constants.baseFolder$, base, gitignorePath); + if (!localGitignores.exists()) { + File warGitignores = new File(contextFolder, "/WEB-INF/data/gitignore"); + if (!warGitignores.equals(localGitignores)) { + try { + com.gitblit.utils.FileUtils.copy(localGitignores, warGitignores.listFiles()); + } catch (IOException e) { + logger.error(MessageFormat.format( + "Failed to copy included .gitignore files from {0} to {1}", + warGitignores, localGitignores)); + } + } + } + // merge the WebXmlSettings into the runtime settings (for backwards-compatibilty) runtimeSettings.merge(webxmlSettings); diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java index 7291d039..f63ff3d9 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.java +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.java @@ -57,6 +57,7 @@ import com.gitblit.wicket.pages.ComparePage; import com.gitblit.wicket.pages.DocPage; import com.gitblit.wicket.pages.DocsPage; import com.gitblit.wicket.pages.EditMilestonePage; +import com.gitblit.wicket.pages.EditRepositoryPage; import com.gitblit.wicket.pages.EditTicketPage; import com.gitblit.wicket.pages.ExportTicketPage; import com.gitblit.wicket.pages.FederationRegistrationPage; @@ -71,6 +72,7 @@ import com.gitblit.wicket.pages.MetricsPage; import com.gitblit.wicket.pages.MyDashboardPage; import com.gitblit.wicket.pages.MyTicketsPage; import com.gitblit.wicket.pages.NewMilestonePage; +import com.gitblit.wicket.pages.NewRepositoryPage; import com.gitblit.wicket.pages.NewTicketPage; import com.gitblit.wicket.pages.OverviewPage; import com.gitblit.wicket.pages.PatchPage; @@ -92,6 +94,8 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp { private final Class homePageClass = MyDashboardPage.class; + private final Class newRepositoryPageClass = NewRepositoryPage.class; + private final Map cacheablePages = new HashMap(); private final IStoredSettings settings; @@ -207,6 +211,8 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp { mount("/proposal", ReviewProposalPage.class, "t"); mount("/registration", FederationRegistrationPage.class, "u", "n"); + mount("/new", NewRepositoryPage.class); + mount("/edit", EditRepositoryPage.class, "r"); mount("/activity", ActivityPage.class, "r", "h"); mount("/lucene", LuceneSearchPage.class); mount("/project", ProjectPage.class, "p"); @@ -262,6 +268,10 @@ public class GitBlitWebApp extends WebApplication implements GitblitWicketApp { return homePageClass; } + public Class getNewRepositoryPage() { + return newRepositoryPageClass; + } + /* (non-Javadoc) * @see com.gitblit.wicket.Webapp#isCacheablePage(java.lang.String) */ diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 12430ade..ac589558 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -685,4 +685,19 @@ gb.closedMilestones = closed milestones gb.administration = administration gb.plugins = plugins gb.extensions = extensions - +gb.anonymous = Anonymous +gb.anonymousRepoDescription = Anyone can see, clone, and push to this repository. +gb.public = Public +gb.publicRepoDescription = Anyone can see and clone this repository. You choose who can push. +gb.protected = Protected +gb.protectedRepoDescription = Anyone can see this repository. You choose who can clone and push. +gb.private = Private +gb.privateRepoDescription = You choose who can see, clone, and push to this repository. +gb.initialCommit = Initial Commit +gb.initialCommitDescription = This will allow you to git clone this repository immediately. Skip this step if you have already run git init locally. +gb.initWithReadme = Include a README +gb.initWithReadmeDescription = This will generate a simple README document for your repository. +gb.initWithGitignore = Include a .gitignore file +gb.initWithGitignoreDescription = This will insert a config file that instructs your Git clients to ignore files or directories that match defined patterns. +gb.initWithGitflow = Include a .gitflow file +gb.initWithGitflowDescription = This will generate a config file which guides Git clients in setting up Gitflow branches. \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java index 412c0ecc..c18cd514 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -429,11 +429,7 @@ public class EditRepositoryPage extends RootSubPage { return; } setRedirect(false); - if (isCreate) { - setResponsePage(RepositoriesPage.class); - } else { - setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryModel.name)); - } + setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryModel.name)); } }; @@ -632,7 +628,15 @@ public class EditRepositoryPage extends RootSubPage { if (canDelete) { if (app().repositories().deleteRepositoryModel(latestModel)) { info(MessageFormat.format(getString("gb.repositoryDeleted"), latestModel)); - setResponsePage(RepositoriesPage.class); + if (latestModel.isPersonalRepository()) { + // redirect to user's profile page + String prefix = app().settings().getString(Keys.git.userRepositoryPrefix, "~"); + String username = latestModel.projectPath.substring(prefix.length()); + setResponsePage(UserPage.class, WicketUtils.newUsernameParameter(username)); + } else { + // redirect to server repositories page + setResponsePage(RepositoriesPage.class); + } } else { error(MessageFormat.format(getString("gb.repositoryDeleteFailed"), latestModel)); } diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html new file mode 100644 index 00000000..e9f12027 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html @@ -0,0 +1,98 @@ + + + + + +
+
+
+ + + + + + + + + + + + + + +
/  
+ +
+
+ +
+ +
+ + +
+
+ + +
+
+
+ +
+
+
+ +
+ +

+
+

+
+ +
+
+ +
+
+
+

+
+
+ +
+ +
+ +
+
+ +

+
+
+ +
+
+ +
+
+
+

+

+
+
+ + + + + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java new file mode 100644 index 00000000..b0cc3e95 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java @@ -0,0 +1,493 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.pages; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; +import org.apache.wicket.behavior.SimpleAttributeModifier; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.Button; +import org.apache.wicket.markup.html.form.CheckBox; +import org.apache.wicket.markup.html.form.DropDownChoice; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.Radio; +import org.apache.wicket.markup.html.form.RadioGroup; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.model.CompoundPropertyModel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheBuilder; +import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.lib.CommitBuilder; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectInserter; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.RefUpdate; +import org.eclipse.jgit.lib.RefUpdate.Result; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; + +import com.gitblit.Constants; +import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.GitBlitException; +import com.gitblit.Keys; +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.UserModel; +import com.gitblit.utils.ArrayUtils; +import com.gitblit.utils.FileUtils; +import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.GitBlitWebSession; +import com.gitblit.wicket.WicketUtils; + +public class NewRepositoryPage extends RootSubPage { + + private final RepositoryModel repositoryModel; + private RadioGroup permissionGroup; + private IModel addReadmeModel; + private Model gitignoreModel; + private IModel addGitflowModel; + private IModel addGitignoreModel; + + public NewRepositoryPage() { + // create constructor + super(); + repositoryModel = new RepositoryModel(); + + setupPage(getString("gb.newRepository"), ""); + + setStatelessHint(false); + setOutputMarkupId(true); + } + + @Override + protected boolean requiresPageMap() { + return true; + } + + @Override + protected Class getRootNavPageClass() { + return RepositoriesPage.class; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + CompoundPropertyModel rModel = new CompoundPropertyModel<>(repositoryModel); + Form form = new Form("editForm", rModel) { + + private static final long serialVersionUID = 1L; + + @Override + protected void onSubmit() { + + // confirm a repository name was entered + if (StringUtils.isEmpty(repositoryModel.name)) { + error(getString("gb.pleaseSetRepositoryName")); + return; + } + + String project = repositoryModel.projectPath; + String fullName = (project + "/" + repositoryModel.name).trim(); + fullName = fullName.replace('\\', '/'); + fullName = fullName.replace("//", "/"); + if (fullName.charAt(0) == '/') { + fullName = fullName.substring(1); + } + if (fullName.endsWith("/")) { + fullName = fullName.substring(0, fullName.length() - 1); + } + + try { + if (fullName.contains("../")) { + error(getString("gb.illegalRelativeSlash")); + return; + } + if (fullName.contains("/../")) { + error(getString("gb.illegalRelativeSlash")); + return; + } + + // confirm valid characters in repository name + Character c = StringUtils.findInvalidCharacter(fullName); + if (c != null) { + error(MessageFormat.format(getString("gb.illegalCharacterRepositoryName"), + c)); + return; + } + + repositoryModel.name = fullName; + repositoryModel.projectPath = null; + + Permission permisison = permissionGroup.getModelObject(); + repositoryModel.accessRestriction = permisison.type; + repositoryModel.authorizationControl = AuthorizationControl.NAMED; + + repositoryModel.owners = new ArrayList(); + repositoryModel.owners.add(GitBlitWebSession.get().getUsername()); + + // setup branch defaults + boolean useGitFlow = addGitflowModel.getObject(); + + repositoryModel.HEAD = Constants.R_MASTER; + repositoryModel.mergeTo = Constants.MASTER; + if (useGitFlow) { + // tickets normally merge to develop unless they are hotfixes + repositoryModel.mergeTo = Constants.DEVELOP; + } + + repositoryModel.allowForks = app().settings().getBoolean(Keys.web.allowForking, true); + + // optionally generate an initial commit + boolean addReadme = addReadmeModel.getObject(); + String gitignore = null; + boolean addGitignore = addGitignoreModel.getObject(); + if (addGitignore) { + gitignore = gitignoreModel.getObject(); + if (StringUtils.isEmpty(gitignore)) { + throw new GitBlitException("Please select a .gitignore file"); + } + } + + // init the repository + app().gitblit().updateRepositoryModel(repositoryModel.name, repositoryModel, true); + + // optionally create an initial commit + initialCommit(repositoryModel, addReadme, gitignore, useGitFlow); + + } catch (GitBlitException e) { + error(e.getMessage()); + + // restore project and name fields on error condition + repositoryModel.projectPath = StringUtils.getFirstPathElement(fullName); + if (!StringUtils.isEmpty(repositoryModel.projectPath)) { + repositoryModel.name = fullName.substring(repositoryModel.projectPath.length() + 1); + } + return; + } + setRedirect(true); + setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(fullName)); + } + }; + + GitBlitWebSession session = GitBlitWebSession.get(); + UserModel user = session.getUser(); + + // build project list for repository destination + String defaultProject = null; + List projects = new ArrayList(); + + if (user.canAdmin()) { + String main = app().settings().getString(Keys.web.repositoryRootGroupName, "main"); + projects.add(main); + defaultProject = main; + } + + if (user.canCreate()) { + projects.add(user.getPersonalPath()); + if (defaultProject == null) { + // only prefer personal namespace if default is not already set + defaultProject = user.getPersonalPath(); + } + } + + repositoryModel.projectPath = defaultProject; + + // do not let the browser pre-populate these fields + form.add(new SimpleAttributeModifier("autocomplete", "off")); + + form.add(new DropDownChoice("projectPath", projects)); + form.add(new TextField("name")); + form.add(new TextField("description")); + + Permission anonymousPermission = new Permission(getString("gb.anonymous"), getString("gb.anonymousRepoDescription"), "blank.png", AccessRestrictionType.NONE); + Permission publicPermission = new Permission(getString("gb.public"), getString("gb.publicRepoDescription"), "lock_go_16x16.png", AccessRestrictionType.PUSH); + Permission protectedPermission = new Permission(getString("gb.protected"), getString("gb.protectedRepoDescription"), "lock_pull_16x16.png", AccessRestrictionType.CLONE); + Permission privatePermission = new Permission(getString("gb.private"), getString("gb.privateRepoDescription"), "shield_16x16.png", AccessRestrictionType.VIEW); + + List permissions = new ArrayList(); + if (app().settings().getBoolean(Keys.git.allowAnonymousPushes, false)) { + permissions.add(anonymousPermission); + } + permissions.add(publicPermission); + permissions.add(protectedPermission); + permissions.add(privatePermission); + + // determine default permission selection + AccessRestrictionType defaultRestriction = AccessRestrictionType.fromName( + app().settings().getString(Keys.git.defaultAccessRestriction, AccessRestrictionType.PUSH.name())); + if (AccessRestrictionType.NONE == defaultRestriction) { + defaultRestriction = AccessRestrictionType.PUSH; + } + + Permission defaultPermission = publicPermission; + for (Permission permission : permissions) { + if (permission.type == defaultRestriction) { + defaultPermission = permission; + } + } + + permissionGroup = new RadioGroup<>("permissionsGroup", new Model(defaultPermission)); + form.add(permissionGroup); + + ListView permissionsList = new ListView("permissions", permissions) { + + private static final long serialVersionUID = 1L; + + @Override + protected void populateItem(ListItem item) { + Permission p = item.getModelObject(); + item.add(new Radio("radio", item.getModel())); + item.add(WicketUtils.newImage("image", p.image)); + item.add(new Label("name", p.name)); + item.add(new Label("description", p.description)); + } + }; + permissionGroup.add(permissionsList); + + // + // initial commit options + // + + // add README + addReadmeModel = Model.of(false); + form.add(new CheckBox("addReadme", addReadmeModel)); + + // add .gitignore + File gitignoreDir = app().runtime().getFileOrFolder(Keys.git.gitignoreFolder, "${baseFolder}/gitignore"); + File [] files = gitignoreDir.listFiles(); + if (files == null) { + files = new File[0]; + } + List gitignores = new ArrayList(); + for (File file : files) { + if (file.isFile() && file.getName().endsWith(".gitignore")) { + gitignores.add(StringUtils.stripFileExtension(file.getName())); + } + } + Collections.sort(gitignores); + gitignoreModel = Model.of(""); + final DropDownChoice gitignoreChoice = new DropDownChoice("gitignore", gitignoreModel, gitignores); + gitignoreChoice.setOutputMarkupId(true); + form.add(gitignoreChoice.setEnabled(false)); + + addGitignoreModel = Model.of(false); + final CheckBox gitignoreCheckbox = new CheckBox("addGitignore", addGitignoreModel); + form.add(gitignoreCheckbox); + + gitignoreCheckbox.add(new AjaxFormComponentUpdatingBehavior("onchange") { + + private static final long serialVersionUID = 1L; + + @Override + protected void onUpdate(AjaxRequestTarget target) { + gitignoreChoice.setEnabled(addGitignoreModel.getObject()); + target.addComponent(gitignoreChoice); + } + }); + + // TODO add .gitflow + addGitflowModel = Model.of(false); + form.add(new CheckBox("addGitflow", addGitflowModel)); + + form.add(new Button("create")); + + add(form); + } + + /** + * Prepare the initial commit for the repository. + * + * @param repository + * @param addReadme + * @param gitignore + * @param addGitFlow + * @return true if an initial commit was created + */ + protected boolean initialCommit(RepositoryModel repository, boolean addReadme, String gitignore, + boolean addGitFlow) { + boolean initialCommit = addReadme || !StringUtils.isEmpty(gitignore) || addGitFlow; + if (!initialCommit) { + return false; + } + + // build an initial commit + boolean success = false; + Repository db = app().repositories().getRepository(repositoryModel.name); + ObjectInserter odi = db.newObjectInserter(); + try { + + UserModel user = GitBlitWebSession.get().getUser(); + PersonIdent author = new PersonIdent(user.getDisplayName(), user.emailAddress); + + DirCache newIndex = DirCache.newInCore(); + DirCacheBuilder indexBuilder = newIndex.builder(); + + if (addReadme) { + // insert a README + String title = StringUtils.stripDotGit(StringUtils.getLastPathElement(repositoryModel.name)); + String description = repositoryModel.description == null ? "" : repositoryModel.description; + String readme = String.format("## %s\n\n%s\n\n", title, description); + byte [] bytes = readme.getBytes(Constants.ENCODING); + + DirCacheEntry entry = new DirCacheEntry("README.md"); + entry.setLength(bytes.length); + entry.setLastModified(System.currentTimeMillis()); + entry.setFileMode(FileMode.REGULAR_FILE); + entry.setObjectId(odi.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, bytes)); + + indexBuilder.add(entry); + } + + if (!StringUtils.isEmpty(gitignore)) { + // insert a .gitignore file + File dir = app().runtime().getFileOrFolder(Keys.git.gitignoreFolder, "${baseFolder}/gitignore"); + File file = new File(dir, gitignore + ".gitignore"); + if (file.exists() && file.length() > 0) { + byte [] bytes = FileUtils.readContent(file); + if (!ArrayUtils.isEmpty(bytes)) { + DirCacheEntry entry = new DirCacheEntry(".gitignore"); + entry.setLength(bytes.length); + entry.setLastModified(System.currentTimeMillis()); + entry.setFileMode(FileMode.REGULAR_FILE); + entry.setObjectId(odi.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, bytes)); + + indexBuilder.add(entry); + } + } + } + + if (addGitFlow) { + // insert a .gitflow file + Config config = new Config(); + config.setString("gitflow", null, "masterBranch", Constants.MASTER); + config.setString("gitflow", null, "developBranch", Constants.DEVELOP); + config.setString("gitflow", null, "featureBranchPrefix", "feature/"); + config.setString("gitflow", null, "releaseBranchPrefix", "release/"); + config.setString("gitflow", null, "hotfixBranchPrefix", "hotfix/"); + config.setString("gitflow", null, "supportBranchPrefix", "support/"); + config.setString("gitflow", null, "versionTagPrefix", ""); + + byte [] bytes = config.toText().getBytes(Constants.ENCODING); + + DirCacheEntry entry = new DirCacheEntry(".gitflow"); + entry.setLength(bytes.length); + entry.setLastModified(System.currentTimeMillis()); + entry.setFileMode(FileMode.REGULAR_FILE); + entry.setObjectId(odi.insert(org.eclipse.jgit.lib.Constants.OBJ_BLOB, bytes)); + + indexBuilder.add(entry); + } + + indexBuilder.finish(); + + if (newIndex.getEntryCount() == 0) { + // nothing to commit + return false; + } + + ObjectId treeId = newIndex.writeTree(odi); + + // Create a commit object + CommitBuilder commit = new CommitBuilder(); + commit.setAuthor(author); + commit.setCommitter(author); + commit.setEncoding(Constants.ENCODING); + commit.setMessage("Initial commit"); + commit.setTreeId(treeId); + + // Insert the commit into the repository + ObjectId commitId = odi.insert(commit); + odi.flush(); + + // set the branch refs + RevWalk revWalk = new RevWalk(db); + try { + // set the master branch + RevCommit revCommit = revWalk.parseCommit(commitId); + RefUpdate masterRef = db.updateRef(Constants.R_MASTER); + masterRef.setNewObjectId(commitId); + masterRef.setRefLogMessage("commit: " + revCommit.getShortMessage(), false); + Result masterRC = masterRef.update(); + switch (masterRC) { + case NEW: + success = true; + break; + default: + success = false; + } + + if (addGitFlow) { + // set the develop branch for git-flow + RefUpdate developRef = db.updateRef(Constants.R_DEVELOP); + developRef.setNewObjectId(commitId); + developRef.setRefLogMessage("commit: " + revCommit.getShortMessage(), false); + Result developRC = developRef.update(); + switch (developRC) { + case NEW: + success = true; + break; + default: + success = false; + } + } + } finally { + revWalk.release(); + } + } catch (UnsupportedEncodingException e) { + logger().error(null, e); + } catch (IOException e) { + logger().error(null, e); + } finally { + odi.release(); + db.close(); + } + return success; + } + + private static class Permission implements Serializable { + + private static final long serialVersionUID = 1L; + + final String name; + final String description; + final String image; + final AccessRestrictionType type; + + Permission(String name, String description, String img, AccessRestrictionType type) { + this.name = name; + this.description = description; + this.image = img; + this.type = type; + } + } +} diff --git a/src/main/java/com/gitblit/wicket/pages/RootPage.java b/src/main/java/com/gitblit/wicket/pages/RootPage.java index a2f3a497..b1c3639d 100644 --- a/src/main/java/com/gitblit/wicket/pages/RootPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RootPage.java @@ -607,7 +607,7 @@ public abstract class RootPage extends BasePage { List standardItems = new ArrayList(); standardItems.add(new MenuDivider()); if (user.canAdmin() || user.canCreate()) { - standardItems.add(new PageLinkMenuItem("gb.newRepository", EditRepositoryPage.class)); + standardItems.add(new PageLinkMenuItem("gb.newRepository", app().getNewRepositoryPage())); } standardItems.add(new PageLinkMenuItem("gb.myProfile", UserPage.class, WicketUtils.newUsernameParameter(user.username))); diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java index 6cb791eb..29b49b33 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.java +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java @@ -30,8 +30,8 @@ import org.eclipse.jgit.lib.PersonIdent; import com.gitblit.Keys; import com.gitblit.models.Menu.ParameterMenuItem; -import com.gitblit.models.NavLink.DropDownPageMenuNavLink; import com.gitblit.models.NavLink; +import com.gitblit.models.NavLink.DropDownPageMenuNavLink; import com.gitblit.models.ProjectModel; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; @@ -95,7 +95,7 @@ public class UserPage extends RootPage { UserModel sessionUser = GitBlitWebSession.get().getUser(); if (sessionUser != null && user.canCreate() && sessionUser.equals(user)) { // user can create personal repositories - add(new BookmarkablePageLink("newRepository", EditRepositoryPage.class)); + add(new BookmarkablePageLink("newRepository", app().getNewRepositoryPage())); } else { add(new Label("newRepository").setVisible(false)); } diff --git a/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java b/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java index 45b0bab1..4433b043 100644 --- a/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java +++ b/src/main/java/com/gitblit/wicket/panels/FilterableRepositoryList.java @@ -33,7 +33,6 @@ import com.gitblit.utils.StringUtils; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.freemarker.FreemarkerPanel; import com.gitblit.wicket.ng.NgController; -import com.gitblit.wicket.pages.EditRepositoryPage; /** * A client-side filterable rich repository list which uses Freemarker, Wicket, @@ -98,7 +97,7 @@ public class FilterableRepositoryList extends BasePanel { } if (allowCreate) { - panel.add(new LinkPanel(ngList + "Button", "btn btn-mini", getString("gb.newRepository"), EditRepositoryPage.class)); + panel.add(new LinkPanel(ngList + "Button", "btn btn-mini", getString("gb.newRepository"), app().getNewRepositoryPage())); } else { panel.add(new Label(ngList + "Button").setVisible(false)); } diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java index dd208e23..8573e1a6 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/RepositoriesPanel.java @@ -51,7 +51,6 @@ import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.pages.BasePage; -import com.gitblit.wicket.pages.EditRepositoryPage; import com.gitblit.wicket.pages.ProjectPage; import com.gitblit.wicket.pages.RepositoriesPage; import com.gitblit.wicket.pages.SummaryPage; @@ -87,12 +86,12 @@ public class RepositoriesPanel extends BasePanel { setResponsePage(RepositoriesPage.class); } }.setVisible(app().settings().getBoolean(Keys.git.cacheRepositoryList, true))); - managementLinks.add(new BookmarkablePageLink("newRepository", EditRepositoryPage.class)); + managementLinks.add(new BookmarkablePageLink("newRepository", app().getNewRepositoryPage())); add(managementLinks); } else if (showManagement && user != null && user.canCreate()) { // user can create personal repositories managementLinks = new Fragment("managementPanel", "personalLinks", this); - managementLinks.add(new BookmarkablePageLink("newRepository", EditRepositoryPage.class)); + managementLinks.add(new BookmarkablePageLink("newRepository", app().getNewRepositoryPage())); add(managementLinks); } else { // user has no management permissions -- cgit v1.2.3 From 8845b9aff37ee1cdc538ed4247933f7e3c06a49e Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 29 May 2014 21:19:59 -0400 Subject: Inlcude authorization control and revise the string resources --- .../com/gitblit/wicket/GitBlitWebApp.properties | 14 +++--- .../gitblit/wicket/pages/NewRepositoryPage.java | 53 ++++++++++++++++++---- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index ac589558..3fd5a3ac 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -685,12 +685,14 @@ gb.closedMilestones = closed milestones gb.administration = administration gb.plugins = plugins gb.extensions = extensions -gb.anonymous = Anonymous -gb.anonymousRepoDescription = Anyone can see, clone, and push to this repository. -gb.public = Public -gb.publicRepoDescription = Anyone can see and clone this repository. You choose who can push. -gb.protected = Protected -gb.protectedRepoDescription = Anyone can see this repository. You choose who can clone and push. +gb.anonymousPush = Anonymous Pushes +gb.anonymousPushDescription = Anyone can see, clone, and push to this repository. +gb.pushRestrictedAuthenticated = Restrict Pushes (Authenticated) +gb.pushRestrictedAuthenticatedDescription = Anyone can see and clone this repository. All authenticated users can push. +gb.pushRestrictedNamed = Restrict Pushes (Named) +gb.pushRestrictedNamedDescription = Anyone can see and clone this repository. You choose who can push. +gb.cloneRestricted = Restrict Clones & Pushes +gb.cloneRestrictedDescription = Anyone can see this repository. You choose who can clone and push. gb.private = Private gb.privateRepoDescription = You choose who can see, clone, and push to this repository. gb.initialCommit = Initial Commit diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java index b0cc3e95..a423ae62 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java @@ -148,9 +148,9 @@ public class NewRepositoryPage extends RootSubPage { repositoryModel.name = fullName; repositoryModel.projectPath = null; - Permission permisison = permissionGroup.getModelObject(); - repositoryModel.accessRestriction = permisison.type; - repositoryModel.authorizationControl = AuthorizationControl.NAMED; + Permission permission = permissionGroup.getModelObject(); + repositoryModel.authorizationControl = permission.control; + repositoryModel.accessRestriction = permission.type; repositoryModel.owners = new ArrayList(); repositoryModel.owners.add(GitBlitWebSession.get().getUsername()); @@ -229,15 +229,41 @@ public class NewRepositoryPage extends RootSubPage { form.add(new TextField("name")); form.add(new TextField("description")); - Permission anonymousPermission = new Permission(getString("gb.anonymous"), getString("gb.anonymousRepoDescription"), "blank.png", AccessRestrictionType.NONE); - Permission publicPermission = new Permission(getString("gb.public"), getString("gb.publicRepoDescription"), "lock_go_16x16.png", AccessRestrictionType.PUSH); - Permission protectedPermission = new Permission(getString("gb.protected"), getString("gb.protectedRepoDescription"), "lock_pull_16x16.png", AccessRestrictionType.CLONE); - Permission privatePermission = new Permission(getString("gb.private"), getString("gb.privateRepoDescription"), "shield_16x16.png", AccessRestrictionType.VIEW); + Permission anonymousPermission = new Permission(getString("gb.anonymousPush"), + getString("gb.anonymousPushDescription"), + "blank.png", + AuthorizationControl.AUTHENTICATED, + AccessRestrictionType.NONE); + + Permission authenticatedPermission = new Permission(getString("gb.pushRestrictedAuthenticated"), + getString("gb.pushRestrictedAuthenticatedDescription"), + "lock_go_16x16.png", + AuthorizationControl.AUTHENTICATED, + AccessRestrictionType.PUSH); + + Permission publicPermission = new Permission(getString("gb.pushRestrictedNamed"), + getString("gb.pushRestrictedNamedDescription"), + "lock_go_16x16.png", + AuthorizationControl.NAMED, + AccessRestrictionType.PUSH); + + Permission protectedPermission = new Permission(getString("gb.cloneRestricted"), + getString("gb.cloneRestrictedDescription"), + "lock_pull_16x16.png", + AuthorizationControl.NAMED, + AccessRestrictionType.CLONE); + + Permission privatePermission = new Permission(getString("gb.private"), + getString("gb.privateRepoDescription"), + "shield_16x16.png", + AuthorizationControl.NAMED, + AccessRestrictionType.VIEW); List permissions = new ArrayList(); if (app().settings().getBoolean(Keys.git.allowAnonymousPushes, false)) { permissions.add(anonymousPermission); } + permissions.add(authenticatedPermission); permissions.add(publicPermission); permissions.add(protectedPermission); permissions.add(privatePermission); @@ -248,10 +274,17 @@ public class NewRepositoryPage extends RootSubPage { if (AccessRestrictionType.NONE == defaultRestriction) { defaultRestriction = AccessRestrictionType.PUSH; } + AuthorizationControl defaultControl = AuthorizationControl.fromName( + app().settings().getString(Keys.git.defaultAuthorizationControl, AuthorizationControl.NAMED.name())); + + if (AuthorizationControl.AUTHENTICATED == defaultControl) { + defaultRestriction = AccessRestrictionType.PUSH; + } Permission defaultPermission = publicPermission; for (Permission permission : permissions) { - if (permission.type == defaultRestriction) { + if (permission.type == defaultRestriction + && permission.control == defaultControl) { defaultPermission = permission; } } @@ -481,12 +514,14 @@ public class NewRepositoryPage extends RootSubPage { final String name; final String description; final String image; + final AuthorizationControl control; final AccessRestrictionType type; - Permission(String name, String description, String img, AccessRestrictionType type) { + Permission(String name, String description, String img, AuthorizationControl control, AccessRestrictionType type) { this.name = name; this.description = description; this.image = img; + this.control = control; this.type = type; } } -- cgit v1.2.3 From 2c50880dbd5de292e37d2533fccfcb62f6be9f95 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 29 May 2014 21:47:56 -0400 Subject: Extract authorization/access selection panel to re-usable class --- .../gitblit/wicket/pages/NewRepositoryPage.html | 13 +- .../gitblit/wicket/pages/NewRepositoryPage.java | 101 +----------- .../wicket/panels/RepositoryPermissionPanel.html | 25 +++ .../wicket/panels/RepositoryPermissionPanel.java | 171 +++++++++++++++++++++ 4 files changed, 205 insertions(+), 105 deletions(-) create mode 100644 src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.html create mode 100644 src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html index e9f12027..c59f29c8 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html @@ -32,18 +32,7 @@
- -
-
- - -
-
-
- -
-
-
+
diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java index a423ae62..cd0cef61 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java @@ -17,7 +17,6 @@ package com.gitblit.wicket.pages; import java.io.File; import java.io.IOException; -import java.io.Serializable; import java.io.UnsupportedEncodingException; import java.text.MessageFormat; import java.util.ArrayList; @@ -27,16 +26,11 @@ import java.util.List; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.behavior.SimpleAttributeModifier; -import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Button; import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; -import org.apache.wicket.markup.html.form.Radio; -import org.apache.wicket.markup.html.form.RadioGroup; import org.apache.wicket.markup.html.form.TextField; -import org.apache.wicket.markup.html.list.ListItem; -import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; @@ -67,15 +61,16 @@ import com.gitblit.utils.FileUtils; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.panels.RepositoryPermissionPanel; public class NewRepositoryPage extends RootSubPage { private final RepositoryModel repositoryModel; - private RadioGroup permissionGroup; private IModel addReadmeModel; private Model gitignoreModel; private IModel addGitflowModel; private IModel addGitignoreModel; + private RepositoryPermissionPanel permissionPanel; public NewRepositoryPage() { // create constructor @@ -148,9 +143,7 @@ public class NewRepositoryPage extends RootSubPage { repositoryModel.name = fullName; repositoryModel.projectPath = null; - Permission permission = permissionGroup.getModelObject(); - repositoryModel.authorizationControl = permission.control; - repositoryModel.accessRestriction = permission.type; + permissionPanel.setPermission(repositoryModel); repositoryModel.owners = new ArrayList(); repositoryModel.owners.add(GitBlitWebSession.get().getUsername()); @@ -229,46 +222,7 @@ public class NewRepositoryPage extends RootSubPage { form.add(new TextField("name")); form.add(new TextField("description")); - Permission anonymousPermission = new Permission(getString("gb.anonymousPush"), - getString("gb.anonymousPushDescription"), - "blank.png", - AuthorizationControl.AUTHENTICATED, - AccessRestrictionType.NONE); - - Permission authenticatedPermission = new Permission(getString("gb.pushRestrictedAuthenticated"), - getString("gb.pushRestrictedAuthenticatedDescription"), - "lock_go_16x16.png", - AuthorizationControl.AUTHENTICATED, - AccessRestrictionType.PUSH); - - Permission publicPermission = new Permission(getString("gb.pushRestrictedNamed"), - getString("gb.pushRestrictedNamedDescription"), - "lock_go_16x16.png", - AuthorizationControl.NAMED, - AccessRestrictionType.PUSH); - - Permission protectedPermission = new Permission(getString("gb.cloneRestricted"), - getString("gb.cloneRestrictedDescription"), - "lock_pull_16x16.png", - AuthorizationControl.NAMED, - AccessRestrictionType.CLONE); - - Permission privatePermission = new Permission(getString("gb.private"), - getString("gb.privateRepoDescription"), - "shield_16x16.png", - AuthorizationControl.NAMED, - AccessRestrictionType.VIEW); - - List permissions = new ArrayList(); - if (app().settings().getBoolean(Keys.git.allowAnonymousPushes, false)) { - permissions.add(anonymousPermission); - } - permissions.add(authenticatedPermission); - permissions.add(publicPermission); - permissions.add(protectedPermission); - permissions.add(privatePermission); - - // determine default permission selection + // prepare the default access controls AccessRestrictionType defaultRestriction = AccessRestrictionType.fromName( app().settings().getString(Keys.git.defaultAccessRestriction, AccessRestrictionType.PUSH.name())); if (AccessRestrictionType.NONE == defaultRestriction) { @@ -281,31 +235,11 @@ public class NewRepositoryPage extends RootSubPage { defaultRestriction = AccessRestrictionType.PUSH; } - Permission defaultPermission = publicPermission; - for (Permission permission : permissions) { - if (permission.type == defaultRestriction - && permission.control == defaultControl) { - defaultPermission = permission; - } - } - - permissionGroup = new RadioGroup<>("permissionsGroup", new Model(defaultPermission)); - form.add(permissionGroup); + repositoryModel.authorizationControl = defaultControl; + repositoryModel.accessRestriction = defaultRestriction; - ListView permissionsList = new ListView("permissions", permissions) { - - private static final long serialVersionUID = 1L; - - @Override - protected void populateItem(ListItem item) { - Permission p = item.getModelObject(); - item.add(new Radio("radio", item.getModel())); - item.add(WicketUtils.newImage("image", p.image)); - item.add(new Label("name", p.name)); - item.add(new Label("description", p.description)); - } - }; - permissionGroup.add(permissionsList); + permissionPanel = new RepositoryPermissionPanel("permissionPanel", repositoryModel); + form.add(permissionPanel); // // initial commit options @@ -506,23 +440,4 @@ public class NewRepositoryPage extends RootSubPage { } return success; } - - private static class Permission implements Serializable { - - private static final long serialVersionUID = 1L; - - final String name; - final String description; - final String image; - final AuthorizationControl control; - final AccessRestrictionType type; - - Permission(String name, String description, String img, AuthorizationControl control, AccessRestrictionType type) { - this.name = name; - this.description = description; - this.image = img; - this.control = control; - this.type = type; - } - } } diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.html b/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.html new file mode 100644 index 00000000..6a4d5cef --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.html @@ -0,0 +1,25 @@ + + + + + + + +
+
+ + +
+
+
+ +
+
+
+ +
+ + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java new file mode 100644 index 00000000..7c416b1b --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java @@ -0,0 +1,171 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.panels; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.Radio; +import org.apache.wicket.markup.html.form.RadioGroup; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.model.Model; + +import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Keys; +import com.gitblit.models.RepositoryModel; +import com.gitblit.wicket.WicketUtils; + +/** + * A radio group panel of the 5 available authorization/access restriction combinations. + * + * @author James Moger + * + */ +public class RepositoryPermissionPanel extends BasePanel { + + private static final long serialVersionUID = 1L; + + private final RepositoryModel repository; + + private RadioGroup permissionGroup; + + public RepositoryPermissionPanel(String wicketId, RepositoryModel repository) { + super(wicketId); + this.repository = repository; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + Permission anonymousPermission = new Permission(getString("gb.anonymousPush"), + getString("gb.anonymousPushDescription"), + "blank.png", + AuthorizationControl.AUTHENTICATED, + AccessRestrictionType.NONE); + + Permission authenticatedPermission = new Permission(getString("gb.pushRestrictedAuthenticated"), + getString("gb.pushRestrictedAuthenticatedDescription"), + "lock_go_16x16.png", + AuthorizationControl.AUTHENTICATED, + AccessRestrictionType.PUSH); + + Permission publicPermission = new Permission(getString("gb.pushRestrictedNamed"), + getString("gb.pushRestrictedNamedDescription"), + "lock_go_16x16.png", + AuthorizationControl.NAMED, + AccessRestrictionType.PUSH); + + Permission protectedPermission = new Permission(getString("gb.cloneRestricted"), + getString("gb.cloneRestrictedDescription"), + "lock_pull_16x16.png", + AuthorizationControl.NAMED, + AccessRestrictionType.CLONE); + + Permission privatePermission = new Permission(getString("gb.private"), + getString("gb.privateRepoDescription"), + "shield_16x16.png", + AuthorizationControl.NAMED, + AccessRestrictionType.VIEW); + + List permissions = new ArrayList(); + if (app().settings().getBoolean(Keys.git.allowAnonymousPushes, false)) { + permissions.add(anonymousPermission); + } + permissions.add(authenticatedPermission); + permissions.add(publicPermission); + permissions.add(protectedPermission); + permissions.add(privatePermission); + + AccessRestrictionType defaultRestriction = repository.accessRestriction; + if (defaultRestriction == null) { + defaultRestriction = AccessRestrictionType.fromName(app().settings().getString(Keys.git.defaultAccessRestriction, + AccessRestrictionType.PUSH.name())); + } + + AuthorizationControl defaultControl = repository.authorizationControl; + if (defaultControl == null) { + defaultControl = AuthorizationControl.fromName(app().settings().getString(Keys.git.defaultAuthorizationControl, + AuthorizationControl.NAMED.name())); + } + + Permission defaultPermission = publicPermission; + for (Permission permission : permissions) { + if (permission.type == defaultRestriction && permission.control == defaultControl) { + defaultPermission = permission; + } + } + + permissionGroup = new RadioGroup<>("permissionsGroup", new Model(defaultPermission)); + ListView permissionsList = new ListView("permissions", permissions) { + + private static final long serialVersionUID = 1L; + + @Override + protected void populateItem(ListItem item) { + Permission p = item.getModelObject(); + item.add(new Radio("radio", item.getModel())); + item.add(WicketUtils.newImage("image", p.image)); + item.add(new Label("name", p.name)); + item.add(new Label("description", p.description)); + } + }; + permissionGroup.add(permissionsList); + + setOutputMarkupId(true); + + add(permissionGroup); + } + + public void setPermission(RepositoryModel repository) { + Permission permission = permissionGroup.getModelObject(); + repository.authorizationControl = permission.control; + repository.accessRestriction = permission.type; + } + + @Override + protected boolean getStatelessHint() { + return false; + } + + private static class Permission implements Serializable { + + private static final long serialVersionUID = 1L; + + final String name; + final String description; + final String image; + final AuthorizationControl control; + final AccessRestrictionType type; + + Permission(String name, String description, String img, AuthorizationControl control, AccessRestrictionType type) { + this.name = name; + this.description = description; + this.image = img; + this.control = control; + this.type = type; + } + + @Override + public String toString() { + return name; + } + } +} -- cgit v1.2.3 From a3456e22504a0a054312989fd52a21e4d193baf7 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 29 May 2014 22:29:51 -0400 Subject: Extract repository name panel for re-use --- .../com/gitblit/wicket/GitBlitWebApp.properties | 1 + .../gitblit/wicket/pages/NewRepositoryPage.html | 17 +-- .../gitblit/wicket/pages/NewRepositoryPage.java | 79 ++---------- .../gitblit/wicket/panels/RepositoryNamePanel.html | 27 ++++ .../gitblit/wicket/panels/RepositoryNamePanel.java | 139 +++++++++++++++++++++ .../wicket/panels/RepositoryPermissionPanel.java | 2 +- 6 files changed, 179 insertions(+), 86 deletions(-) create mode 100644 src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html create mode 100644 src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 3fd5a3ac..d90158d4 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -685,6 +685,7 @@ gb.closedMilestones = closed milestones gb.administration = administration gb.plugins = plugins gb.extensions = extensions +gb.pleaseSelectProject = Please select the project! gb.anonymousPush = Anonymous Pushes gb.anonymousPushDescription = Anyone can see, clone, and push to this repository. gb.pushRestrictedAuthenticated = Restrict Pushes (Authenticated) diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html index c59f29c8..05f56012 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html @@ -10,20 +10,7 @@
- - - - - - - - - - - - - -
/  
+

@@ -32,7 +19,7 @@
- +

diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java index cd0cef61..e2e5d4bc 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java @@ -18,7 +18,6 @@ package com.gitblit.wicket.pages; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -61,6 +60,7 @@ import com.gitblit.utils.FileUtils; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.panels.RepositoryNamePanel; import com.gitblit.wicket.panels.RepositoryPermissionPanel; public class NewRepositoryPage extends RootSubPage { @@ -71,6 +71,7 @@ public class NewRepositoryPage extends RootSubPage { private IModel addGitflowModel; private IModel addGitignoreModel; private RepositoryPermissionPanel permissionPanel; + private RepositoryNamePanel namePanel; public NewRepositoryPage() { // create constructor @@ -104,46 +105,11 @@ public class NewRepositoryPage extends RootSubPage { @Override protected void onSubmit() { - - // confirm a repository name was entered - if (StringUtils.isEmpty(repositoryModel.name)) { - error(getString("gb.pleaseSetRepositoryName")); - return; - } - - String project = repositoryModel.projectPath; - String fullName = (project + "/" + repositoryModel.name).trim(); - fullName = fullName.replace('\\', '/'); - fullName = fullName.replace("//", "/"); - if (fullName.charAt(0) == '/') { - fullName = fullName.substring(1); - } - if (fullName.endsWith("/")) { - fullName = fullName.substring(0, fullName.length() - 1); - } - try { - if (fullName.contains("../")) { - error(getString("gb.illegalRelativeSlash")); + if (!namePanel.updateModel(repositoryModel)) { return; } - if (fullName.contains("/../")) { - error(getString("gb.illegalRelativeSlash")); - return; - } - - // confirm valid characters in repository name - Character c = StringUtils.findInvalidCharacter(fullName); - if (c != null) { - error(MessageFormat.format(getString("gb.illegalCharacterRepositoryName"), - c)); - return; - } - - repositoryModel.name = fullName; - repositoryModel.projectPath = null; - - permissionPanel.setPermission(repositoryModel); + permissionPanel.updateModel(repositoryModel); repositoryModel.owners = new ArrayList(); repositoryModel.owners.add(GitBlitWebSession.get().getUsername()); @@ -179,47 +145,20 @@ public class NewRepositoryPage extends RootSubPage { } catch (GitBlitException e) { error(e.getMessage()); - - // restore project and name fields on error condition - repositoryModel.projectPath = StringUtils.getFirstPathElement(fullName); - if (!StringUtils.isEmpty(repositoryModel.projectPath)) { - repositoryModel.name = fullName.substring(repositoryModel.projectPath.length() + 1); - } + namePanel.resetModel(repositoryModel); return; } setRedirect(true); - setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(fullName)); + setResponsePage(SummaryPage.class, WicketUtils.newRepositoryParameter(repositoryModel.name)); } }; - GitBlitWebSession session = GitBlitWebSession.get(); - UserModel user = session.getUser(); - - // build project list for repository destination - String defaultProject = null; - List projects = new ArrayList(); - - if (user.canAdmin()) { - String main = app().settings().getString(Keys.web.repositoryRootGroupName, "main"); - projects.add(main); - defaultProject = main; - } - - if (user.canCreate()) { - projects.add(user.getPersonalPath()); - if (defaultProject == null) { - // only prefer personal namespace if default is not already set - defaultProject = user.getPersonalPath(); - } - } - - repositoryModel.projectPath = defaultProject; - // do not let the browser pre-populate these fields form.add(new SimpleAttributeModifier("autocomplete", "off")); - form.add(new DropDownChoice("projectPath", projects)); - form.add(new TextField("name")); + namePanel = new RepositoryNamePanel("namePanel", repositoryModel); + form.add(namePanel); + form.add(new TextField("description")); // prepare the default access controls diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html new file mode 100644 index 00000000..f3a0738e --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + +
/  
+ +
+ + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java new file mode 100644 index 00000000..7b20adec --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java @@ -0,0 +1,139 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.panels; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; + +import org.apache.wicket.markup.html.form.DropDownChoice; +import org.apache.wicket.markup.html.form.TextField; + +import com.gitblit.models.RepositoryModel; +import com.gitblit.models.UserModel; +import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.GitBlitWebSession; + +/** + * A radio group panel of the 5 available authorization/access restriction combinations. + * + * @author James Moger + * + */ +public class RepositoryNamePanel extends BasePanel { + + private static final long serialVersionUID = 1L; + + private final RepositoryModel repository; + + private String fullName; + + public RepositoryNamePanel(String wicketId, RepositoryModel repository) { + super(wicketId); + this.repository = repository; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + GitBlitWebSession session = GitBlitWebSession.get(); + UserModel user = session.getUser(); + + // build project list for repository destination + String defaultProject = null; + List projects = new ArrayList(); + + if (user.canAdmin()) { + projects.add("/"); + defaultProject = "/"; + } + + if (user.canCreate()) { + String p = user.getPersonalPath() + "/"; + projects.add(p); + if (defaultProject == null) { + // only prefer personal namespace if default is not already set + defaultProject = p; + } + } + + repository.projectPath = defaultProject; + + add(new DropDownChoice("projectPath", projects)); + add(new TextField("name")); + } + + public boolean updateModel(RepositoryModel repositoryModel) { + // confirm a project was selected + if (StringUtils.isEmpty(repositoryModel.projectPath)) { + error(getString("gb.pleaseSelectProject")); + return false; + } + + // confirm a repository name was entered + if (StringUtils.isEmpty(repositoryModel.name)) { + error(getString("gb.pleaseSetRepositoryName")); + return false; + } + + String project = repositoryModel.projectPath; + + fullName = (project + repositoryModel.name).trim(); + fullName = fullName.replace('\\', '/'); + fullName = fullName.replace("//", "/"); + if (fullName.charAt(0) == '/') { + fullName = fullName.substring(1); + } + if (fullName.endsWith("/")) { + fullName = fullName.substring(0, fullName.length() - 1); + } + + if (fullName.contains("../")) { + error(getString("gb.illegalRelativeSlash")); + return false; + } + if (fullName.contains("/../")) { + error(getString("gb.illegalRelativeSlash")); + return false; + } + + // confirm valid characters in repository name + Character c = StringUtils.findInvalidCharacter(fullName); + if (c != null) { + error(MessageFormat.format(getString("gb.illegalCharacterRepositoryName"), c)); + return false; + } + + repositoryModel.name = fullName; + repositoryModel.projectPath = null; + + return true; + } + + public void resetModel(RepositoryModel repositoryModel) { + // restore project and name fields on error condition + repositoryModel.projectPath = StringUtils.getFirstPathElement(fullName) + "/"; + if (repositoryModel.projectPath.length() > 1) { + repositoryModel.name = fullName.substring(repositoryModel.projectPath.length()); + } + } + + @Override + protected boolean getStatelessHint() { + return false; + } +} diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java index 7c416b1b..ed3f1fed 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java @@ -134,7 +134,7 @@ public class RepositoryPermissionPanel extends BasePanel { add(permissionGroup); } - public void setPermission(RepositoryModel repository) { + public void updateModel(RepositoryModel repository) { Permission permission = permissionGroup.getModelObject(); repository.authorizationControl = permission.control; repository.accessRestriction = permission.type; -- cgit v1.2.3 From 5779988cf3a1d737322b2b6a1d568da8713509e7 Mon Sep 17 00:00:00 2001 From: James Moger Date: Fri, 30 May 2014 10:05:06 -0400 Subject: Use RepositoryNamePanel in EditRepositoryPage, rename AccessPolicyPanel --- .../com/gitblit/wicket/GitBlitWebApp.properties | 22 +-- .../gitblit/wicket/pages/EditRepositoryPage.html | 4 +- .../gitblit/wicket/pages/EditRepositoryPage.java | 63 ++------ .../gitblit/wicket/pages/NewRepositoryPage.html | 5 - .../gitblit/wicket/pages/NewRepositoryPage.java | 9 +- .../gitblit/wicket/panels/AccessPolicyPanel.html | 28 ++++ .../gitblit/wicket/panels/AccessPolicyPanel.java | 171 +++++++++++++++++++++ .../gitblit/wicket/panels/RepositoryNamePanel.html | 7 +- .../gitblit/wicket/panels/RepositoryNamePanel.java | 83 +++++++--- .../wicket/panels/RepositoryPermissionPanel.html | 25 --- .../wicket/panels/RepositoryPermissionPanel.java | 171 --------------------- 11 files changed, 290 insertions(+), 298 deletions(-) create mode 100644 src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html create mode 100644 src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java delete mode 100644 src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.html delete mode 100644 src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index d90158d4..d2d1454e 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -686,16 +686,18 @@ gb.administration = administration gb.plugins = plugins gb.extensions = extensions gb.pleaseSelectProject = Please select the project! -gb.anonymousPush = Anonymous Pushes -gb.anonymousPushDescription = Anyone can see, clone, and push to this repository. -gb.pushRestrictedAuthenticated = Restrict Pushes (Authenticated) -gb.pushRestrictedAuthenticatedDescription = Anyone can see and clone this repository. All authenticated users can push. -gb.pushRestrictedNamed = Restrict Pushes (Named) -gb.pushRestrictedNamedDescription = Anyone can see and clone this repository. You choose who can push. -gb.cloneRestricted = Restrict Clones & Pushes -gb.cloneRestrictedDescription = Anyone can see this repository. You choose who can clone and push. -gb.private = Private -gb.privateRepoDescription = You choose who can see, clone, and push to this repository. +gb.accessPolicy = Access Policy +gb.accessPolicyDescription = Choose an access policy to control visibility, cloning, and pushing to this repository. +gb.anonymousPolicy = Anonymous View, Clone, & Push +gb.anonymousPolicyDescription = Anyone can see, clone, and push to this repository. +gb.authenticatedPushPolicy = Restrict Push (Authenticated) +gb.authenticatedPushPolicyDescription = Anyone can see and clone this repository. All authenticated users have RW+ push permission. +gb.namedPushPolicy = Restrict Push (Named) +gb.namedPushPolicyDescription = Anyone can see and clone this repository. You choose who can push. +gb.clonePolicy = Restrict Clone & Push +gb.clonePolicyDescription = Anyone can see this repository. You choose who can clone and push. +gb.viewPolicy = Restrict View, Clone, & Push +gb.viewPolicyDescription = You choose who can see, clone, and push to this repository. gb.initialCommit = Initial Commit gb.initialCommitDescription = This will allow you to git clone this repository immediately. Skip this step if you have already run git init locally. gb.initWithReadme = Include a README diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html index b7a1976f..ccb60a5c 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html @@ -24,10 +24,10 @@
+
+ - - diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java index c18cd514..4759fd0d 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -72,11 +72,14 @@ import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.BasePanel.JavascriptEventConfirmation; import com.gitblit.wicket.panels.BulletListPanel; import com.gitblit.wicket.panels.RegistrantPermissionsPanel; +import com.gitblit.wicket.panels.RepositoryNamePanel; public class EditRepositoryPage extends RootSubPage { private final boolean isCreate; + RepositoryNamePanel namePanel; + private boolean isAdmin; RepositoryModel repositoryModel; @@ -263,60 +266,9 @@ public class EditRepositoryPage extends RootSubPage { @Override protected void onSubmit() { try { - // confirm a repository name was entered - if (repositoryModel.name == null && StringUtils.isEmpty(repositoryModel.name)) { - error(getString("gb.pleaseSetRepositoryName")); - return; - } - - // ensure name is trimmed - repositoryModel.name = repositoryModel.name.trim(); - - // automatically convert backslashes to forward slashes - repositoryModel.name = repositoryModel.name.replace('\\', '/'); - // Automatically replace // with / - repositoryModel.name = repositoryModel.name.replace("//", "/"); - - // prohibit folder paths - if (repositoryModel.name.startsWith("/")) { - error(getString("gb.illegalLeadingSlash")); - return; - } - if (repositoryModel.name.startsWith("../")) { - error(getString("gb.illegalRelativeSlash")); - return; - } - if (repositoryModel.name.contains("/../")) { - error(getString("gb.illegalRelativeSlash")); + if (!namePanel.updateModel(repositoryModel)) { return; } - if (repositoryModel.name.endsWith("/")) { - repositoryModel.name = repositoryModel.name.substring(0, repositoryModel.name.length() - 1); - } - - // confirm valid characters in repository name - Character c = StringUtils.findInvalidCharacter(repositoryModel.name); - if (c != null) { - error(MessageFormat.format(getString("gb.illegalCharacterRepositoryName"), - c)); - return; - } - - if (user.canCreate() && !user.canAdmin() && allowEditName) { - // ensure repository name begins with the user's path - if (!repositoryModel.name.startsWith(user.getPersonalPath())) { - error(MessageFormat.format(getString("gb.illegalPersonalRepositoryLocation"), - user.getPersonalPath())); - return; - } - - if (repositoryModel.name.equals(user.getPersonalPath())) { - // reset path prefix and show error - repositoryModel.name = user.getPersonalPath() + "/"; - error(getString("gb.pleaseSetRepositoryName")); - return; - } - } // confirm access restriction selection if (repositoryModel.accessRestriction == null) { @@ -426,6 +378,7 @@ public class EditRepositoryPage extends RootSubPage { } } catch (GitBlitException e) { error(e.getMessage()); + namePanel.resetModel(repositoryModel); return; } setRedirect(false); @@ -437,8 +390,10 @@ public class EditRepositoryPage extends RootSubPage { form.add(new SimpleAttributeModifier("autocomplete", "off")); // field names reflective match RepositoryModel fields - form.add(new TextField("name").setEnabled(allowEditName)); - form.add(new TextField("description")); + namePanel = new RepositoryNamePanel("namePanel", repositoryModel); + namePanel.setEditable(allowEditName); + form.add(namePanel); + form.add(ownersPalette); form.add(new CheckBox("allowForks").setEnabled(app().settings().getBoolean(Keys.web.allowForking, true))); DropDownChoice accessRestriction = new DropDownChoice("accessRestriction", diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html index 05f56012..8e4e74ac 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html @@ -12,11 +12,6 @@
-
-
- -
-
diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java index e2e5d4bc..0adb1ddd 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java @@ -29,7 +29,6 @@ import org.apache.wicket.markup.html.form.Button; import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; -import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; @@ -61,7 +60,7 @@ import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.RepositoryNamePanel; -import com.gitblit.wicket.panels.RepositoryPermissionPanel; +import com.gitblit.wicket.panels.AccessPolicyPanel; public class NewRepositoryPage extends RootSubPage { @@ -70,7 +69,7 @@ public class NewRepositoryPage extends RootSubPage { private Model gitignoreModel; private IModel addGitflowModel; private IModel addGitignoreModel; - private RepositoryPermissionPanel permissionPanel; + private AccessPolicyPanel permissionPanel; private RepositoryNamePanel namePanel; public NewRepositoryPage() { @@ -159,8 +158,6 @@ public class NewRepositoryPage extends RootSubPage { namePanel = new RepositoryNamePanel("namePanel", repositoryModel); form.add(namePanel); - form.add(new TextField("description")); - // prepare the default access controls AccessRestrictionType defaultRestriction = AccessRestrictionType.fromName( app().settings().getString(Keys.git.defaultAccessRestriction, AccessRestrictionType.PUSH.name())); @@ -177,7 +174,7 @@ public class NewRepositoryPage extends RootSubPage { repositoryModel.authorizationControl = defaultControl; repositoryModel.accessRestriction = defaultRestriction; - permissionPanel = new RepositoryPermissionPanel("permissionPanel", repositoryModel); + permissionPanel = new AccessPolicyPanel("permissionPanel", repositoryModel); form.add(permissionPanel); // diff --git a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html new file mode 100644 index 00000000..38fa7f6a --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html @@ -0,0 +1,28 @@ + + + + + + +

+

+ + +
+
+ + +
+
+
+ +
+
+
+ +
+ + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java new file mode 100644 index 00000000..a115e251 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java @@ -0,0 +1,171 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.panels; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.Radio; +import org.apache.wicket.markup.html.form.RadioGroup; +import org.apache.wicket.markup.html.list.ListItem; +import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.model.Model; + +import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Keys; +import com.gitblit.models.RepositoryModel; +import com.gitblit.wicket.WicketUtils; + +/** + * A radio group panel of the 5 available authorization/access restriction combinations. + * + * @author James Moger + * + */ +public class AccessPolicyPanel extends BasePanel { + + private static final long serialVersionUID = 1L; + + private final RepositoryModel repository; + + private RadioGroup policiesGroup; + + public AccessPolicyPanel(String wicketId, RepositoryModel repository) { + super(wicketId); + this.repository = repository; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + + AccessPolicy anonymousPolicy = new AccessPolicy(getString("gb.anonymousPolicy"), + getString("gb.anonymousPolicyDescription"), + "blank.png", + AuthorizationControl.AUTHENTICATED, + AccessRestrictionType.NONE); + + AccessPolicy authenticatedPushPolicy = new AccessPolicy(getString("gb.authenticatedPushPolicy"), + getString("gb.authenticatedPushPolicyDescription"), + "lock_go_16x16.png", + AuthorizationControl.AUTHENTICATED, + AccessRestrictionType.PUSH); + + AccessPolicy namedPushPolicy = new AccessPolicy(getString("gb.namedPushPolicy"), + getString("gb.namedPushPolicyDescription"), + "lock_go_16x16.png", + AuthorizationControl.NAMED, + AccessRestrictionType.PUSH); + + AccessPolicy clonePolicy = new AccessPolicy(getString("gb.clonePolicy"), + getString("gb.clonePolicyDescription"), + "lock_pull_16x16.png", + AuthorizationControl.NAMED, + AccessRestrictionType.CLONE); + + AccessPolicy viewPolicy = new AccessPolicy(getString("gb.viewPolicy"), + getString("gb.viewPolicyDescription"), + "shield_16x16.png", + AuthorizationControl.NAMED, + AccessRestrictionType.VIEW); + + List policies = new ArrayList(); + if (app().settings().getBoolean(Keys.git.allowAnonymousPushes, false)) { + policies.add(anonymousPolicy); + } + policies.add(authenticatedPushPolicy); + policies.add(namedPushPolicy); + policies.add(clonePolicy); + policies.add(viewPolicy); + + AccessRestrictionType defaultRestriction = repository.accessRestriction; + if (defaultRestriction == null) { + defaultRestriction = AccessRestrictionType.fromName(app().settings().getString(Keys.git.defaultAccessRestriction, + AccessRestrictionType.PUSH.name())); + } + + AuthorizationControl defaultControl = repository.authorizationControl; + if (defaultControl == null) { + defaultControl = AuthorizationControl.fromName(app().settings().getString(Keys.git.defaultAuthorizationControl, + AuthorizationControl.NAMED.name())); + } + + AccessPolicy defaultPolicy = namedPushPolicy; + for (AccessPolicy policy : policies) { + if (policy.type == defaultRestriction && policy.control == defaultControl) { + defaultPolicy = policy; + } + } + + policiesGroup = new RadioGroup<>("policiesGroup", new Model(defaultPolicy)); + ListView policiesList = new ListView("policies", policies) { + + private static final long serialVersionUID = 1L; + + @Override + protected void populateItem(ListItem item) { + AccessPolicy p = item.getModelObject(); + item.add(new Radio("radio", item.getModel())); + item.add(WicketUtils.newImage("image", p.image)); + item.add(new Label("name", p.name)); + item.add(new Label("description", p.description)); + } + }; + policiesGroup.add(policiesList); + + setOutputMarkupId(true); + + add(policiesGroup); + } + + public void updateModel(RepositoryModel repository) { + AccessPolicy policy = policiesGroup.getModelObject(); + repository.authorizationControl = policy.control; + repository.accessRestriction = policy.type; + } + + @Override + protected boolean getStatelessHint() { + return false; + } + + private static class AccessPolicy implements Serializable { + + private static final long serialVersionUID = 1L; + + final String name; + final String description; + final String image; + final AuthorizationControl control; + final AccessRestrictionType type; + + AccessPolicy(String name, String description, String img, AuthorizationControl control, AccessRestrictionType type) { + this.name = name; + this.description = description; + this.image = img; + this.control = control; + this.type = type; + } + + @Override + public String toString() { + return name; + } + } +} diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html index f3a0738e..3c651620 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html @@ -11,16 +11,19 @@
- -
 

/  
+ +
+
+ +
diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java index 7b20adec..358ff59b 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java @@ -17,18 +17,20 @@ package com.gitblit.wicket.panels; import java.text.MessageFormat; import java.util.ArrayList; -import java.util.List; +import java.util.Set; +import java.util.TreeSet; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.TextField; +import com.gitblit.models.ProjectModel; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; /** - * A radio group panel of the 5 available authorization/access restriction combinations. + * A panel for naming a repository, specifying it's project, and entering a description. * * @author James Moger * @@ -37,44 +39,79 @@ public class RepositoryNamePanel extends BasePanel { private static final long serialVersionUID = 1L; - private final RepositoryModel repository; - private String fullName; + private DropDownChoice projectChoice; + + private TextField nameField; + public RepositoryNamePanel(String wicketId, RepositoryModel repository) { super(wicketId); - this.repository = repository; - } - - @Override - protected void onInitialize() { - super.onInitialize(); GitBlitWebSession session = GitBlitWebSession.get(); UserModel user = session.getUser(); - // build project list for repository destination + // build project set for repository destination String defaultProject = null; - List projects = new ArrayList(); + Set projectNames = new TreeSet(); + + // add the registered/known projects + for (ProjectModel project : app().projects().getProjectModels(user, false)) { + // TODO issue-351: user.canAdmin(project) + if (user.canAdmin()) { + if (project.isRoot) { + projectNames.add("/"); + } else { + projectNames.add(project.name + "/"); + } + } + } - if (user.canAdmin()) { - projects.add("/"); - defaultProject = "/"; + // add the user's personal project namespace + if (user.canAdmin() || user.canCreate()) { + projectNames.add(user.getPersonalPath() + "/"); } - if (user.canCreate()) { - String p = user.getPersonalPath() + "/"; - projects.add(p); - if (defaultProject == null) { - // only prefer personal namespace if default is not already set - defaultProject = p; + if (!StringUtils.isEmpty(repository.name)) { + // editing a repository name + // set the defaultProject to the current repository project + defaultProject = repository.projectPath; + if (StringUtils.isEmpty(defaultProject)) { + defaultProject = "/"; + } else { + defaultProject += "/"; + } + + projectNames.add(defaultProject); + } + + // if default project is not already set, set preference based on the user permissions + if (defaultProject == null) { + if (user.canAdmin()) { + defaultProject = "/"; + } else if (user.canCreate()) { + defaultProject = user.getPersonalPath() + "/"; } } + // update the model which is reflectively mapped to the Wicket fields by name repository.projectPath = defaultProject; + if (repository.projectPath.length() > 1 && !StringUtils.isEmpty(repository.name)) { + repository.name = repository.name.substring(repository.projectPath.length()); + } + projectChoice = new DropDownChoice("projectPath", new ArrayList(projectNames)); + nameField = new TextField("name"); + + // only enable project selection if we actually have multiple choices + add(projectChoice.setEnabled(projectNames.size() > 1)); + add(nameField); + add(new TextField("description")); + } - add(new DropDownChoice("projectPath", projects)); - add(new TextField("name")); + public void setEditable(boolean editable) { + // only enable project selection if we actually have multiple choices + projectChoice.setEnabled(projectChoice.getChoices().size() > 1 && editable); + nameField.setEnabled(editable); } public boolean updateModel(RepositoryModel repositoryModel) { diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.html b/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.html deleted file mode 100644 index 6a4d5cef..00000000 --- a/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - -
-
- - -
-
-
- -
-
-
- -
- - \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java deleted file mode 100644 index ed3f1fed..00000000 --- a/src/main/java/com/gitblit/wicket/panels/RepositoryPermissionPanel.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.gitblit.wicket.panels; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.form.Radio; -import org.apache.wicket.markup.html.form.RadioGroup; -import org.apache.wicket.markup.html.list.ListItem; -import org.apache.wicket.markup.html.list.ListView; -import org.apache.wicket.model.Model; - -import com.gitblit.Constants.AccessRestrictionType; -import com.gitblit.Constants.AuthorizationControl; -import com.gitblit.Keys; -import com.gitblit.models.RepositoryModel; -import com.gitblit.wicket.WicketUtils; - -/** - * A radio group panel of the 5 available authorization/access restriction combinations. - * - * @author James Moger - * - */ -public class RepositoryPermissionPanel extends BasePanel { - - private static final long serialVersionUID = 1L; - - private final RepositoryModel repository; - - private RadioGroup permissionGroup; - - public RepositoryPermissionPanel(String wicketId, RepositoryModel repository) { - super(wicketId); - this.repository = repository; - } - - @Override - protected void onInitialize() { - super.onInitialize(); - - Permission anonymousPermission = new Permission(getString("gb.anonymousPush"), - getString("gb.anonymousPushDescription"), - "blank.png", - AuthorizationControl.AUTHENTICATED, - AccessRestrictionType.NONE); - - Permission authenticatedPermission = new Permission(getString("gb.pushRestrictedAuthenticated"), - getString("gb.pushRestrictedAuthenticatedDescription"), - "lock_go_16x16.png", - AuthorizationControl.AUTHENTICATED, - AccessRestrictionType.PUSH); - - Permission publicPermission = new Permission(getString("gb.pushRestrictedNamed"), - getString("gb.pushRestrictedNamedDescription"), - "lock_go_16x16.png", - AuthorizationControl.NAMED, - AccessRestrictionType.PUSH); - - Permission protectedPermission = new Permission(getString("gb.cloneRestricted"), - getString("gb.cloneRestrictedDescription"), - "lock_pull_16x16.png", - AuthorizationControl.NAMED, - AccessRestrictionType.CLONE); - - Permission privatePermission = new Permission(getString("gb.private"), - getString("gb.privateRepoDescription"), - "shield_16x16.png", - AuthorizationControl.NAMED, - AccessRestrictionType.VIEW); - - List permissions = new ArrayList(); - if (app().settings().getBoolean(Keys.git.allowAnonymousPushes, false)) { - permissions.add(anonymousPermission); - } - permissions.add(authenticatedPermission); - permissions.add(publicPermission); - permissions.add(protectedPermission); - permissions.add(privatePermission); - - AccessRestrictionType defaultRestriction = repository.accessRestriction; - if (defaultRestriction == null) { - defaultRestriction = AccessRestrictionType.fromName(app().settings().getString(Keys.git.defaultAccessRestriction, - AccessRestrictionType.PUSH.name())); - } - - AuthorizationControl defaultControl = repository.authorizationControl; - if (defaultControl == null) { - defaultControl = AuthorizationControl.fromName(app().settings().getString(Keys.git.defaultAuthorizationControl, - AuthorizationControl.NAMED.name())); - } - - Permission defaultPermission = publicPermission; - for (Permission permission : permissions) { - if (permission.type == defaultRestriction && permission.control == defaultControl) { - defaultPermission = permission; - } - } - - permissionGroup = new RadioGroup<>("permissionsGroup", new Model(defaultPermission)); - ListView permissionsList = new ListView("permissions", permissions) { - - private static final long serialVersionUID = 1L; - - @Override - protected void populateItem(ListItem item) { - Permission p = item.getModelObject(); - item.add(new Radio("radio", item.getModel())); - item.add(WicketUtils.newImage("image", p.image)); - item.add(new Label("name", p.name)); - item.add(new Label("description", p.description)); - } - }; - permissionGroup.add(permissionsList); - - setOutputMarkupId(true); - - add(permissionGroup); - } - - public void updateModel(RepositoryModel repository) { - Permission permission = permissionGroup.getModelObject(); - repository.authorizationControl = permission.control; - repository.accessRestriction = permission.type; - } - - @Override - protected boolean getStatelessHint() { - return false; - } - - private static class Permission implements Serializable { - - private static final long serialVersionUID = 1L; - - final String name; - final String description; - final String image; - final AuthorizationControl control; - final AccessRestrictionType type; - - Permission(String name, String description, String img, AuthorizationControl control, AccessRestrictionType type) { - this.name = name; - this.description = description; - this.image = img; - this.control = control; - this.type = type; - } - - @Override - public String toString() { - return name; - } - } -} -- cgit v1.2.3 From 6a437ec4a6853bdd15f7c33f7fbafdd247a3790c Mon Sep 17 00:00:00 2001 From: James Moger Date: Sat, 31 May 2014 10:23:56 -0400 Subject: Use AccessPolicyPanel in EditRepositoryPage --- .../com/gitblit/wicket/GitBlitWebApp.properties | 4 +- .../gitblit/wicket/pages/EditRepositoryPage.html | 4 +- .../gitblit/wicket/pages/EditRepositoryPage.java | 91 +++------------------- .../gitblit/wicket/pages/NewRepositoryPage.html | 6 +- .../gitblit/wicket/pages/NewRepositoryPage.java | 10 +-- .../gitblit/wicket/panels/AccessPolicyPanel.java | 17 +++- 6 files changed, 33 insertions(+), 99 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index d2d1454e..13abcc06 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -687,7 +687,7 @@ gb.plugins = plugins gb.extensions = extensions gb.pleaseSelectProject = Please select the project! gb.accessPolicy = Access Policy -gb.accessPolicyDescription = Choose an access policy to control visibility, cloning, and pushing to this repository. +gb.accessPolicyDescription = Choose an access policy to control repository visibility and git permissions. gb.anonymousPolicy = Anonymous View, Clone, & Push gb.anonymousPolicyDescription = Anyone can see, clone, and push to this repository. gb.authenticatedPushPolicy = Restrict Push (Authenticated) @@ -704,5 +704,3 @@ gb.initWithReadme = Include a README gb.initWithReadmeDescription = This will generate a simple README document for your repository. gb.initWithGitignore = Include a .gitignore file gb.initWithGitignoreDescription = This will insert a config file that instructs your Git clients to ignore files or directories that match defined patterns. -gb.initWithGitflow = Include a .gitflow file -gb.initWithGitflowDescription = This will generate a config file which guides Git clients in setting up Gitflow branches. \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html index ccb60a5c..ab448038 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html @@ -58,9 +58,7 @@
-   diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java index 4759fd0d..e86bd1ee 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -29,7 +29,6 @@ import java.util.Set; import org.apache.wicket.PageParameters; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior; -import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.behavior.SimpleAttributeModifier; import org.apache.wicket.extensions.markup.html.form.palette.Palette; import org.apache.wicket.markup.html.WebMarkupContainer; @@ -40,7 +39,6 @@ import org.apache.wicket.markup.html.form.ChoiceRenderer; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.html.form.IChoiceRenderer; -import org.apache.wicket.markup.html.form.RadioChoice; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.link.Link; import org.apache.wicket.markup.html.list.ListItem; @@ -69,6 +67,7 @@ import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.StringChoiceRenderer; import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.panels.AccessPolicyPanel; import com.gitblit.wicket.panels.BasePanel.JavascriptEventConfirmation; import com.gitblit.wicket.panels.BulletListPanel; import com.gitblit.wicket.panels.RegistrantPermissionsPanel; @@ -80,6 +79,8 @@ public class EditRepositoryPage extends RootSubPage { RepositoryNamePanel namePanel; + AccessPolicyPanel accessPolicyPanel; + private boolean isAdmin; RepositoryModel repositoryModel; @@ -396,9 +397,6 @@ public class EditRepositoryPage extends RootSubPage { form.add(ownersPalette); form.add(new CheckBox("allowForks").setEnabled(app().settings().getBoolean(Keys.web.allowForking, true))); - DropDownChoice accessRestriction = new DropDownChoice("accessRestriction", - AccessRestrictionType.choices(app().settings().getBoolean(Keys.git.allowAnonymousPushes, false)), new AccessRestrictionRenderer()); - form.add(accessRestriction); form.add(new CheckBox("isFrozen")); // TODO enable origin definition form.add(new TextField("origin").setEnabled(false/* isCreate */)); @@ -456,11 +454,6 @@ public class EditRepositoryPage extends RootSubPage { form.add(new TextField("mailingLists", mailingLists)); form.add(indexedBranchesPalette); - List acList = Arrays.asList(AuthorizationControl.values()); - final RadioChoice authorizationControl = new RadioChoice( - "authorizationControl", acList, new AuthorizationControlRenderer()); - form.add(authorizationControl); - final CheckBox verifyCommitter = new CheckBox("verifyCommitter"); verifyCommitter.setOutputMarkupId(true); form.add(verifyCommitter); @@ -484,12 +477,10 @@ public class EditRepositoryPage extends RootSubPage { // anonymous everything, disable all controls usersPalette.setEnabled(false); teamsPalette.setEnabled(false); - authorizationControl.setEnabled(false); verifyCommitter.setEnabled(false); } else { // authenticated something // enable authorization controls - authorizationControl.setEnabled(true); verifyCommitter.setEnabled(true); boolean allowFineGrainedControls = repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED); @@ -497,15 +488,15 @@ public class EditRepositoryPage extends RootSubPage { teamsPalette.setEnabled(allowFineGrainedControls); } - accessRestriction.add(new AjaxFormComponentUpdatingBehavior("onchange") { + AjaxFormChoiceComponentUpdatingBehavior callback = new AjaxFormChoiceComponentUpdatingBehavior() { private static final long serialVersionUID = 1L; @Override protected void onUpdate(AjaxRequestTarget target) { - // enable/disable permissions panel based on access restriction + accessPolicyPanel.updateModel(repositoryModel); + boolean allowAuthorizationControl = repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE); - authorizationControl.setEnabled(allowAuthorizationControl); verifyCommitter.setEnabled(allowAuthorizationControl); boolean allowFineGrainedControls = allowAuthorizationControl && repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED); @@ -516,36 +507,14 @@ public class EditRepositoryPage extends RootSubPage { repositoryModel.authorizationControl = AuthorizationControl.NAMED; } - target.addComponent(authorizationControl); target.addComponent(verifyCommitter); target.addComponent(usersPalette); target.addComponent(teamsPalette); } - }); - - authorizationControl.add(new AjaxFormChoiceComponentUpdatingBehavior() { - - private static final long serialVersionUID = 1L; - - @Override - protected void onUpdate(AjaxRequestTarget target) { - // enable/disable permissions panel based on access restriction - boolean allowAuthorizationControl = repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE); - authorizationControl.setEnabled(allowAuthorizationControl); - - boolean allowFineGrainedControls = allowAuthorizationControl && repositoryModel.authorizationControl.equals(AuthorizationControl.NAMED); - usersPalette.setEnabled(allowFineGrainedControls); - teamsPalette.setEnabled(allowFineGrainedControls); + }; - if (allowFineGrainedControls) { - repositoryModel.authorizationControl = AuthorizationControl.NAMED; - } - - target.addComponent(authorizationControl); - target.addComponent(usersPalette); - target.addComponent(teamsPalette); - } - }); + accessPolicyPanel = new AccessPolicyPanel("accessPolicyPanel", repositoryModel, callback); + form.add(accessPolicyPanel); List renderers = Arrays.asList(CommitMessageRenderer.values()); DropDownChoice messageRendererChoice = new DropDownChoice("commitMessageRenderer", renderers); @@ -656,27 +625,6 @@ public class EditRepositoryPage extends RootSubPage { } } - private class AccessRestrictionRenderer implements IChoiceRenderer { - - private static final long serialVersionUID = 1L; - - private final Map map; - - public AccessRestrictionRenderer() { - map = getAccessRestrictions(); - } - - @Override - public String getDisplayValue(AccessRestrictionType type) { - return map.get(type); - } - - @Override - public String getIdValue(AccessRestrictionType type, int index) { - return Integer.toString(index); - } - } - private class FederationTypeRenderer implements IChoiceRenderer { private static final long serialVersionUID = 1L; @@ -698,27 +646,6 @@ public class EditRepositoryPage extends RootSubPage { } } - private class AuthorizationControlRenderer implements IChoiceRenderer { - - private static final long serialVersionUID = 1L; - - private final Map map; - - public AuthorizationControlRenderer() { - map = getAuthorizationControls(); - } - - @Override - public String getDisplayValue(AuthorizationControl type) { - return map.get(type); - } - - @Override - public String getIdValue(AuthorizationControl type, int index) { - return Integer.toString(index); - } - } - private class GCPeriodRenderer implements IChoiceRenderer { private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html index 8e4e74ac..df55381a 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html @@ -14,7 +14,7 @@
-
+

@@ -39,8 +39,8 @@
- -

+ Include a .gitflow file +

This will generate a config file which guides Git clients in setting up Gitflow branches.

diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java index 0adb1ddd..d5ae3440 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java @@ -59,8 +59,8 @@ import com.gitblit.utils.FileUtils; import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; -import com.gitblit.wicket.panels.RepositoryNamePanel; import com.gitblit.wicket.panels.AccessPolicyPanel; +import com.gitblit.wicket.panels.RepositoryNamePanel; public class NewRepositoryPage extends RootSubPage { @@ -69,7 +69,7 @@ public class NewRepositoryPage extends RootSubPage { private Model gitignoreModel; private IModel addGitflowModel; private IModel addGitignoreModel; - private AccessPolicyPanel permissionPanel; + private AccessPolicyPanel accessPolicyPanel; private RepositoryNamePanel namePanel; public NewRepositoryPage() { @@ -108,7 +108,7 @@ public class NewRepositoryPage extends RootSubPage { if (!namePanel.updateModel(repositoryModel)) { return; } - permissionPanel.updateModel(repositoryModel); + accessPolicyPanel.updateModel(repositoryModel); repositoryModel.owners = new ArrayList(); repositoryModel.owners.add(GitBlitWebSession.get().getUsername()); @@ -174,8 +174,8 @@ public class NewRepositoryPage extends RootSubPage { repositoryModel.authorizationControl = defaultControl; repositoryModel.accessRestriction = defaultRestriction; - permissionPanel = new AccessPolicyPanel("permissionPanel", repositoryModel); - form.add(permissionPanel); + accessPolicyPanel = new AccessPolicyPanel("accessPolicyPanel", repositoryModel); + form.add(accessPolicyPanel); // // initial commit options diff --git a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java index a115e251..057b96f4 100644 --- a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java @@ -19,6 +19,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Radio; import org.apache.wicket.markup.html.form.RadioGroup; @@ -44,11 +45,18 @@ public class AccessPolicyPanel extends BasePanel { private final RepositoryModel repository; + private final AjaxFormChoiceComponentUpdatingBehavior callback; + private RadioGroup policiesGroup; public AccessPolicyPanel(String wicketId, RepositoryModel repository) { + this(wicketId, repository, null); + } + + public AccessPolicyPanel(String wicketId, RepositoryModel repository, AjaxFormChoiceComponentUpdatingBehavior callback) { super(wicketId); this.repository = repository; + this.callback = callback; } @Override @@ -128,10 +136,13 @@ public class AccessPolicyPanel extends BasePanel { } }; policiesGroup.add(policiesList); + if (callback != null) { + policiesGroup.add(callback); + policiesGroup.setOutputMarkupId(true); + } + add(policiesGroup); setOutputMarkupId(true); - - add(policiesGroup); } public void updateModel(RepositoryModel repository) { @@ -145,7 +156,7 @@ public class AccessPolicyPanel extends BasePanel { return false; } - private static class AccessPolicy implements Serializable { + public static class AccessPolicy implements Serializable { private static final long serialVersionUID = 1L; -- cgit v1.2.3 From 85b5d72949ead641ba697543324ff5d236e23fd1 Mon Sep 17 00:00:00 2001 From: James Moger Date: Tue, 3 Jun 2014 00:16:38 -0400 Subject: Overhaul EditRepositoryPage for layout and usability --- .../com/gitblit/wicket/GitBlitWebApp.properties | 24 +- .../gitblit/wicket/pages/EditRepositoryPage.html | 242 ++++++++++++----- .../gitblit/wicket/pages/EditRepositoryPage.java | 288 ++++++++++++++++----- .../gitblit/wicket/panels/AccessPolicyPanel.html | 35 ++- .../gitblit/wicket/panels/AccessPolicyPanel.java | 20 ++ .../gitblit/wicket/panels/RepositoryNamePanel.html | 2 +- 6 files changed, 470 insertions(+), 141 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 13abcc06..bd5d89e0 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -133,7 +133,7 @@ gb.sendProposal = propose gb.status = status gb.origin = origin gb.headRef = default branch (HEAD) -gb.headRefDescription = change the ref that HEAD links to. e.g. refs/heads/master +gb.headRefDescription = The default branch that will be cloned and displayed on the Summary page. gb.federationStrategy = federation strategy gb.federationRegistration = federation registration gb.federationResults = federation pull results @@ -223,8 +223,8 @@ gb.queryResults = results {0} - {1} ({2} hits) gb.noHits = no hits gb.authored = authored gb.committed = committed -gb.indexedBranches = indexed branches -gb.indexedBranchesDescription = select the branches to include in your Lucene index +gb.indexedBranches = Indexed Branches +gb.indexedBranchesDescription = Select the branches to be indexed by Lucene gb.noIndexedRepositoriesWarning = none of your repositories are configured for Lucene indexing gb.undefinedQueryWarning = query is undefined! gb.noSelectedRepositoriesWarning = please select one or more repositories! @@ -704,3 +704,21 @@ gb.initWithReadme = Include a README gb.initWithReadmeDescription = This will generate a simple README document for your repository. gb.initWithGitignore = Include a .gitignore file gb.initWithGitignoreDescription = This will insert a config file that instructs your Git clients to ignore files or directories that match defined patterns. +gb.receive = receive +gb.permissions = permissions +gb.ownersDescription = Owners can manage all repository settings but they are not allowed to rename a repository unless it is their personal repository. +gb.userPermissionsDescription = You can specify individual user permissions. These settings will override team or regex permissions. +gb.teamPermissionsDescription = You can specify individual team permissions. These settings will override regex permissions. +gb.ticketSettings = Ticket Settings +gb.receiveSettings = Receive Settings +gb.receiveSettingsDescription = The receive settings control pushes to the repository. +gb.preReceiveDescription = Pre-receive hooks are executed after commits are received but BEFORE the refs are updated.

This is the appropriate hook for rejecting a push.

+gb.postReceiveDescription = Post-receive hooks are executed after commits are received but AFTER the refs are updated.

This is the appropriate hook for notifications, build triggers, etc.

+gb.federationStrategyDescription = Control if and how to federate this repository with another Gitblit. +gb.federationSetsDescription = This repository will be included in the selected federation sets. +gb.miscellaneous = miscellaneous +gb.originDescription = The url from which this repository was cloned. +gb.gc = GC +gb.garbageCollection = Garbage Collection +gb.garbageCollectionDescription = The garbage collector will pack loose objects pushed from clients and will remove unreferenced objects from the repository. +gb.commitMessageRendererDescription = Commit messages can be displayed as plaintext or as rendered markup. \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html index ab448038..b5f9528f 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html @@ -9,14 +9,17 @@
-
+
@@ -24,97 +27,200 @@
-
+ +
+ +
+ +
- - - - - - - - - - - - - - - - - - - - - - - -

 



+ +

+

+
+ +
+ +

+

+
+ +
+ +

+

+
+ +
+ + +
+

+

+ +
+ +
+
+
+ +
+ +

+

+ - - - - - - - - - - - + + + +




-
- -
+
+ +

+

+ - - + + + +
+ +
+
+ +

+

+ + + + +
+
+ +
+ + +
+ +

+

+ +
+ +
+
+
+
+ +
+ + +
+

+

+ +
+ +
+ +
+ +

+

+ +
- -
- - - - -
-
- - - -

 

+ +
+ +

+

+ +
+
-
-
-
-
+ + +
-
-
-
   
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+ +
   
+ +
+
+ + +
+
+ +
+ +
+
+ + +
+
+ +
+ + +
+
+ \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java index e86bd1ee..16dac895 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -43,9 +43,11 @@ import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.link.Link; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.markup.html.panel.Fragment; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.util.CollectionModel; import org.apache.wicket.model.util.ListModel; import org.eclipse.jgit.lib.Repository; @@ -200,7 +202,7 @@ public class EditRepositoryPage extends RootSubPage { } } final Palette ownersPalette = new Palette("owners", new ListModel(owners), new CollectionModel( - persons), new ChoiceRenderer(null, "userId"), 12, true); + persons), new ChoiceRenderer(null, "userId"), 12, false); // indexed local branches palette List allLocalBranches = new ArrayList(); @@ -387,21 +389,7 @@ public class EditRepositoryPage extends RootSubPage { } }; - // do not let the browser pre-populate these fields - form.add(new SimpleAttributeModifier("autocomplete", "off")); - - // field names reflective match RepositoryModel fields - namePanel = new RepositoryNamePanel("namePanel", repositoryModel); - namePanel.setEditable(allowEditName); - form.add(namePanel); - - form.add(ownersPalette); - form.add(new CheckBox("allowForks").setEnabled(app().settings().getBoolean(Keys.web.allowForking, true))); - form.add(new CheckBox("isFrozen")); - // TODO enable origin definition - form.add(new TextField("origin").setEnabled(false/* isCreate */)); - - // allow relinking HEAD to a branch or tag other than master on edit repository + // Determine available refs & branches List availableRefs = new ArrayList(); List availableBranches = new ArrayList(); if (!ArrayUtils.isEmpty(repositoryModel.availableRefs)) { @@ -414,53 +402,79 @@ public class EditRepositoryPage extends RootSubPage { } } } - form.add(new DropDownChoice("HEAD", availableRefs).setEnabled(availableRefs.size() > 0)); - boolean gcEnabled = app().settings().getBoolean(Keys.git.enableGarbageCollection, false); - int defaultGcPeriod = app().settings().getInteger(Keys.git.defaultGarbageCollectionPeriod, 7); - if (repositoryModel.gcPeriod == 0) { - repositoryModel.gcPeriod = defaultGcPeriod; - } - List gcPeriods = Arrays.asList(1, 2, 3, 4, 5, 7, 10, 14 ); - form.add(new DropDownChoice("gcPeriod", gcPeriods, new GCPeriodRenderer()).setEnabled(gcEnabled)); - form.add(new TextField("gcThreshold").setEnabled(gcEnabled)); + // do not let the browser pre-populate these fields + form.add(new SimpleAttributeModifier("autocomplete", "off")); - // federation strategies - remove ORIGIN choice if this repository has - // no origin. - List federationStrategies = new ArrayList( - Arrays.asList(FederationStrategy.values())); - if (StringUtils.isEmpty(repositoryModel.origin)) { - federationStrategies.remove(FederationStrategy.FEDERATE_ORIGIN); - } - form.add(new DropDownChoice("federationStrategy", federationStrategies, - new FederationTypeRenderer())); - form.add(new CheckBox("acceptNewPatchsets")); - form.add(new CheckBox("acceptNewTickets")); - form.add(new CheckBox("requireApproval")); - form.add(new DropDownChoice("mergeTo", availableBranches).setEnabled(availableBranches.size() > 0)); - form.add(new CheckBox("useIncrementalPushTags")); - form.add(new CheckBox("showRemoteBranches")); - form.add(new CheckBox("skipSizeCalculation")); - form.add(new CheckBox("skipSummaryMetrics")); - List maxActivityCommits = Arrays.asList(-1, 0, 25, 50, 75, 100, 150, 200, 250, 500); - form.add(new DropDownChoice("maxActivityCommits", maxActivityCommits, new MaxActivityCommitsRenderer())); - metricAuthorExclusions = new Model(ArrayUtils.isEmpty(repositoryModel.metricAuthorExclusions) ? "" - : StringUtils.flattenStrings(repositoryModel.metricAuthorExclusions, " ")); - form.add(new TextField("metricAuthorExclusions", metricAuthorExclusions)); + // + // + // GENERAL + // + namePanel = new RepositoryNamePanel("namePanel", repositoryModel); + namePanel.setEditable(allowEditName); + form.add(namePanel); - mailingLists = new Model(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? "" - : StringUtils.flattenStrings(repositoryModel.mailingLists, " ")); - form.add(new TextField("mailingLists", mailingLists)); - form.add(indexedBranchesPalette); + // XXX AccessPolicyPanel is defined later. + + form.add(newChoice("head", + getString("gb.headRef"), + getString("gb.headRefDescription"), + new PropertyModel(repositoryModel, "HEAD"), + availableRefs)); - final CheckBox verifyCommitter = new CheckBox("verifyCommitter"); - verifyCommitter.setOutputMarkupId(true); - form.add(verifyCommitter); + // + // PERMISSIONS + // + form.add(ownersPalette); form.add(usersPalette); form.add(teamsPalette); - form.add(federationSetsPalette); + + // + // TICKETS + // + form.add(newCheckbox("acceptNewPatchsets", + getString("gb.acceptNewPatchsets"), + getString("gb.acceptNewPatchsetsDescription"), + new PropertyModel(repositoryModel, "acceptNewPatchsets"))); + + form.add(newCheckbox("acceptNewTickets", + getString("gb.acceptNewTickets"), + getString("gb.acceptNewTicketsDescription"), + new PropertyModel(repositoryModel, "acceptNewPatchsets"))); + + form.add(newCheckbox("requireApproval", + getString("gb.requireApproval"), + getString("gb.requireApprovalDescription"), + new PropertyModel(repositoryModel, "requireApproval"))); + + form.add(newChoice("mergeTo", + getString("gb.mergeTo"), + getString("gb.mergeToDescription"), + new PropertyModel(repositoryModel, "mergeTo"), + availableBranches)); + + // + // RECEIVE + // + form.add(newCheckbox("isFrozen", + getString("gb.isFrozen"), + getString("gb.isFrozenDescription"), + new PropertyModel(repositoryModel, "isFrozen"))); + + form.add(newCheckbox("incrementalPushTags", + getString("gb.enableIncrementalPushTags"), + getString("gb.useIncrementalPushTagsDescription"), + new PropertyModel(repositoryModel, "useIncrementalPushTags"))); + + final CheckBox verifyCommitter = new CheckBox("checkbox", new PropertyModel(repositoryModel, "verifyCommitter")); + verifyCommitter.setOutputMarkupId(true); + form.add(newCheckbox("verifyCommitter", + getString("gb.verifyCommitter"), + getString("gb.verifyCommitterDescription"), + verifyCommitter)); + form.add(preReceivePalette); form.add(new BulletListPanel("inheritedPreReceive", getString("gb.inherited"), app().repositories() .getPreReceiveScriptsInherited(repositoryModel))); @@ -472,6 +486,116 @@ public class EditRepositoryPage extends RootSubPage { customFieldsSection.add(customFieldsListView); form.add(customFieldsSection.setVisible(!app().settings().getString(Keys.groovy.customFields, "").isEmpty())); + // + // FEDERATION + // + List federationStrategies = new ArrayList( + Arrays.asList(FederationStrategy.values())); + // federation strategies - remove ORIGIN choice if this repository has no origin. + if (StringUtils.isEmpty(repositoryModel.origin)) { + federationStrategies.remove(FederationStrategy.FEDERATE_ORIGIN); + } + + form.add(newChoice("federationStrategy", + getString("gb.federationStrategy"), + getString("gb.federationStrategyDescription"), + new DropDownChoice( + "choice", + new PropertyModel(repositoryModel, "federationStrategy"), + federationStrategies, + new FederationTypeRenderer()))); + + form.add(federationSetsPalette); + + // + // SEARCH + // + form.add(indexedBranchesPalette); + + // + // GARBAGE COLLECTION + // + boolean gcEnabled = app().settings().getBoolean(Keys.git.enableGarbageCollection, false); + int defaultGcPeriod = app().settings().getInteger(Keys.git.defaultGarbageCollectionPeriod, 7); + if (repositoryModel.gcPeriod == 0) { + repositoryModel.gcPeriod = defaultGcPeriod; + } + List gcPeriods = Arrays.asList(1, 2, 3, 4, 5, 7, 10, 14 ); + form.add(newChoice("gcPeriod", + getString("gb.gcPeriod"), + getString("gb.gcPeriodDescription"), + new DropDownChoice("choice", + new PropertyModel(repositoryModel, "gcPeriod"), + gcPeriods, + new GCPeriodRenderer())).setEnabled(gcEnabled)); + + form.add(newTextfield("gcThreshold", + getString("gb.gcThreshold"), + getString("gb.gcThresholdDescription"), + "span1", + new PropertyModel(repositoryModel, "gcThreshold")).setEnabled(gcEnabled)); + + // + // MISCELLANEOUS + // + + form.add(newTextfield("origin", + getString("gb.origin"), + getString("gb.originDescription"), + "span6", + new PropertyModel(repositoryModel, "origin")).setEnabled(false)); + + form.add(newCheckbox("showRemoteBranches", + getString("gb.showRemoteBranches"), + getString("gb.showRemoteBranchesDescription"), + new PropertyModel(repositoryModel, "showRemoteBranches"))); + + form.add(newCheckbox("skipSizeCalculation", + getString("gb.skipSizeCalculation"), + getString("gb.skipSizeCalculationDescription"), + new PropertyModel(repositoryModel, "skipSizeCalculation"))); + + form.add(newCheckbox("skipSummaryMetrics", + getString("gb.skipSummaryMetrics"), + getString("gb.skipSummaryMetricsDescription"), + new PropertyModel(repositoryModel, "skipSummaryMetrics"))); + + List maxActivityCommits = Arrays.asList(-1, 0, 25, 50, 75, 100, 150, 200, 250, 500); + form.add(newChoice("maxActivityCommits", + getString("gb.maxActivityCommits"), + getString("gb.maxActivityCommitsDescription"), + new DropDownChoice("choice", + new PropertyModel(repositoryModel, "maxActivityCommits"), + maxActivityCommits, + new MaxActivityCommitsRenderer()))); + + List renderers = Arrays.asList(CommitMessageRenderer.values()); + form.add(newChoice("commitMessageRenderer", + getString("gb.commitMessageRenderer"), + getString("gb.commitMessageRendererDescription"), + new DropDownChoice("choice", + new PropertyModel(repositoryModel, "commitMessageRenderer"), + renderers))); + + metricAuthorExclusions = new Model(ArrayUtils.isEmpty(repositoryModel.metricAuthorExclusions) ? "" + : StringUtils.flattenStrings(repositoryModel.metricAuthorExclusions, " ")); + + form.add(newTextfield("metricAuthorExclusions", + getString("gb.metricAuthorExclusions"), + getString("gb.metricAuthorExclusions"), + "span6", + metricAuthorExclusions)); + + mailingLists = new Model(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? "" + : StringUtils.flattenStrings(repositoryModel.mailingLists, " ")); + + form.add(newTextfield("mailingLists", + getString("gb.mailingLists"), + getString("gb.mailingLists"), + "span6", + mailingLists)); + + // initial enable/disable of permission controls if (repositoryModel.accessRestriction.equals(AccessRestrictionType.NONE)) { // anonymous everything, disable all controls @@ -488,6 +612,9 @@ public class EditRepositoryPage extends RootSubPage { teamsPalette.setEnabled(allowFineGrainedControls); } + // + // ACCESS POLICY PANEL (GENERAL) + // AjaxFormChoiceComponentUpdatingBehavior callback = new AjaxFormChoiceComponentUpdatingBehavior() { private static final long serialVersionUID = 1L; @@ -516,10 +643,10 @@ public class EditRepositoryPage extends RootSubPage { accessPolicyPanel = new AccessPolicyPanel("accessPolicyPanel", repositoryModel, callback); form.add(accessPolicyPanel); - List renderers = Arrays.asList(CommitMessageRenderer.values()); - DropDownChoice messageRendererChoice = new DropDownChoice("commitMessageRenderer", renderers); - form.add(messageRendererChoice); + // + // FORM CONTROLS + // form.add(new Button("save")); Button cancel = new Button("cancel") { private static final long serialVersionUID = 1L; @@ -625,6 +752,51 @@ public class EditRepositoryPage extends RootSubPage { } } + private Fragment newCheckbox(String wicketId, String title, String description, IModel model) { + Fragment fragment = new Fragment(wicketId, "checkboxOption", this); + fragment.add(new Label("name", title)); + fragment.add(new Label("description", description)); + fragment.add(new CheckBox("checkbox", model)); + return fragment; + } + + private Fragment newCheckbox(String wicketId, String title, String description, CheckBox checkbox) { + Fragment fragment = new Fragment(wicketId, "checkboxOption", this); + fragment.add(new Label("name", title)); + fragment.add(new Label("description", description)); + fragment.add(checkbox); + return fragment; + } + + private Fragment newChoice(String wicketId, String title, String description, IModel model, List choices) { + Fragment fragment = new Fragment(wicketId, "choiceOption", this); + fragment.add(new Label("name", title)); + fragment.add(new Label("description", description)); + fragment.add(new DropDownChoice<>("choice", model, choices).setEnabled(choices.size() > 0)); + return fragment; + } + + private Fragment newChoice(String wicketId, String title, String description, DropDownChoice choice) { + Fragment fragment = new Fragment(wicketId, "choiceOption", this); + fragment.add(new Label("name", title)); + fragment.add(new Label("description", description)); + fragment.add(choice.setEnabled(choice.getChoices().size() > 0)); + return fragment; + } + + private Fragment newTextfield(String wicketId, String title, String description, String css, IModel model) { + Fragment fragment = new Fragment(wicketId, "textfieldOption", this); + fragment.add(new Label("name", title)); + fragment.add(new Label("description", description)); + TextField tf = new TextField("text", model); + if (!StringUtils.isEmpty(css)) { + WicketUtils.setCssClass(tf, css); + } + fragment.add(tf); + return fragment; + } + + private class FederationTypeRenderer implements IChoiceRenderer { private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html index 38fa7f6a..965c4d51 100644 --- a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html +++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html @@ -10,19 +10,32 @@

- -
-
- - -
-
-
- -
+
+
+
+ +
- +
+
+ +
+
+
+ +
+
+ + +
+
+ +
+ +
+
+ \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java index 057b96f4..7aa801f4 100644 --- a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java @@ -21,10 +21,13 @@ import java.util.List; import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior; import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.Radio; import org.apache.wicket.markup.html.form.RadioGroup; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; +import org.apache.wicket.markup.html.panel.Fragment; +import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import com.gitblit.Constants.AccessRestrictionType; @@ -49,6 +52,8 @@ public class AccessPolicyPanel extends BasePanel { private RadioGroup policiesGroup; + private IModel allowForks; + public AccessPolicyPanel(String wicketId, RepositoryModel repository) { this(wicketId, repository, null); } @@ -142,13 +147,28 @@ public class AccessPolicyPanel extends BasePanel { } add(policiesGroup); + allowForks = Model.of(true); + add(newCheckbox("allowForks", + getString("gb.allowForks"), + getString("gb.allowForksDescription"), + allowForks).setEnabled(app().settings().getBoolean(Keys.web.allowForking, true))); + setOutputMarkupId(true); } + private Fragment newCheckbox(String wicketId, String title, String description, IModel model) { + Fragment fragment = new Fragment(wicketId, "checkboxOption", this); + fragment.add(new Label("name", title)); + fragment.add(new Label("description", description)); + fragment.add(new CheckBox("checkbox", model)); + return fragment; + } + public void updateModel(RepositoryModel repository) { AccessPolicy policy = policiesGroup.getModelObject(); repository.authorizationControl = policy.control; repository.accessRestriction = policy.type; + repository.allowForks = allowForks.getObject(); } @Override diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html index 3c651620..6fb6e45c 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.html @@ -15,7 +15,7 @@   +   -- cgit v1.2.3 From 2cf367f1970133303c872e969861be6147196fef Mon Sep 17 00:00:00 2001 From: James Moger Date: Tue, 3 Jun 2014 09:13:58 -0400 Subject: Extract re-usable checkbox, choice, and text option panels --- .../gitblit/wicket/pages/EditRepositoryPage.html | 33 -------- .../gitblit/wicket/pages/EditRepositoryPage.java | 90 ++++++---------------- .../gitblit/wicket/panels/AccessPolicyPanel.html | 9 --- .../gitblit/wicket/panels/AccessPolicyPanel.java | 12 +-- .../com/gitblit/wicket/panels/CheckboxOption.html | 17 ++++ .../com/gitblit/wicket/panels/CheckboxOption.java | 53 +++++++++++++ .../com/gitblit/wicket/panels/ChoiceOption.html | 19 +++++ .../com/gitblit/wicket/panels/ChoiceOption.java | 51 ++++++++++++ .../wicket/panels/RegistrantPermissionsPanel.html | 2 +- .../java/com/gitblit/wicket/panels/TextOption.html | 20 +++++ .../java/com/gitblit/wicket/panels/TextOption.java | 53 +++++++++++++ 11 files changed, 239 insertions(+), 120 deletions(-) create mode 100644 src/main/java/com/gitblit/wicket/panels/CheckboxOption.html create mode 100644 src/main/java/com/gitblit/wicket/panels/CheckboxOption.java create mode 100644 src/main/java/com/gitblit/wicket/panels/ChoiceOption.html create mode 100644 src/main/java/com/gitblit/wicket/panels/ChoiceOption.java create mode 100644 src/main/java/com/gitblit/wicket/panels/TextOption.html create mode 100644 src/main/java/com/gitblit/wicket/panels/TextOption.java diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html index b5f9528f..1e683b4f 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.html @@ -189,38 +189,5 @@ - -
-
- -
- -
-
- - -
-
- -
- - -
-
- \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java index 16dac895..f891595c 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -43,7 +43,6 @@ import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.link.Link; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; -import org.apache.wicket.markup.html.panel.Fragment; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; @@ -72,8 +71,11 @@ import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.AccessPolicyPanel; import com.gitblit.wicket.panels.BasePanel.JavascriptEventConfirmation; import com.gitblit.wicket.panels.BulletListPanel; +import com.gitblit.wicket.panels.CheckboxOption; +import com.gitblit.wicket.panels.ChoiceOption; import com.gitblit.wicket.panels.RegistrantPermissionsPanel; import com.gitblit.wicket.panels.RepositoryNamePanel; +import com.gitblit.wicket.panels.TextOption; public class EditRepositoryPage extends RootSubPage { @@ -417,7 +419,7 @@ public class EditRepositoryPage extends RootSubPage { // XXX AccessPolicyPanel is defined later. - form.add(newChoice("head", + form.add(new ChoiceOption("head", getString("gb.headRef"), getString("gb.headRefDescription"), new PropertyModel(repositoryModel, "HEAD"), @@ -434,22 +436,22 @@ public class EditRepositoryPage extends RootSubPage { // // TICKETS // - form.add(newCheckbox("acceptNewPatchsets", + form.add(new CheckboxOption("acceptNewPatchsets", getString("gb.acceptNewPatchsets"), getString("gb.acceptNewPatchsetsDescription"), new PropertyModel(repositoryModel, "acceptNewPatchsets"))); - form.add(newCheckbox("acceptNewTickets", + form.add(new CheckboxOption("acceptNewTickets", getString("gb.acceptNewTickets"), getString("gb.acceptNewTicketsDescription"), new PropertyModel(repositoryModel, "acceptNewPatchsets"))); - form.add(newCheckbox("requireApproval", + form.add(new CheckboxOption("requireApproval", getString("gb.requireApproval"), getString("gb.requireApprovalDescription"), new PropertyModel(repositoryModel, "requireApproval"))); - form.add(newChoice("mergeTo", + form.add(new ChoiceOption("mergeTo", getString("gb.mergeTo"), getString("gb.mergeToDescription"), new PropertyModel(repositoryModel, "mergeTo"), @@ -458,22 +460,22 @@ public class EditRepositoryPage extends RootSubPage { // // RECEIVE // - form.add(newCheckbox("isFrozen", + form.add(new CheckboxOption("isFrozen", getString("gb.isFrozen"), getString("gb.isFrozenDescription"), new PropertyModel(repositoryModel, "isFrozen"))); - form.add(newCheckbox("incrementalPushTags", + form.add(new CheckboxOption("incrementalPushTags", getString("gb.enableIncrementalPushTags"), getString("gb.useIncrementalPushTagsDescription"), new PropertyModel(repositoryModel, "useIncrementalPushTags"))); final CheckBox verifyCommitter = new CheckBox("checkbox", new PropertyModel(repositoryModel, "verifyCommitter")); verifyCommitter.setOutputMarkupId(true); - form.add(newCheckbox("verifyCommitter", + form.add(new CheckboxOption("verifyCommitter", getString("gb.verifyCommitter"), - getString("gb.verifyCommitterDescription"), - verifyCommitter)); + getString("gb.verifyCommitterDescription") + "
" + getString("gb.verifyCommitterNote"), + verifyCommitter).setIsHtmlDescription(true)); form.add(preReceivePalette); form.add(new BulletListPanel("inheritedPreReceive", getString("gb.inherited"), app().repositories() @@ -496,7 +498,7 @@ public class EditRepositoryPage extends RootSubPage { federationStrategies.remove(FederationStrategy.FEDERATE_ORIGIN); } - form.add(newChoice("federationStrategy", + form.add(new ChoiceOption("federationStrategy", getString("gb.federationStrategy"), getString("gb.federationStrategyDescription"), new DropDownChoice( @@ -521,7 +523,7 @@ public class EditRepositoryPage extends RootSubPage { repositoryModel.gcPeriod = defaultGcPeriod; } List gcPeriods = Arrays.asList(1, 2, 3, 4, 5, 7, 10, 14 ); - form.add(newChoice("gcPeriod", + form.add(new ChoiceOption("gcPeriod", getString("gb.gcPeriod"), getString("gb.gcPeriodDescription"), new DropDownChoice("choice", @@ -529,7 +531,7 @@ public class EditRepositoryPage extends RootSubPage { gcPeriods, new GCPeriodRenderer())).setEnabled(gcEnabled)); - form.add(newTextfield("gcThreshold", + form.add(new TextOption("gcThreshold", getString("gb.gcThreshold"), getString("gb.gcThresholdDescription"), "span1", @@ -539,29 +541,29 @@ public class EditRepositoryPage extends RootSubPage { // MISCELLANEOUS // - form.add(newTextfield("origin", + form.add(new TextOption("origin", getString("gb.origin"), getString("gb.originDescription"), "span6", new PropertyModel(repositoryModel, "origin")).setEnabled(false)); - form.add(newCheckbox("showRemoteBranches", + form.add(new CheckboxOption("showRemoteBranches", getString("gb.showRemoteBranches"), getString("gb.showRemoteBranchesDescription"), new PropertyModel(repositoryModel, "showRemoteBranches"))); - form.add(newCheckbox("skipSizeCalculation", + form.add(new CheckboxOption("skipSizeCalculation", getString("gb.skipSizeCalculation"), getString("gb.skipSizeCalculationDescription"), new PropertyModel(repositoryModel, "skipSizeCalculation"))); - form.add(newCheckbox("skipSummaryMetrics", + form.add(new CheckboxOption("skipSummaryMetrics", getString("gb.skipSummaryMetrics"), getString("gb.skipSummaryMetricsDescription"), new PropertyModel(repositoryModel, "skipSummaryMetrics"))); List maxActivityCommits = Arrays.asList(-1, 0, 25, 50, 75, 100, 150, 200, 250, 500); - form.add(newChoice("maxActivityCommits", + form.add(new ChoiceOption("maxActivityCommits", getString("gb.maxActivityCommits"), getString("gb.maxActivityCommitsDescription"), new DropDownChoice("choice", @@ -570,7 +572,7 @@ public class EditRepositoryPage extends RootSubPage { new MaxActivityCommitsRenderer()))); List renderers = Arrays.asList(CommitMessageRenderer.values()); - form.add(newChoice("commitMessageRenderer", + form.add(new ChoiceOption("commitMessageRenderer", getString("gb.commitMessageRenderer"), getString("gb.commitMessageRendererDescription"), new DropDownChoice("choice", @@ -580,7 +582,7 @@ public class EditRepositoryPage extends RootSubPage { metricAuthorExclusions = new Model(ArrayUtils.isEmpty(repositoryModel.metricAuthorExclusions) ? "" : StringUtils.flattenStrings(repositoryModel.metricAuthorExclusions, " ")); - form.add(newTextfield("metricAuthorExclusions", + form.add(new TextOption("metricAuthorExclusions", getString("gb.metricAuthorExclusions"), getString("gb.metricAuthorExclusions"), "span6", @@ -589,7 +591,7 @@ public class EditRepositoryPage extends RootSubPage { mailingLists = new Model(ArrayUtils.isEmpty(repositoryModel.mailingLists) ? "" : StringUtils.flattenStrings(repositoryModel.mailingLists, " ")); - form.add(newTextfield("mailingLists", + form.add(new TextOption("mailingLists", getString("gb.mailingLists"), getString("gb.mailingLists"), "span6", @@ -752,50 +754,6 @@ public class EditRepositoryPage extends RootSubPage { } } - private Fragment newCheckbox(String wicketId, String title, String description, IModel model) { - Fragment fragment = new Fragment(wicketId, "checkboxOption", this); - fragment.add(new Label("name", title)); - fragment.add(new Label("description", description)); - fragment.add(new CheckBox("checkbox", model)); - return fragment; - } - - private Fragment newCheckbox(String wicketId, String title, String description, CheckBox checkbox) { - Fragment fragment = new Fragment(wicketId, "checkboxOption", this); - fragment.add(new Label("name", title)); - fragment.add(new Label("description", description)); - fragment.add(checkbox); - return fragment; - } - - private Fragment newChoice(String wicketId, String title, String description, IModel model, List choices) { - Fragment fragment = new Fragment(wicketId, "choiceOption", this); - fragment.add(new Label("name", title)); - fragment.add(new Label("description", description)); - fragment.add(new DropDownChoice<>("choice", model, choices).setEnabled(choices.size() > 0)); - return fragment; - } - - private Fragment newChoice(String wicketId, String title, String description, DropDownChoice choice) { - Fragment fragment = new Fragment(wicketId, "choiceOption", this); - fragment.add(new Label("name", title)); - fragment.add(new Label("description", description)); - fragment.add(choice.setEnabled(choice.getChoices().size() > 0)); - return fragment; - } - - private Fragment newTextfield(String wicketId, String title, String description, String css, IModel model) { - Fragment fragment = new Fragment(wicketId, "textfieldOption", this); - fragment.add(new Label("name", title)); - fragment.add(new Label("description", description)); - TextField tf = new TextField("text", model); - if (!StringUtils.isEmpty(css)) { - WicketUtils.setCssClass(tf, css); - } - fragment.add(tf); - return fragment; - } - private class FederationTypeRenderer implements IChoiceRenderer { diff --git a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html index 965c4d51..d3c29ba7 100644 --- a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html +++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html @@ -27,15 +27,6 @@
- -
-
- -
- -
-
- \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java index 7aa801f4..4f234263 100644 --- a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.java @@ -21,12 +21,10 @@ import java.util.List; import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior; import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.markup.html.form.Radio; import org.apache.wicket.markup.html.form.RadioGroup; import org.apache.wicket.markup.html.list.ListItem; import org.apache.wicket.markup.html.list.ListView; -import org.apache.wicket.markup.html.panel.Fragment; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; @@ -148,7 +146,7 @@ public class AccessPolicyPanel extends BasePanel { add(policiesGroup); allowForks = Model.of(true); - add(newCheckbox("allowForks", + add(new CheckboxOption("allowForks", getString("gb.allowForks"), getString("gb.allowForksDescription"), allowForks).setEnabled(app().settings().getBoolean(Keys.web.allowForking, true))); @@ -156,14 +154,6 @@ public class AccessPolicyPanel extends BasePanel { setOutputMarkupId(true); } - private Fragment newCheckbox(String wicketId, String title, String description, IModel model) { - Fragment fragment = new Fragment(wicketId, "checkboxOption", this); - fragment.add(new Label("name", title)); - fragment.add(new Label("description", description)); - fragment.add(new CheckBox("checkbox", model)); - return fragment; - } - public void updateModel(RepositoryModel repository) { AccessPolicy policy = policiesGroup.getModelObject(); repository.authorizationControl = policy.control; diff --git a/src/main/java/com/gitblit/wicket/panels/CheckboxOption.html b/src/main/java/com/gitblit/wicket/panels/CheckboxOption.html new file mode 100644 index 00000000..6684fe92 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/CheckboxOption.html @@ -0,0 +1,17 @@ + + + + + +
+
+ +
+ +
+
+ + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java b/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java new file mode 100644 index 00000000..086d8ef2 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.panels; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.CheckBox; +import org.apache.wicket.model.IModel; + +/** + * A re-usable checkbox option panel. + * + * [x] title + * description + * + * @author James Moger + * + */ +public class CheckboxOption extends BasePanel { + + private static final long serialVersionUID = 1L; + + public CheckboxOption(String wicketId, String title, String description, IModel model) { + super(wicketId); + add(new Label("name", title)); + add(new Label("description", description)); + add(new CheckBox("checkbox", model)); + } + + public CheckboxOption(String wicketId, String title, String description, CheckBox checkbox) { + super(wicketId); + add(new Label("name", title)); + add(new Label("description", description)); + add(checkbox.setMarkupId("checkbox")); + } + + public CheckboxOption setIsHtmlDescription(boolean val) { + ((Label) get("description")).setEscapeModelStrings(!val); + return this; + } +} diff --git a/src/main/java/com/gitblit/wicket/panels/ChoiceOption.html b/src/main/java/com/gitblit/wicket/panels/ChoiceOption.html new file mode 100644 index 00000000..8c34c819 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/ChoiceOption.html @@ -0,0 +1,19 @@ + + + + + +
+
+ +
+
diff --git a/src/main/java/com/gitblit/wicket/panels/TextOption.html b/src/main/java/com/gitblit/wicket/panels/TextOption.html new file mode 100644 index 00000000..ff2da78e --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/TextOption.html @@ -0,0 +1,20 @@ + + + + + +
+
+ +
+ + +
+
+ + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/TextOption.java b/src/main/java/com/gitblit/wicket/panels/TextOption.java new file mode 100644 index 00000000..dcd465fb --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/TextOption.java @@ -0,0 +1,53 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.panels; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.model.IModel; + +import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.WicketUtils; + +/** + * A re-usable textfield option panel. + * + * title + * description + * [textfield] + * + * @author James Moger + * + */ +public class TextOption extends BasePanel { + + private static final long serialVersionUID = 1L; + + public TextOption(String wicketId, String title, String description, IModel model) { + this(wicketId, title, description, null, model); + } + + public TextOption(String wicketId, String title, String description, String css, IModel model) { + super(wicketId); + add(new Label("name", title)); + add(new Label("description", description)); + TextField tf = new TextField("text", model); + if (!StringUtils.isEmpty(css)) { + WicketUtils.setCssClass(tf, css); + } + add(tf); + } +} -- cgit v1.2.3 From 7b8654dec60d378059bd9d765abcfd597b80ab5f Mon Sep 17 00:00:00 2001 From: James Moger Date: Tue, 3 Jun 2014 09:21:57 -0400 Subject: Use alignment from option panels un AccessPolicyPanel --- src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html index d3c29ba7..a2d76b7e 100644 --- a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html +++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html @@ -12,14 +12,10 @@
-
- - -
-
-
- +
+
+
-- cgit v1.2.3 From 6cc8ec025ad26f1451f0947fa4ad79bb2f9c292a Mon Sep 17 00:00:00 2001 From: James Moger Date: Tue, 3 Jun 2014 09:24:39 -0400 Subject: Hide empty option descriptions --- src/main/java/com/gitblit/wicket/panels/CheckboxOption.java | 5 +++-- src/main/java/com/gitblit/wicket/panels/ChoiceOption.java | 5 +++-- src/main/java/com/gitblit/wicket/panels/TextOption.java | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java b/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java index 086d8ef2..08eeaa24 100644 --- a/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java +++ b/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java @@ -18,6 +18,7 @@ package com.gitblit.wicket.panels; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.CheckBox; import org.apache.wicket.model.IModel; +import org.parboiled.common.StringUtils; /** * A re-usable checkbox option panel. @@ -35,14 +36,14 @@ public class CheckboxOption extends BasePanel { public CheckboxOption(String wicketId, String title, String description, IModel model) { super(wicketId); add(new Label("name", title)); - add(new Label("description", description)); + add(new Label("description", description).setVisible(!StringUtils.isEmpty(description))); add(new CheckBox("checkbox", model)); } public CheckboxOption(String wicketId, String title, String description, CheckBox checkbox) { super(wicketId); add(new Label("name", title)); - add(new Label("description", description)); + add(new Label("description", description).setVisible(!StringUtils.isEmpty(description))); add(checkbox.setMarkupId("checkbox")); } diff --git a/src/main/java/com/gitblit/wicket/panels/ChoiceOption.java b/src/main/java/com/gitblit/wicket/panels/ChoiceOption.java index cc084a7b..9c25b70a 100644 --- a/src/main/java/com/gitblit/wicket/panels/ChoiceOption.java +++ b/src/main/java/com/gitblit/wicket/panels/ChoiceOption.java @@ -20,6 +20,7 @@ import java.util.List; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.model.IModel; +import org.parboiled.common.StringUtils; /** * A re-usable choice option panel. @@ -38,14 +39,14 @@ public class ChoiceOption extends BasePanel { public ChoiceOption(String wicketId, String title, String description, IModel model, List choices) { super(wicketId); add(new Label("name", title)); - add(new Label("description", description)); + add(new Label("description", description).setVisible(!StringUtils.isEmpty(description))); add(new DropDownChoice<>("choice", model, choices).setEnabled(choices.size() > 0)); } public ChoiceOption(String wicketId, String title, String description, DropDownChoice choice) { super(wicketId); add(new Label("name", title)); - add(new Label("description", description)); + add(new Label("description", description).setVisible(!StringUtils.isEmpty(description))); add(choice.setMarkupId("choice").setEnabled(choice.getChoices().size() > 0)); } } diff --git a/src/main/java/com/gitblit/wicket/panels/TextOption.java b/src/main/java/com/gitblit/wicket/panels/TextOption.java index dcd465fb..22370f3c 100644 --- a/src/main/java/com/gitblit/wicket/panels/TextOption.java +++ b/src/main/java/com/gitblit/wicket/panels/TextOption.java @@ -43,7 +43,7 @@ public class TextOption extends BasePanel { public TextOption(String wicketId, String title, String description, String css, IModel model) { super(wicketId); add(new Label("name", title)); - add(new Label("description", description)); + add(new Label("description", description).setVisible(!StringUtils.isEmpty(description))); TextField tf = new TextField("text", model); if (!StringUtils.isEmpty(css)) { WicketUtils.setCssClass(tf, css); -- cgit v1.2.3 From ba516f6c6aaabf7935ef42292f446bf375bf542b Mon Sep 17 00:00:00 2001 From: James Moger Date: Tue, 3 Jun 2014 09:56:50 -0400 Subject: Extract re-usable conditional choice option panel --- .../gitblit/wicket/pages/NewRepositoryPage.html | 36 ++-------- .../gitblit/wicket/pages/NewRepositoryPage.java | 44 ++++++------ .../wicket/panels/ConditionalChoiceOption.html | 19 ++++++ .../wicket/panels/ConditionalChoiceOption.java | 78 ++++++++++++++++++++++ 4 files changed, 120 insertions(+), 57 deletions(-) create mode 100644 src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.html create mode 100644 src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.java diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html index df55381a..115b8c10 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.html @@ -19,41 +19,13 @@

-
-

-
+

-
-
- -
-
-
-

-
-
+
-
- -
- -
-
- Include a .gitflow file -

This will generate a config file which guides Git clients in setting up Gitflow branches.

-
-
+
-
-
- -
-
-
-

-

+

+
+
+ +
+ + + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/BooleanOption.java b/src/main/java/com/gitblit/wicket/panels/BooleanOption.java new file mode 100644 index 00000000..4a9299ce --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/BooleanOption.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.panels; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.CheckBox; +import org.apache.wicket.model.IModel; +import org.parboiled.common.StringUtils; + +/** + * A re-usable checkbox option panel. + * + * [x] title + * description + * + * @author James Moger + * + */ +public class BooleanOption extends BasePanel { + + private static final long serialVersionUID = 1L; + + public BooleanOption(String wicketId, String title, String description, IModel model) { + super(wicketId); + add(new Label("name", title)); + add(new Label("description", description).setVisible(!StringUtils.isEmpty(description))); + add(new CheckBox("checkbox", model)); + } + + public BooleanOption(String wicketId, String title, String description, CheckBox checkbox) { + super(wicketId); + add(new Label("name", title)); + add(new Label("description", description).setVisible(!StringUtils.isEmpty(description))); + add(checkbox.setMarkupId("checkbox")); + } + + public BooleanOption setIsHtmlDescription(boolean val) { + ((Label) get("description")).setEscapeModelStrings(!val); + return this; + } +} diff --git a/src/main/java/com/gitblit/wicket/panels/CheckboxOption.html b/src/main/java/com/gitblit/wicket/panels/CheckboxOption.html deleted file mode 100644 index 6684fe92..00000000 --- a/src/main/java/com/gitblit/wicket/panels/CheckboxOption.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - -
-
- -
- -
-
- - \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java b/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java deleted file mode 100644 index 08eeaa24..00000000 --- a/src/main/java/com/gitblit/wicket/panels/CheckboxOption.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2014 gitblit.com. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.gitblit.wicket.panels; - -import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.form.CheckBox; -import org.apache.wicket.model.IModel; -import org.parboiled.common.StringUtils; - -/** - * A re-usable checkbox option panel. - * - * [x] title - * description - * - * @author James Moger - * - */ -public class CheckboxOption extends BasePanel { - - private static final long serialVersionUID = 1L; - - public CheckboxOption(String wicketId, String title, String description, IModel model) { - super(wicketId); - add(new Label("name", title)); - add(new Label("description", description).setVisible(!StringUtils.isEmpty(description))); - add(new CheckBox("checkbox", model)); - } - - public CheckboxOption(String wicketId, String title, String description, CheckBox checkbox) { - super(wicketId); - add(new Label("name", title)); - add(new Label("description", description).setVisible(!StringUtils.isEmpty(description))); - add(checkbox.setMarkupId("checkbox")); - } - - public CheckboxOption setIsHtmlDescription(boolean val) { - ((Label) get("description")).setEscapeModelStrings(!val); - return this; - } -} diff --git a/src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.html b/src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.html deleted file mode 100644 index fb360d12..00000000 --- a/src/main/java/com/gitblit/wicket/panels/ConditionalChoiceOption.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - -
-
- -
-
-- cgit v1.2.3 From c9921bd3b0b7bf90b6e5e2a52141c3fdf0f31f89 Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 4 Jun 2014 17:04:17 -0400 Subject: Revise the user profile page and add a preferences form --- .../com/gitblit/wicket/GitBlitWebApp.properties | 9 +- .../java/com/gitblit/wicket/pages/UserPage.html | 51 ++++--- .../java/com/gitblit/wicket/pages/UserPage.java | 153 +++++++++++++++++++-- .../gitblit/wicket/panels/AccessPolicyPanel.html | 2 +- .../gitblit/wicket/panels/BooleanChoiceOption.html | 2 +- .../com/gitblit/wicket/panels/BooleanOption.html | 2 +- .../com/gitblit/wicket/panels/ChoiceOption.html | 2 +- .../java/com/gitblit/wicket/panels/TextOption.html | 2 +- 8 files changed, 185 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index d6fd57e9..81171799 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -722,4 +722,11 @@ gb.originDescription = The url from which this repository was cloned. gb.gc = GC gb.garbageCollection = Garbage Collection gb.garbageCollectionDescription = The garbage collector will pack loose objects pushed from clients and will remove unreferenced objects from the repository. -gb.commitMessageRendererDescription = Commit messages can be displayed as plaintext or as rendered markup. \ No newline at end of file +gb.commitMessageRendererDescription = Commit messages can be displayed as plaintext or as rendered markup. +gb.preferences = preferences +gb.accountPreferences = Account Preferences +gb.accountPreferencesDescription = Specify your account preferences +gb.languagePreference = Language Preference +gb.languagePreferenceDescription = Select your preferred translation for the Gitblit UI +gb.displayNameDescription = The preferred name for display +gb.emailAddressDescription = The primary email address for receiving notifications \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.html b/src/main/java/com/gitblit/wicket/pages/UserPage.html index 7aaded7a..09267873 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.html +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.html @@ -7,27 +7,19 @@
-
-
-
-
-

-
-
-
+
+
+
- -
- -
+
+ +
+
+
@@ -41,11 +33,36 @@
+ + +
+
+ + +
  • +
    + + +
    +

    +

    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java index 29b49b33..baad4a06 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.java +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java @@ -15,19 +15,27 @@ */ package com.gitblit.wicket.pages; +import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Locale; import org.apache.wicket.PageParameters; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.markup.html.basic.Label; -import org.apache.wicket.markup.html.link.BookmarkablePageLink; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.panel.Fragment; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.data.DataView; import org.apache.wicket.markup.repeater.data.ListDataProvider; -import org.eclipse.jgit.lib.PersonIdent; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import com.gitblit.GitBlitException; import com.gitblit.Keys; import com.gitblit.models.Menu.ParameterMenuItem; import com.gitblit.models.NavLink; @@ -40,9 +48,10 @@ import com.gitblit.wicket.GitBlitWebApp; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.GitblitRedirectException; import com.gitblit.wicket.WicketUtils; -import com.gitblit.wicket.panels.GravatarImage; -import com.gitblit.wicket.panels.LinkPanel; +import com.gitblit.wicket.panels.ChoiceOption; import com.gitblit.wicket.panels.ProjectRepositoryPanel; +import com.gitblit.wicket.panels.TextOption; +import com.gitblit.wicket.panels.UserTitlePanel; public class UserPage extends RootPage { @@ -83,21 +92,18 @@ public class UserPage extends RootPage { user = new UserModel(userName); } - add(new Label("userDisplayName", user.getDisplayName())); - add(new Label("userUsername", user.username)); - LinkPanel email = new LinkPanel("userEmail", null, user.emailAddress, "mailto:#"); - email.setRenderBodyOnly(true); - add(email.setVisible(app().settings().getBoolean(Keys.web.showEmailAddresses, true) && !StringUtils.isEmpty(user.emailAddress))); - PersonIdent person = new PersonIdent(user.getDisplayName(), user.emailAddress == null ? user.getDisplayName() : user.emailAddress); - add(new GravatarImage("gravatar", person, 210)); + add(new UserTitlePanel("userTitlePanel", user, user.username)); UserModel sessionUser = GitBlitWebSession.get().getUser(); - if (sessionUser != null && user.canCreate() && sessionUser.equals(user)) { - // user can create personal repositories - add(new BookmarkablePageLink("newRepository", app().getNewRepositoryPage())); + boolean isMyProfile = sessionUser != null && sessionUser.equals(user); + + if (isMyProfile) { + addPreferences(user); } else { - add(new Label("newRepository").setVisible(false)); + // visiting user + add(new Label("preferencesLink").setVisible(false)); + add(new Label("preferencesTab").setVisible(false)); } List repositories = getRepositories(params); @@ -145,4 +151,121 @@ public class UserPage extends RootPage { navLinks.add(menu); } + + private void addPreferences(UserModel user) { + // add preferences + Form prefs = new Form("prefsForm"); + + List languages = Arrays.asList( + new Language("English","en"), + new Language("Español", "es"), + new Language("Français", "fr"), + new Language("日本語", "ja"), + new Language("한국ë§", "ko"), + new Language("Nederlands", "nl"), + new Language("Norsk", "no"), + new Language("JÄ™zyk Polski", "pl"), + new Language("Português", "pt_BR"), + new Language("中文", "zh_CN")); + + String lc = user.getPreferences().locale; + if (StringUtils.isEmpty(lc)) { + // user has not specified language preference + // try server default preference + lc = app().settings().getString(Keys.web.forceDefaultLocale, null); + if (StringUtils.isEmpty(lc)) { + // server default language is not configured + // try browser preference + Locale sessionLocale = GitBlitWebSession.get().getLocale(); + if (sessionLocale != null) { + lc = sessionLocale.getLanguage() + "_" + sessionLocale.getCountry(); + } + } + } + Language preferredLanguage = null; + if (!StringUtils.isEmpty(lc)) { + for (Language language : languages) { + if (language.code.equals(lc)) { + // language_COUNTRY match + preferredLanguage = language; + } else if (preferredLanguage != null && lc.startsWith(language.code)) { + // language match, but not COUNTRY match + preferredLanguage = language; + } + } + } + + final IModel displayName = Model.of(user.getDisplayName()); + final IModel emailAddress = Model.of(user.emailAddress == null ? "" : user.emailAddress); + final IModel language = Model.of(preferredLanguage); + + prefs.add(new TextOption("displayName", + getString("gb.displayName"), + getString("gb.displayNameDescription"), + displayName).setVisible(app().authentication().supportsDisplayNameChanges(user))); + + prefs.add(new TextOption("emailAddress", + getString("gb.emailAddress"), + getString("gb.emailAddressDescription"), + emailAddress).setVisible(app().authentication().supportsEmailAddressChanges(user))); + + prefs.add(new ChoiceOption("language", + getString("gb.languagePreference"), + getString("gb.languagePreferenceDescription"), + language, + languages)); + + prefs.add(new AjaxButton("save") { + + private static final long serialVersionUID = 1L; + + @Override + protected void onSubmit(AjaxRequestTarget target, Form form) { + + UserModel user = GitBlitWebSession.get().getUser(); + + user.displayName = displayName.getObject(); + user.emailAddress = emailAddress.getObject(); + + Language lang = language.getObject(); + if (lang != null) { + user.getPreferences().locale = lang.code; + } + + try { + app().gitblit().reviseUser(user.username, user); + + setRedirect(true); + setResponsePage(UserPage.class, WicketUtils.newUsernameParameter(user.username)); + } catch (GitBlitException e) { + // logger.error("Failed to update user " + user.username, e); + // error(getString("gb.failedToUpdateUser"), false); + } + } + }); + + // add the preferences tab + add(new Fragment("preferencesLink", "preferencesLinkFragment", this).setRenderBodyOnly(true)); + Fragment fragment = new Fragment("preferencesTab", "preferencesTabFragment", this); + fragment.add(prefs); + add(fragment.setRenderBodyOnly(true)); + } + + private class Language implements Serializable { + + private static final long serialVersionUID = 1L; + + final String name; + final String code; + + public Language(String name, String code) { + this.name = name; + this.code = code; + } + + @Override + public String toString() { + return name + " (" + code +")"; + } + } } diff --git a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html index 87a02068..07050192 100644 --- a/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html +++ b/src/main/java/com/gitblit/wicket/panels/AccessPolicyPanel.html @@ -13,7 +13,7 @@
    - +
    diff --git a/src/main/java/com/gitblit/wicket/panels/BooleanChoiceOption.html b/src/main/java/com/gitblit/wicket/panels/BooleanChoiceOption.html index fb360d12..b1ced8da 100644 --- a/src/main/java/com/gitblit/wicket/panels/BooleanChoiceOption.html +++ b/src/main/java/com/gitblit/wicket/panels/BooleanChoiceOption.html @@ -8,7 +8,7 @@
    - +
    diff --git a/src/main/java/com/gitblit/wicket/panels/ChoiceOption.html b/src/main/java/com/gitblit/wicket/panels/ChoiceOption.html index 8c34c819..e9e48874 100644 --- a/src/main/java/com/gitblit/wicket/panels/ChoiceOption.html +++ b/src/main/java/com/gitblit/wicket/panels/ChoiceOption.html @@ -7,7 +7,7 @@
    -
    +
    @@ -47,6 +51,10 @@
  • + +
  • +
    +

    @@ -63,6 +71,12 @@
    + +
    +
    +
    +
    + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java index baad4a06..4a955c7c 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.java +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java @@ -50,6 +50,7 @@ import com.gitblit.wicket.GitblitRedirectException; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.ChoiceOption; import com.gitblit.wicket.panels.ProjectRepositoryPanel; +import com.gitblit.wicket.panels.SshKeysPanel; import com.gitblit.wicket.panels.TextOption; import com.gitblit.wicket.panels.UserTitlePanel; @@ -100,10 +101,22 @@ public class UserPage extends RootPage { if (isMyProfile) { addPreferences(user); + + if (app().gitblit().isServingSSH()) { + // show the SSH key management tab + addSshKeys(user); + } else { + // SSH daemon is disabled, hide keys tab + add(new Label("sshKeysLink").setVisible(false)); + add(new Label("sshKeysTab").setVisible(false)); + } } else { // visiting user add(new Label("preferencesLink").setVisible(false)); add(new Label("preferencesTab").setVisible(false)); + + add(new Label("sshKeysLink").setVisible(false)); + add(new Label("sshKeysTab").setVisible(false)); } List repositories = getRepositories(params); @@ -251,6 +264,15 @@ public class UserPage extends RootPage { add(fragment.setRenderBodyOnly(true)); } + private void addSshKeys(final UserModel user) { + Fragment keysTab = new Fragment("sshKeysTab", "sshKeysTabFragment", this); + keysTab.add(new SshKeysPanel("sshKeysPanel", user, getClass(), getPageParameters())); + + // add the SSH keys tab + add(new Fragment("sshKeysLink", "sshKeysLinkFragment", this).setRenderBodyOnly(true)); + add(keysTab.setRenderBodyOnly(true)); + } + private class Language implements Serializable { private static final long serialVersionUID = 1L; diff --git a/src/main/java/com/gitblit/wicket/panels/SshKeysPanel.html b/src/main/java/com/gitblit/wicket/panels/SshKeysPanel.html new file mode 100644 index 00000000..d67b704a --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/SshKeysPanel.html @@ -0,0 +1,46 @@ + + + + + +

    +

    +
    + +
    +
    + +
    +
    +
    +
    
    +		
    + +
    +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +

    +
    +
    +
    + +
    +
    +
    +
    + + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/SshKeysPanel.java b/src/main/java/com/gitblit/wicket/panels/SshKeysPanel.java new file mode 100644 index 00000000..03cb93ca --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/SshKeysPanel.java @@ -0,0 +1,161 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.panels; + +import java.util.Arrays; +import java.util.List; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.form.AjaxButton; +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.link.Link; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.data.DataView; +import org.apache.wicket.markup.repeater.data.ListDataProvider; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; + +import com.gitblit.Constants.AccessPermission; +import com.gitblit.models.UserModel; +import com.gitblit.transport.ssh.SshKey; +import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.GitBlitWebSession; + + +/** + * A panel that enumerates and manages SSH public keys. + * + * @author James Moger + * + */ +public class SshKeysPanel extends BasePanel { + + private static final long serialVersionUID = 1L; + + private final UserModel user; + + private final Class pageClass; + + private final PageParameters params; + + public SshKeysPanel(String wicketId, UserModel user, Class pageClass, PageParameters params) { + super(wicketId); + + this.user = user; + this.pageClass = pageClass; + this.params = params; + } + + @Override + protected void onInitialize() { + super.onInitialize(); + List keys = app().keys().getKeys(user.username); + + final ListDataProvider dp = new ListDataProvider(keys); + DataView keysView = new DataView("keys", dp) { + private static final long serialVersionUID = 1L; + + @Override + public void populateItem(final Item item) { + final SshKey key = item.getModelObject(); + item.add(new Label("comment", key.getComment())); + item.add(new Label("fingerprint", key.getFingerprint())); + item.add(new Label("permission", key.getPermission().toString())); + item.add(new Label("algorithm", key.getAlgorithm())); + + Link delete = new Link("delete") { + + private static final long serialVersionUID = 1L; + + @Override + public void onClick() { + if (app().keys().removeKey(user.username, key)) { + setRedirect(true); + setResponsePage(pageClass, params); + } + } + }; + item.add(delete); + } + }; + add(keysView); + + Form addKeyForm = new Form("addKeyForm"); + + final IModel keyData = Model.of(""); + addKeyForm.add(new TextAreaOption("addKeyData", + getString("gb.key"), + null, + "span5", + keyData)); + + final IModel keyPermission = Model.of(AccessPermission.PUSH); + addKeyForm.add(new ChoiceOption("addKeyPermission", + getString("gb.permission"), + getString("gb.sshKeyPermissionDescription"), + keyPermission, + Arrays.asList(AccessPermission.SSHPERMISSIONS))); + + final IModel keyComment = Model.of(""); + addKeyForm.add(new TextOption("addKeyComment", + getString("gb.comment"), + getString("gb.sshKeyCommentDescription"), + "span5", + keyComment)); + + addKeyForm.add(new AjaxButton("addKeyButton") { + + private static final long serialVersionUID = 1L; + + @Override + protected void onSubmit(AjaxRequestTarget target, Form form) { + + UserModel user = GitBlitWebSession.get().getUser(); + String data = keyData.getObject(); + if (StringUtils.isEmpty(data)) { + // do not submit empty key + return; + } + + SshKey key = new SshKey(data); + try { + key.getPublicKey(); + } catch (Exception e) { + // failed to parse the key + return; + } + + AccessPermission permission = keyPermission.getObject(); + key.setPermission(permission); + + String comment = keyComment.getObject(); + if (!StringUtils.isEmpty(comment)) { + key.setComment(comment); + } + + if (app().keys().addKey(user.username, key)) { + setRedirect(true); + setResponsePage(pageClass, params); + } + } + }); + + add(addKeyForm); + } +} diff --git a/src/main/java/com/gitblit/wicket/panels/TextAreaOption.html b/src/main/java/com/gitblit/wicket/panels/TextAreaOption.html new file mode 100644 index 00000000..bb7dc7c6 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/TextAreaOption.html @@ -0,0 +1,20 @@ + + + + + +
    +
    + +
    + + +
    +
    + + \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/panels/TextAreaOption.java b/src/main/java/com/gitblit/wicket/panels/TextAreaOption.java new file mode 100644 index 00000000..d2c74a06 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/panels/TextAreaOption.java @@ -0,0 +1,54 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.wicket.panels; + +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.TextArea; +import org.apache.wicket.model.IModel; + +import com.gitblit.utils.StringUtils; +import com.gitblit.wicket.WicketUtils; + +/** + * A re-usable textarea option panel. + * + * title + * description + * [text + * area] + * + * @author James Moger + * + */ +public class TextAreaOption extends BasePanel { + + private static final long serialVersionUID = 1L; + + public TextAreaOption(String wicketId, String title, String description, IModel model) { + this(wicketId, title, description, null, model); + } + + public TextAreaOption(String wicketId, String title, String description, String css, IModel model) { + super(wicketId); + add(new Label("name", title)); + add(new Label("description", description).setVisible(!StringUtils.isEmpty(description))); + TextArea tf = new TextArea("text", model); + if (!StringUtils.isEmpty(css)) { + WicketUtils.setCssClass(tf, css); + } + add(tf); + } +} diff --git a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java index 6e56a873..54be539f 100644 --- a/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java +++ b/src/test/java/com/gitblit/tests/mock/MockRuntimeManager.java @@ -81,6 +81,21 @@ public class MockRuntimeManager implements IRuntimeManager { return true; } + @Override + public boolean isServingHTTP() { + return true; + } + + @Override + public boolean isServingGIT() { + return true; + } + + @Override + public boolean isServingSSH() { + return true; + } + @Override public boolean isDebugMode() { return true; -- cgit v1.2.3 From 6537deb8b76b7a4725c40a174a7c440385f88e51 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 5 Jun 2014 10:20:59 -0400 Subject: Revise language/locale preference handling --- src/main/java/com/gitblit/ConfigUserService.java | 9 +++++--- .../java/com/gitblit/models/UserPreferences.java | 6 ++++- .../com/gitblit/wicket/GitBlitWebApp.properties | 2 +- .../java/com/gitblit/wicket/pages/UserPage.java | 26 ++++++++++++++-------- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/gitblit/ConfigUserService.java b/src/main/java/com/gitblit/ConfigUserService.java index 9b4dd7f1..b5dfde3b 100644 --- a/src/main/java/com/gitblit/ConfigUserService.java +++ b/src/main/java/com/gitblit/ConfigUserService.java @@ -707,8 +707,9 @@ public class ConfigUserService implements IUserService { config.setBoolean(USER, model.username, DISABLED, true); } if (model.getPreferences() != null) { - if (!StringUtils.isEmpty(model.getPreferences().locale)) { - config.setString(USER, model.username, LOCALE, model.getPreferences().locale); + if (model.getPreferences().getLocale() != null) { + String val = model.getPreferences().getLocale().getLanguage() + "_" + model.getPreferences().getLocale().getCountry(); + config.setString(USER, model.username, LOCALE, val); } } @@ -880,11 +881,13 @@ public class ConfigUserService implements IUserService { user.stateProvince = config.getString(USER, username, STATEPROVINCE); user.countryCode = config.getString(USER, username, COUNTRYCODE); user.cookie = config.getString(USER, username, COOKIE); - user.getPreferences().locale = config.getString(USER, username, LOCALE); if (StringUtils.isEmpty(user.cookie) && !StringUtils.isEmpty(user.password)) { user.cookie = StringUtils.getSHA1(user.username + user.password); } + // preferences + user.getPreferences().setLocale(config.getString(USER, username, LOCALE)); + // user roles Set roles = new HashSet(Arrays.asList(config.getStringList( USER, username, ROLE))); diff --git a/src/main/java/com/gitblit/models/UserPreferences.java b/src/main/java/com/gitblit/models/UserPreferences.java index 44e44933..61db353c 100644 --- a/src/main/java/com/gitblit/models/UserPreferences.java +++ b/src/main/java/com/gitblit/models/UserPreferences.java @@ -37,7 +37,7 @@ public class UserPreferences implements Serializable { public final String username; - public String locale; + private String locale; private final Map repositoryPreferences = new TreeMap(); @@ -58,6 +58,10 @@ public class UserPreferences implements Serializable { return new Locale(locale); } + public void setLocale(String locale) { + this.locale = locale; + } + public UserRepositoryPreferences getRepositoryPreferences(String repositoryName) { String key = repositoryName.toLowerCase(); if (!repositoryPreferences.containsKey(key)) { diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 7dc0f9b6..90d30f29 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -727,7 +727,7 @@ gb.preferences = preferences gb.accountPreferences = Account Preferences gb.accountPreferencesDescription = Specify your account preferences gb.languagePreference = Language Preference -gb.languagePreferenceDescription = Select your preferred translation for the Gitblit UI +gb.languagePreferenceDescription = Select your preferred translation for Gitblit gb.displayNameDescription = The preferred name for display gb.emailAddressDescription = The primary email address for receiving notifications gb.sshKeys = SSH Keys diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java index 4a955c7c..94048963 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.java +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java @@ -181,28 +181,36 @@ public class UserPage extends RootPage { new Language("Português", "pt_BR"), new Language("中文", "zh_CN")); - String lc = user.getPreferences().locale; - if (StringUtils.isEmpty(lc)) { + Locale locale = user.getPreferences().getLocale(); + if (locale == null) { // user has not specified language preference // try server default preference - lc = app().settings().getString(Keys.web.forceDefaultLocale, null); + String lc = app().settings().getString(Keys.web.forceDefaultLocale, null); if (StringUtils.isEmpty(lc)) { // server default language is not configured // try browser preference Locale sessionLocale = GitBlitWebSession.get().getLocale(); if (sessionLocale != null) { - lc = sessionLocale.getLanguage() + "_" + sessionLocale.getCountry(); + locale = sessionLocale; } + } else { + } } + Language preferredLanguage = null; - if (!StringUtils.isEmpty(lc)) { + if (locale != null) { + String localeCode = locale.getLanguage(); + if (!StringUtils.isEmpty(locale.getCountry())) { + localeCode += "_" + locale.getCountry(); + } + for (Language language : languages) { - if (language.code.equals(lc)) { + if (language.code.equals(localeCode)) { // language_COUNTRY match preferredLanguage = language; - } else if (preferredLanguage != null && lc.startsWith(language.code)) { - // language match, but not COUNTRY match + } else if (preferredLanguage != null && language.code.startsWith(locale.getLanguage())) { + // language match preferredLanguage = language; } } @@ -242,7 +250,7 @@ public class UserPage extends RootPage { Language lang = language.getObject(); if (lang != null) { - user.getPreferences().locale = lang.code; + user.getPreferences().setLocale(lang.code); } try { -- cgit v1.2.3 From 74221eb302e782ef23777d5c3f0a649ceb321c1e Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 5 Jun 2014 10:23:58 -0400 Subject: Add method to INotificationManager to return email service status --- src/main/java/com/gitblit/FederationClient.java | 5 +++++ src/main/java/com/gitblit/manager/GitblitManager.java | 5 +++++ src/main/java/com/gitblit/manager/INotificationManager.java | 8 ++++++++ src/main/java/com/gitblit/manager/NotificationManager.java | 5 +++++ 4 files changed, 23 insertions(+) diff --git a/src/main/java/com/gitblit/FederationClient.java b/src/main/java/com/gitblit/FederationClient.java index c3dcd9da..cd06c3cb 100644 --- a/src/main/java/com/gitblit/FederationClient.java +++ b/src/main/java/com/gitblit/FederationClient.java @@ -165,6 +165,11 @@ public class FederationClient { return this; } + @Override + public boolean isSendingMail() { + return false; + } + @Override public void sendMailToAdministrators(String subject, String message) { } diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java index ef2433dd..98ad33e7 100644 --- a/src/main/java/com/gitblit/manager/GitblitManager.java +++ b/src/main/java/com/gitblit/manager/GitblitManager.java @@ -660,6 +660,11 @@ public class GitblitManager implements IGitblit { * NOTIFICATION MANAGER */ + @Override + public boolean isSendingMail() { + return notificationManager.isSendingMail(); + } + @Override public void sendMailToAdministrators(String subject, String message) { notificationManager.sendMailToAdministrators(subject, message); diff --git a/src/main/java/com/gitblit/manager/INotificationManager.java b/src/main/java/com/gitblit/manager/INotificationManager.java index 231cf43a..64fc01e8 100644 --- a/src/main/java/com/gitblit/manager/INotificationManager.java +++ b/src/main/java/com/gitblit/manager/INotificationManager.java @@ -21,6 +21,14 @@ import com.gitblit.models.Mailing; public interface INotificationManager extends IManager { + /** + * Returns true if the email service is configured and ready to send notifications. + * + * @return true if the email service is operational + * @since 1.6.0 + */ + boolean isSendingMail(); + /** * Notify the administrators by email. * diff --git a/src/main/java/com/gitblit/manager/NotificationManager.java b/src/main/java/com/gitblit/manager/NotificationManager.java index ba63cfc1..69a611bb 100644 --- a/src/main/java/com/gitblit/manager/NotificationManager.java +++ b/src/main/java/com/gitblit/manager/NotificationManager.java @@ -71,6 +71,11 @@ public class NotificationManager implements INotificationManager { return this; } + @Override + public boolean isSendingMail() { + return mailService.isReady(); + } + /** * Notify the administrators by email. * -- cgit v1.2.3 From afbaebde11093fae8b420aaaf71dcd56d8c0f9fd Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 5 Jun 2014 10:24:39 -0400 Subject: Add "email me on my ticket changes" preference --- src/main/java/com/gitblit/ConfigUserService.java | 4 ++++ src/main/java/com/gitblit/models/UserPreferences.java | 13 +++++++++++++ src/main/java/com/gitblit/tickets/TicketNotifier.java | 11 +++++++++-- src/main/java/com/gitblit/wicket/GitBlitWebApp.properties | 2 ++ src/main/java/com/gitblit/wicket/pages/UserPage.html | 3 ++- src/main/java/com/gitblit/wicket/pages/UserPage.java | 9 +++++++++ 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gitblit/ConfigUserService.java b/src/main/java/com/gitblit/ConfigUserService.java index b5dfde3b..9759eff7 100644 --- a/src/main/java/com/gitblit/ConfigUserService.java +++ b/src/main/java/com/gitblit/ConfigUserService.java @@ -96,6 +96,8 @@ public class ConfigUserService implements IUserService { private static final String LOCALE = "locale"; + private static final String EMAILONMYTICKETCHANGES = "emailMeOnMyTicketChanges"; + private static final String ACCOUNTTYPE = "accountType"; private static final String DISABLED = "disabled"; @@ -711,6 +713,7 @@ public class ConfigUserService implements IUserService { String val = model.getPreferences().getLocale().getLanguage() + "_" + model.getPreferences().getLocale().getCountry(); config.setString(USER, model.username, LOCALE, val); } + config.setBoolean(USER, model.username, EMAILONMYTICKETCHANGES, model.getPreferences().isEmailMeOnMyTicketChanges()); } // user roles @@ -887,6 +890,7 @@ public class ConfigUserService implements IUserService { // preferences user.getPreferences().setLocale(config.getString(USER, username, LOCALE)); + user.getPreferences().setEmailMeOnMyTicketChanges(config.getBoolean(USER, username, EMAILONMYTICKETCHANGES, true)); // user roles Set roles = new HashSet(Arrays.asList(config.getStringList( diff --git a/src/main/java/com/gitblit/models/UserPreferences.java b/src/main/java/com/gitblit/models/UserPreferences.java index 61db353c..c95b0da5 100644 --- a/src/main/java/com/gitblit/models/UserPreferences.java +++ b/src/main/java/com/gitblit/models/UserPreferences.java @@ -39,6 +39,8 @@ public class UserPreferences implements Serializable { private String locale; + private Boolean emailMeOnMyTicketChanges; + private final Map repositoryPreferences = new TreeMap(); public UserPreferences(String username) { @@ -100,4 +102,15 @@ public class UserPreferences implements Serializable { Collections.sort(list); return list; } + + public boolean isEmailMeOnMyTicketChanges() { + if (emailMeOnMyTicketChanges == null) { + return true; + } + return emailMeOnMyTicketChanges; + } + + public void setEmailMeOnMyTicketChanges(boolean value) { + this.emailMeOnMyTicketChanges = value; + } } diff --git a/src/main/java/com/gitblit/tickets/TicketNotifier.java b/src/main/java/com/gitblit/tickets/TicketNotifier.java index 9a5e4e1d..07371b1b 100644 --- a/src/main/java/com/gitblit/tickets/TicketNotifier.java +++ b/src/main/java/com/gitblit/tickets/TicketNotifier.java @@ -545,7 +545,6 @@ public class TicketNotifier { } } } - mailing.setRecipients(toAddresses); // // CC recipients @@ -554,7 +553,7 @@ public class TicketNotifier { // repository owners if (!ArrayUtils.isEmpty(repository.owners)) { - tos.addAll(repository.owners); + ccs.addAll(repository.owners); } // cc users mentioned in last comment @@ -595,6 +594,14 @@ public class TicketNotifier { } ccAddresses.addAll(settings.getStrings(Keys.mail.mailingLists)); + // respect the author's email preference + UserModel lastAuthor = userManager.getUserModel(lastChange.author); + if (!lastAuthor.getPreferences().isEmailMeOnMyTicketChanges()) { + toAddresses.remove(lastAuthor.emailAddress); + ccAddresses.remove(lastAuthor.emailAddress); + } + + mailing.setRecipients(toAddresses); mailing.setCCs(ccAddresses); } diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index 90d30f29..c80d45ce 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -728,6 +728,8 @@ gb.accountPreferences = Account Preferences gb.accountPreferencesDescription = Specify your account preferences gb.languagePreference = Language Preference gb.languagePreferenceDescription = Select your preferred translation for Gitblit +gb.emailMeOnMyTicketChanges = Email me on my ticket changes +gb.emailMeOnMyTicketChangesDescription = Send me an email notification for changes that I make to a ticket gb.displayNameDescription = The preferred name for display gb.emailAddressDescription = The primary email address for receiving notifications gb.sshKeys = SSH Keys diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.html b/src/main/java/com/gitblit/wicket/pages/UserPage.html index d71cb2b5..017fcb1f 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.html +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.html @@ -64,7 +64,8 @@
    -
    +
    +
    diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java index 94048963..505f55d9 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.java +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java @@ -48,6 +48,7 @@ import com.gitblit.wicket.GitBlitWebApp; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.GitblitRedirectException; import com.gitblit.wicket.WicketUtils; +import com.gitblit.wicket.panels.BooleanOption; import com.gitblit.wicket.panels.ChoiceOption; import com.gitblit.wicket.panels.ProjectRepositoryPanel; import com.gitblit.wicket.panels.SshKeysPanel; @@ -219,6 +220,7 @@ public class UserPage extends RootPage { final IModel displayName = Model.of(user.getDisplayName()); final IModel emailAddress = Model.of(user.emailAddress == null ? "" : user.emailAddress); final IModel language = Model.of(preferredLanguage); + final IModel emailMeOnMyTicketChanges = Model.of(user.getPreferences().isEmailMeOnMyTicketChanges()); prefs.add(new TextOption("displayName", getString("gb.displayName"), @@ -236,6 +238,11 @@ public class UserPage extends RootPage { language, languages)); + prefs.add(new BooleanOption("emailMeOnMyTicketChanges", + getString("gb.emailMeOnMyTicketChanges"), + getString("gb.emailMeOnMyTicketChangesDescription"), + emailMeOnMyTicketChanges).setVisible(app().notifier().isSendingMail())); + prefs.add(new AjaxButton("save") { private static final long serialVersionUID = 1L; @@ -253,6 +260,8 @@ public class UserPage extends RootPage { user.getPreferences().setLocale(lang.code); } + user.getPreferences().setEmailMeOnMyTicketChanges(emailMeOnMyTicketChanges.getObject()); + try { app().gitblit().reviseUser(user.username, user); -- cgit v1.2.3 From b0658eedf4bc1590cd5003d17d9c71dd47b3c70c Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 5 Jun 2014 11:22:44 -0400 Subject: Use AJAX to manage the SSH keys panel --- .../java/com/gitblit/wicket/pages/UserPage.java | 2 +- .../com/gitblit/wicket/panels/SshKeysPanel.java | 46 +++++++++++++--------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java index 505f55d9..00a36272 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.java +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java @@ -283,7 +283,7 @@ public class UserPage extends RootPage { private void addSshKeys(final UserModel user) { Fragment keysTab = new Fragment("sshKeysTab", "sshKeysTabFragment", this); - keysTab.add(new SshKeysPanel("sshKeysPanel", user, getClass(), getPageParameters())); + keysTab.add(new SshKeysPanel("sshKeysPanel", user)); // add the SSH keys tab add(new Fragment("sshKeysLink", "sshKeysLinkFragment", this).setRenderBodyOnly(true)); diff --git a/src/main/java/com/gitblit/wicket/panels/SshKeysPanel.java b/src/main/java/com/gitblit/wicket/panels/SshKeysPanel.java index 03cb93ca..15ebd67b 100644 --- a/src/main/java/com/gitblit/wicket/panels/SshKeysPanel.java +++ b/src/main/java/com/gitblit/wicket/panels/SshKeysPanel.java @@ -15,16 +15,15 @@ */ package com.gitblit.wicket.panels; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import org.apache.wicket.PageParameters; import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.ajax.markup.html.form.AjaxButton; -import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Form; -import org.apache.wicket.markup.html.link.Link; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.data.DataView; import org.apache.wicket.markup.repeater.data.ListDataProvider; @@ -39,7 +38,7 @@ import com.gitblit.wicket.GitBlitWebSession; /** - * A panel that enumerates and manages SSH public keys. + * A panel that enumerates and manages SSH public keys using AJAX. * * @author James Moger * @@ -50,25 +49,21 @@ public class SshKeysPanel extends BasePanel { private final UserModel user; - private final Class pageClass; - - private final PageParameters params; - - public SshKeysPanel(String wicketId, UserModel user, Class pageClass, PageParameters params) { + public SshKeysPanel(String wicketId, UserModel user) { super(wicketId); this.user = user; - this.pageClass = pageClass; - this.params = params; } @Override protected void onInitialize() { super.onInitialize(); - List keys = app().keys().getKeys(user.username); + setOutputMarkupId(true); + + final List keys = new ArrayList(app().keys().getKeys(user.username)); final ListDataProvider dp = new ListDataProvider(keys); - DataView keysView = new DataView("keys", dp) { + final DataView keysView = new DataView("keys", dp) { private static final long serialVersionUID = 1L; @Override @@ -79,15 +74,19 @@ public class SshKeysPanel extends BasePanel { item.add(new Label("permission", key.getPermission().toString())); item.add(new Label("algorithm", key.getAlgorithm())); - Link delete = new Link("delete") { + AjaxLink delete = new AjaxLink("delete") { private static final long serialVersionUID = 1L; @Override - public void onClick() { + public void onClick(AjaxRequestTarget target) { if (app().keys().removeKey(user.username, key)) { - setRedirect(true); - setResponsePage(pageClass, params); + // reset the keys list + keys.clear(); + keys.addAll(app().keys().getKeys(user.username)); + + // update the panel + target.addComponent(SshKeysPanel.this); } } }; @@ -150,8 +149,17 @@ public class SshKeysPanel extends BasePanel { } if (app().keys().addKey(user.username, key)) { - setRedirect(true); - setResponsePage(pageClass, params); + // reset add key fields + keyData.setObject(""); + keyPermission.setObject(AccessPermission.PUSH); + keyComment.setObject(""); + + // reset the keys list + keys.clear(); + keys.addAll(app().keys().getKeys(user.username)); + + // update the panel + target.addComponent(SshKeysPanel.this); } } }); -- cgit v1.2.3 From c7796ebac77a30c91e61ca474f63e8f181f6e1be Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 5 Jun 2014 11:27:13 -0400 Subject: Documentation --- releases.moxie | 2 ++ 1 file changed, 2 insertions(+) diff --git a/releases.moxie b/releases.moxie index 7635e064..c7299a7e 100644 --- a/releases.moxie +++ b/releases.moxie @@ -34,6 +34,8 @@ r24: { - Added CRUD functionality for Ticket Milestones (ticket-17) - Implemented Ticket migration tool to move between backends (ticket-19) - Added extension points for top nav links, root-level pages, repository nav links, user menu links, and http request filters (ticket-23) + - Added an editor panel in the user profile page to manipulate preferences (issue-108, issue-424, ticket-64) + - Added an editor panel in the user profile page to manipulate public SSH keys (ticket-64) - Add FORK_REPOSITORY RPC request type (issue-371, pr-161, ticket-65) - Add object type (ot) parameter for RSS queries to retrieve tag details (pr-165, ticket-66) - Add setting to allow STARTTLS without requiring SMTPS (pr-183) -- cgit v1.2.3 From bfce9f59fca542d7b96b88d67494336b0c50b045 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 5 Jun 2014 12:19:07 -0400 Subject: Add setting to control inclusion of personal repositories in the main list --- releases.moxie | 3 +++ src/main/distrib/data/gitblit.properties | 5 +++++ .../java/com/gitblit/wicket/pages/RepositoriesPage.java | 13 ++++++++++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/releases.moxie b/releases.moxie index c7299a7e..fc139b77 100644 --- a/releases.moxie +++ b/releases.moxie @@ -29,6 +29,7 @@ r24: { - Overhaul the EmptyRepositoryPage (ticket-73) - Overhauled the edit repository page (ticket-76) - Process bugtraq links in the ticket description and comments (ticket-78) + - Exclude personal repositories from the repositories list, by default (issue-419, ticket-95) additions: - Add My Tickets page (issue-215, ticket-15) - Added CRUD functionality for Ticket Milestones (ticket-17) @@ -55,8 +56,10 @@ r24: { - Marcus Hunger - Matthias Cullmann - Emmeran Seehuber + - Sascha Vogt settings: - { name: 'web.allowDeletingNonEmptyRepositories', defaultValue: 'true' } + - { name: 'web.includePersonalRepositories', defaultValue: 'false' } - { name: 'mail.starttls', defaultValue: 'false' } - { name: 'execution.defaultThreadPoolSize', defaultValue: '1' } - { name: 'git.gitignoreFolder', defaultValue: '${baseFolder}/gitignore' } diff --git a/src/main/distrib/data/gitblit.properties b/src/main/distrib/data/gitblit.properties index d5623cd5..65fe41e5 100644 --- a/src/main/distrib/data/gitblit.properties +++ b/src/main/distrib/data/gitblit.properties @@ -782,6 +782,11 @@ web.allowCookieAuthentication = true # SINCE 1.6.0 web.allowDeletingNonEmptyRepositories = true +# Setting to include personal repositories in the main repositories list. +# +# SINCE 1.6.0 +web.includePersonalRepositories = false + # Config file for storing project metadata # # SINCE 1.2.0 diff --git a/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.java b/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.java index a0b15a83..660b4ed1 100644 --- a/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.java +++ b/src/main/java/com/gitblit/wicket/pages/RepositoriesPage.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import org.apache.wicket.Component; @@ -30,8 +31,8 @@ import org.eclipse.jgit.lib.Constants; import com.gitblit.Keys; import com.gitblit.models.Menu.ParameterMenuItem; -import com.gitblit.models.NavLink.DropDownPageMenuNavLink; import com.gitblit.models.NavLink; +import com.gitblit.models.NavLink.DropDownPageMenuNavLink; import com.gitblit.models.RepositoryModel; import com.gitblit.utils.MarkdownUtils; import com.gitblit.utils.StringUtils; @@ -79,7 +80,17 @@ public class RepositoriesPage extends RootPage { .setEscapeModelStrings(false).setVisible(message.length() > 0); add(repositoriesMessage); + // conditionally include personal repositories in this page List repositories = getRepositories(params); + if (!app().settings().getBoolean(Keys.web.includePersonalRepositories, true)) { + Iterator itr = repositories.iterator(); + while (itr.hasNext()) { + RepositoryModel rm = itr.next(); + if (rm.isPersonalRepository()) { + itr.remove(); + } + } + } RepositoriesPanel repositoriesPanel = new RepositoriesPanel("repositoriesPanel", showAdmin, true, repositories, true, getAccessRestrictions()); -- cgit v1.2.3 From 1b04d7730f56a08c935974504b2d849d01870c02 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 5 Jun 2014 14:14:54 -0400 Subject: Add clone transport user preference --- releases.moxie | 1 + src/main/java/com/gitblit/ConfigUserService.java | 9 +++++++++ src/main/java/com/gitblit/GitBlit.java | 19 +++++++++++++++++++ .../java/com/gitblit/models/UserPreferences.java | 11 +++++++++++ .../com/gitblit/wicket/GitBlitWebApp.properties | 4 +++- .../java/com/gitblit/wicket/pages/UserPage.html | 1 + .../java/com/gitblit/wicket/pages/UserPage.java | 21 +++++++++++++++++++++ 7 files changed, 65 insertions(+), 1 deletion(-) diff --git a/releases.moxie b/releases.moxie index fc139b77..c1e11d98 100644 --- a/releases.moxie +++ b/releases.moxie @@ -43,6 +43,7 @@ r24: { - Simplified repository creation, offer simple README generation, and insertion of a pre-defined .gitignore file (ticket-76) - Added an extension point for monitoring onStartup and onShutdown (ticket-79) - Tag server-side merges when incremental push tags are enabled (issue-432, ticket-85) + - Add a user preference for the clone transport (ticket-90) - Add setting to control default thread pool size for miscellaneous background tasks (ticket-92) dependencyChanges: - Update to javax.mail 1.5.1 (issue-417, ticket-58) diff --git a/src/main/java/com/gitblit/ConfigUserService.java b/src/main/java/com/gitblit/ConfigUserService.java index 9759eff7..0c5b2a58 100644 --- a/src/main/java/com/gitblit/ConfigUserService.java +++ b/src/main/java/com/gitblit/ConfigUserService.java @@ -36,6 +36,7 @@ import org.slf4j.LoggerFactory; import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccountType; +import com.gitblit.Constants.Transport; import com.gitblit.manager.IRuntimeManager; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; @@ -98,6 +99,8 @@ public class ConfigUserService implements IUserService { private static final String EMAILONMYTICKETCHANGES = "emailMeOnMyTicketChanges"; + private static final String TRANSPORT = "transport"; + private static final String ACCOUNTTYPE = "accountType"; private static final String DISABLED = "disabled"; @@ -713,7 +716,12 @@ public class ConfigUserService implements IUserService { String val = model.getPreferences().getLocale().getLanguage() + "_" + model.getPreferences().getLocale().getCountry(); config.setString(USER, model.username, LOCALE, val); } + config.setBoolean(USER, model.username, EMAILONMYTICKETCHANGES, model.getPreferences().isEmailMeOnMyTicketChanges()); + + if (model.getPreferences().getTransport() != null) { + config.setString(USER, model.username, TRANSPORT, model.getPreferences().getTransport().name()); + } } // user roles @@ -891,6 +899,7 @@ public class ConfigUserService implements IUserService { // preferences user.getPreferences().setLocale(config.getString(USER, username, LOCALE)); user.getPreferences().setEmailMeOnMyTicketChanges(config.getBoolean(USER, username, EMAILONMYTICKETCHANGES, true)); + user.getPreferences().setTransport(Transport.fromString(config.getString(USER, username, TRANSPORT))); // user roles Set roles = new HashSet(Arrays.asList(config.getStringList( diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java index 81793850..f9d9be9f 100644 --- a/src/main/java/com/gitblit/GitBlit.java +++ b/src/main/java/com/gitblit/GitBlit.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Set; @@ -264,6 +265,24 @@ public class GitBlit extends GitblitManager { } }); + // consider the user's transport preference + RepositoryUrl preferredUrl = null; + Transport preferredTransport = user.getPreferences().getTransport(); + if (preferredTransport != null) { + Iterator itr = list.iterator(); + while (itr.hasNext()) { + RepositoryUrl url = itr.next(); + if (url.transport.equals(preferredTransport)) { + itr.remove(); + preferredUrl = url; + break; + } + } + } + if (preferredUrl != null) { + list.add(0, preferredUrl); + } + return list; } diff --git a/src/main/java/com/gitblit/models/UserPreferences.java b/src/main/java/com/gitblit/models/UserPreferences.java index c95b0da5..90c034fc 100644 --- a/src/main/java/com/gitblit/models/UserPreferences.java +++ b/src/main/java/com/gitblit/models/UserPreferences.java @@ -23,6 +23,7 @@ import java.util.Locale; import java.util.Map; import java.util.TreeMap; +import com.gitblit.Constants.Transport; import com.gitblit.utils.StringUtils; /** @@ -41,6 +42,8 @@ public class UserPreferences implements Serializable { private Boolean emailMeOnMyTicketChanges; + private Transport transport; + private final Map repositoryPreferences = new TreeMap(); public UserPreferences(String username) { @@ -113,4 +116,12 @@ public class UserPreferences implements Serializable { public void setEmailMeOnMyTicketChanges(boolean value) { this.emailMeOnMyTicketChanges = value; } + + public Transport getTransport() { + return transport; + } + + public void setTransport(Transport transport) { + this.transport = transport; + } } diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties index c80d45ce..eb92e2d2 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp.properties @@ -739,4 +739,6 @@ gb.key = Key gb.comment = Comment gb.sshKeyCommentDescription = Enter an optional comment. If blank, the comment will be extracted from the key data. gb.permission = Permission -gb.sshKeyPermissionDescription = Specify the access permission for the SSH key \ No newline at end of file +gb.sshKeyPermissionDescription = Specify the access permission for the SSH key +gb.transportPreference = Transport Preference +gb.transportPreferenceDescription = Set the transport that you prefer to use for cloning \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.html b/src/main/java/com/gitblit/wicket/pages/UserPage.html index 017fcb1f..8dccfee7 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.html +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.html @@ -66,6 +66,7 @@
    +
    diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java index 00a36272..306eea65 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.java +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java @@ -35,6 +35,7 @@ import org.apache.wicket.markup.repeater.data.ListDataProvider; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; +import com.gitblit.Constants.Transport; import com.gitblit.GitBlitException; import com.gitblit.Keys; import com.gitblit.models.Menu.ParameterMenuItem; @@ -221,6 +222,7 @@ public class UserPage extends RootPage { final IModel emailAddress = Model.of(user.emailAddress == null ? "" : user.emailAddress); final IModel language = Model.of(preferredLanguage); final IModel emailMeOnMyTicketChanges = Model.of(user.getPreferences().isEmailMeOnMyTicketChanges()); + final IModel transport = Model.of(user.getPreferences().getTransport()); prefs.add(new TextOption("displayName", getString("gb.displayName"), @@ -243,6 +245,24 @@ public class UserPage extends RootPage { getString("gb.emailMeOnMyTicketChangesDescription"), emailMeOnMyTicketChanges).setVisible(app().notifier().isSendingMail())); + List availableTransports = new ArrayList<>(); + if (app().gitblit().isServingSSH()) { + availableTransports.add(Transport.SSH); + } + if (app().gitblit().isServingHTTP()) { + availableTransports.add(Transport.HTTPS); + availableTransports.add(Transport.HTTP); + } + if (app().gitblit().isServingGIT()) { + availableTransports.add(Transport.GIT); + } + + prefs.add(new ChoiceOption("transport", + getString("gb.transportPreference"), + getString("gb.transportPreferenceDescription"), + transport, + availableTransports)); + prefs.add(new AjaxButton("save") { private static final long serialVersionUID = 1L; @@ -261,6 +281,7 @@ public class UserPage extends RootPage { } user.getPreferences().setEmailMeOnMyTicketChanges(emailMeOnMyTicketChanges.getObject()); + user.getPreferences().setTransport(transport.getObject()); try { app().gitblit().reviseUser(user.username, user); -- cgit v1.2.3 From f9e51c9454c89a8587bb122183c7658b94606d42 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 09:10:13 -0400 Subject: Use separate project and name field models in the RepositoryNamePanel --- .../gitblit/wicket/pages/EditRepositoryPage.java | 3 +- .../gitblit/wicket/pages/NewRepositoryPage.java | 3 +- .../gitblit/wicket/panels/RepositoryNamePanel.java | 73 ++++++++++------------ 3 files changed, 36 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java index a0e6e7ba..a1c37385 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -70,8 +70,8 @@ import com.gitblit.wicket.StringChoiceRenderer; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.AccessPolicyPanel; import com.gitblit.wicket.panels.BasePanel.JavascriptEventConfirmation; -import com.gitblit.wicket.panels.BulletListPanel; import com.gitblit.wicket.panels.BooleanOption; +import com.gitblit.wicket.panels.BulletListPanel; import com.gitblit.wicket.panels.ChoiceOption; import com.gitblit.wicket.panels.RegistrantPermissionsPanel; import com.gitblit.wicket.panels.RepositoryNamePanel; @@ -383,7 +383,6 @@ public class EditRepositoryPage extends RootSubPage { } } catch (GitBlitException e) { error(e.getMessage()); - namePanel.resetModel(repositoryModel); return; } setRedirect(false); diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java index b8752e33..46877168 100644 --- a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java +++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java @@ -56,8 +56,8 @@ import com.gitblit.utils.StringUtils; import com.gitblit.wicket.GitBlitWebSession; import com.gitblit.wicket.WicketUtils; import com.gitblit.wicket.panels.AccessPolicyPanel; -import com.gitblit.wicket.panels.BooleanOption; import com.gitblit.wicket.panels.BooleanChoiceOption; +import com.gitblit.wicket.panels.BooleanOption; import com.gitblit.wicket.panels.RepositoryNamePanel; public class NewRepositoryPage extends RootSubPage { @@ -142,7 +142,6 @@ public class NewRepositoryPage extends RootSubPage { } catch (GitBlitException e) { error(e.getMessage()); - namePanel.resetModel(repositoryModel); return; } setRedirect(true); diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java index 358ff59b..d3e493ed 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java @@ -22,6 +22,8 @@ import java.util.TreeSet; import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; import com.gitblit.models.ProjectModel; import com.gitblit.models.RepositoryModel; @@ -41,7 +43,11 @@ public class RepositoryNamePanel extends BasePanel { private String fullName; - private DropDownChoice projectChoice; + private final IModel projectPath; + + private DropDownChoice pathChoice; + + private final IModel repoName; private TextField nameField; @@ -52,84 +58,82 @@ public class RepositoryNamePanel extends BasePanel { UserModel user = session.getUser(); // build project set for repository destination - String defaultProject = null; - Set projectNames = new TreeSet(); + String defaultPath = null; + String defaultName = null; + Set pathNames = new TreeSet(); // add the registered/known projects for (ProjectModel project : app().projects().getProjectModels(user, false)) { // TODO issue-351: user.canAdmin(project) if (user.canAdmin()) { if (project.isRoot) { - projectNames.add("/"); + pathNames.add("/"); } else { - projectNames.add(project.name + "/"); + pathNames.add(project.name + "/"); } } } // add the user's personal project namespace if (user.canAdmin() || user.canCreate()) { - projectNames.add(user.getPersonalPath() + "/"); + pathNames.add(user.getPersonalPath() + "/"); } if (!StringUtils.isEmpty(repository.name)) { // editing a repository name // set the defaultProject to the current repository project - defaultProject = repository.projectPath; - if (StringUtils.isEmpty(defaultProject)) { - defaultProject = "/"; + if (StringUtils.isEmpty(repository.projectPath)) { + defaultPath = "/"; } else { - defaultProject += "/"; + defaultPath = repository.projectPath + "/"; } - - projectNames.add(defaultProject); + defaultName = repository.name.substring(defaultPath.length()); + pathNames.add(defaultPath); } // if default project is not already set, set preference based on the user permissions - if (defaultProject == null) { + if (defaultPath == null) { if (user.canAdmin()) { - defaultProject = "/"; + defaultPath = "/"; } else if (user.canCreate()) { - defaultProject = user.getPersonalPath() + "/"; + defaultPath = user.getPersonalPath() + "/"; } } - // update the model which is reflectively mapped to the Wicket fields by name - repository.projectPath = defaultProject; - if (repository.projectPath.length() > 1 && !StringUtils.isEmpty(repository.name)) { - repository.name = repository.name.substring(repository.projectPath.length()); - } - projectChoice = new DropDownChoice("projectPath", new ArrayList(projectNames)); - nameField = new TextField("name"); + projectPath = Model.of(defaultPath); + pathChoice = new DropDownChoice("projectPath", projectPath, new ArrayList(pathNames)); + repoName = Model.of(defaultName); + nameField = new TextField("name", repoName); // only enable project selection if we actually have multiple choices - add(projectChoice.setEnabled(projectNames.size() > 1)); + add(pathChoice.setEnabled(pathNames.size() > 1)); add(nameField); add(new TextField("description")); } public void setEditable(boolean editable) { // only enable project selection if we actually have multiple choices - projectChoice.setEnabled(projectChoice.getChoices().size() > 1 && editable); + pathChoice.setEnabled(pathChoice.getChoices().size() > 1 && editable); nameField.setEnabled(editable); } public boolean updateModel(RepositoryModel repositoryModel) { - // confirm a project was selected - if (StringUtils.isEmpty(repositoryModel.projectPath)) { + // confirm a project path was selected + if (StringUtils.isEmpty(projectPath.getObject())) { error(getString("gb.pleaseSelectProject")); return false; } // confirm a repository name was entered - if (StringUtils.isEmpty(repositoryModel.name)) { + if (StringUtils.isEmpty(repoName.getObject())) { error(getString("gb.pleaseSetRepositoryName")); return false; } - String project = repositoryModel.projectPath; + String project = projectPath.getObject(); + String name = repoName.getObject(); - fullName = (project + repositoryModel.name).trim(); + fullName = (project + name).trim(); fullName = fullName.replace('\\', '/'); fullName = fullName.replace("//", "/"); if (fullName.charAt(0) == '/') { @@ -156,21 +160,12 @@ public class RepositoryNamePanel extends BasePanel { } repositoryModel.name = fullName; - repositoryModel.projectPath = null; return true; } - public void resetModel(RepositoryModel repositoryModel) { - // restore project and name fields on error condition - repositoryModel.projectPath = StringUtils.getFirstPathElement(fullName) + "/"; - if (repositoryModel.projectPath.length() > 1) { - repositoryModel.name = fullName.substring(repositoryModel.projectPath.length()); - } - } - @Override protected boolean getStatelessHint() { return false; } -} +} \ No newline at end of file -- cgit v1.2.3 From 7e6932b27785d8dd9309c9a4d7a5fa9824c6b9cf Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 11:28:08 -0400 Subject: Fix locale preference storing --- src/main/java/com/gitblit/ConfigUserService.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gitblit/ConfigUserService.java b/src/main/java/com/gitblit/ConfigUserService.java index 0c5b2a58..d7d6c14f 100644 --- a/src/main/java/com/gitblit/ConfigUserService.java +++ b/src/main/java/com/gitblit/ConfigUserService.java @@ -24,6 +24,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -712,8 +713,14 @@ public class ConfigUserService implements IUserService { config.setBoolean(USER, model.username, DISABLED, true); } if (model.getPreferences() != null) { - if (model.getPreferences().getLocale() != null) { - String val = model.getPreferences().getLocale().getLanguage() + "_" + model.getPreferences().getLocale().getCountry(); + Locale locale = model.getPreferences().getLocale(); + if (locale != null) { + String val; + if (StringUtils.isEmpty(locale.getCountry())) { + val = locale.getLanguage(); + } else { + val = locale.getLanguage() + "_" + locale.getCountry(); + } config.setString(USER, model.username, LOCALE, val); } -- cgit v1.2.3 From e0331746c1aee48a18ae2954770ca481d49eaf36 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 11:33:42 -0400 Subject: Link to open tickets view for open milestones from ticket page --- src/main/java/com/gitblit/wicket/pages/TicketPage.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/TicketPage.java b/src/main/java/com/gitblit/wicket/pages/TicketPage.java index f7e4ada5..f5f63d23 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketPage.java +++ b/src/main/java/com/gitblit/wicket/pages/TicketPage.java @@ -250,8 +250,12 @@ public class TicketPage extends RepositoryPage { } else { // link to milestone query TicketMilestone milestone = app().tickets().getMilestone(repository, ticket.milestone); - PageParameters milestoneParameters = new PageParameters(); - milestoneParameters.put("r", repositoryName); + PageParameters milestoneParameters; + if (milestone.isOpen()) { + milestoneParameters = WicketUtils.newOpenTicketsParameter(repositoryName); + } else { + milestoneParameters = WicketUtils.newRepositoryParameter(repositoryName); + } milestoneParameters.put(Lucene.milestone.name(), ticket.milestone); int progress = 0; int open = 0; -- cgit v1.2.3 From dcd6541d4e7a159e7478962121fbfd0782568af0 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 12:36:09 -0400 Subject: Switch to basic ant copy filter for web.xml --- build.xml | 22 ++++++++++++++++++---- src/main/java/WEB-INF/web.xml | 6 +----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/build.xml b/build.xml index be6f1dd2..035f1896 100644 --- a/build.xml +++ b/build.xml @@ -174,8 +174,19 @@ + + + + + + + + + + + @@ -240,10 +251,13 @@ - - - - + + + + + + + diff --git a/src/main/java/WEB-INF/web.xml b/src/main/java/WEB-INF/web.xml index 3a6c4490..13f612e4 100644 --- a/src/main/java/WEB-INF/web.xml +++ b/src/main/java/WEB-INF/web.xml @@ -30,12 +30,8 @@ - - Gitblit - @gb.version@ - + Gitblit - @gb.version@ - - - + -- cgit v1.2.3 From 65d4270b188ae7b6b3ef7a70fca35c4d7e7696af Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 14:01:44 -0400 Subject: Fix substring regression in repository name panel --- src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java index d3e493ed..f381a45e 100644 --- a/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java +++ b/src/main/java/com/gitblit/wicket/panels/RepositoryNamePanel.java @@ -84,10 +84,11 @@ public class RepositoryNamePanel extends BasePanel { // set the defaultProject to the current repository project if (StringUtils.isEmpty(repository.projectPath)) { defaultPath = "/"; + defaultName = repository.name; } else { defaultPath = repository.projectPath + "/"; + defaultName = repository.name.substring(defaultPath.length()); } - defaultName = repository.name.substring(defaultPath.length()); pathNames.add(defaultPath); } -- cgit v1.2.3 From a755c76d9a035bc9cf9ca82ff1b8541d6711c635 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 14:09:12 -0400 Subject: Add link to Gitblit's Docker file in the Docker registry --- build.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.xml b/build.xml index f33aed34..c405d06d 100644 --- a/build.xml +++ b/build.xml @@ -558,6 +558,8 @@ + + -- cgit v1.2.3 From a8d9888516fe052d5879b293a91854e41365fd0c Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 14:10:05 -0400 Subject: Redirect to teams page on team creation, updates, or deletions --- src/main/java/com/gitblit/wicket/pages/EditTeamPage.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java b/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java index a0d11a05..f537f33d 100644 --- a/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java +++ b/src/main/java/com/gitblit/wicket/pages/EditTeamPage.java @@ -86,7 +86,7 @@ public class EditTeamPage extends RootSubPage { @Override protected Class getRootNavPageClass() { - return UsersPage.class; + return TeamsPage.class; } protected void setupPage(final TeamModel teamModel) { @@ -214,7 +214,7 @@ public class EditTeamPage extends RootSubPage { teamModel.name)); } // back to users page - setResponsePage(UsersPage.class); + setResponsePage(TeamsPage.class); } }; @@ -249,7 +249,7 @@ public class EditTeamPage extends RootSubPage { @Override public void onSubmit() { - setResponsePage(UsersPage.class); + setResponsePage(TeamsPage.class); } }; cancel.setDefaultFormProcessing(false); -- cgit v1.2.3 From ca4d98678c20e4033fdaca09ecbbf0f5952e0b84 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 14:10:51 -0400 Subject: Add repository and user/team lifecycle listener extension points --- src/main/java/com/gitblit/DaggerModule.java | 9 +- src/main/java/com/gitblit/FederationClient.java | 4 +- src/main/java/com/gitblit/MigrateTickets.java | 2 +- src/main/java/com/gitblit/ReindexTickets.java | 2 +- .../extensions/RepositoryLifeCycleListener.java | 45 ++++++++ .../extensions/UserTeamLifeCycleListener.java | 62 +++++++++++ .../com/gitblit/manager/RepositoryManager.java | 25 +++++ src/main/java/com/gitblit/manager/UserManager.java | 124 +++++++++++++++++++-- .../java/com/gitblit/servlet/GitblitContext.java | 10 +- src/site/plugins_extensions.mkd | 75 ++++++++++++- src/test/config/test-users.conf | 6 +- .../gitblit/tests/AuthenticationManagerTest.java | 2 +- .../com/gitblit/tests/BranchTicketServiceTest.java | 4 +- .../com/gitblit/tests/FileTicketServiceTest.java | 4 +- .../gitblit/tests/HtpasswdAuthenticationTest.java | 8 +- .../com/gitblit/tests/LdapAuthenticationTest.java | 10 +- .../java/com/gitblit/tests/LuceneExecutorTest.java | 4 +- .../com/gitblit/tests/RedisTicketServiceTest.java | 4 +- .../gitblit/tests/RedmineAuthenticationTest.java | 6 +- 19 files changed, 362 insertions(+), 44 deletions(-) create mode 100644 src/main/java/com/gitblit/extensions/RepositoryLifeCycleListener.java create mode 100644 src/main/java/com/gitblit/extensions/UserTeamLifeCycleListener.java diff --git a/src/main/java/com/gitblit/DaggerModule.java b/src/main/java/com/gitblit/DaggerModule.java index b89f8c44..6ad3fe63 100644 --- a/src/main/java/com/gitblit/DaggerModule.java +++ b/src/main/java/com/gitblit/DaggerModule.java @@ -91,8 +91,11 @@ public class DaggerModule { return new NotificationManager(settings); } - @Provides @Singleton IUserManager provideUserManager(IRuntimeManager runtimeManager) { - return new UserManager(runtimeManager); + @Provides @Singleton IUserManager provideUserManager( + IRuntimeManager runtimeManager, + IPluginManager pluginManager) { + + return new UserManager(runtimeManager, pluginManager); } @Provides @Singleton IAuthenticationManager provideAuthenticationManager( @@ -131,10 +134,12 @@ public class DaggerModule { @Provides @Singleton IRepositoryManager provideRepositoryManager( IRuntimeManager runtimeManager, + IPluginManager pluginManager, IUserManager userManager) { return new RepositoryManager( runtimeManager, + pluginManager, userManager); } diff --git a/src/main/java/com/gitblit/FederationClient.java b/src/main/java/com/gitblit/FederationClient.java index cd06c3cb..29cdefe6 100644 --- a/src/main/java/com/gitblit/FederationClient.java +++ b/src/main/java/com/gitblit/FederationClient.java @@ -94,8 +94,8 @@ public class FederationClient { // configure the Gitblit singleton for minimal, non-server operation RuntimeManager runtime = new RuntimeManager(settings, baseFolder).start(); NoopNotificationManager notifications = new NoopNotificationManager().start(); - UserManager users = new UserManager(runtime).start(); - RepositoryManager repositories = new RepositoryManager(runtime, users).start(); + UserManager users = new UserManager(runtime, null).start(); + RepositoryManager repositories = new RepositoryManager(runtime, null, users).start(); FederationManager federation = new FederationManager(runtime, notifications, repositories).start(); IGitblit gitblit = new GitblitManager(runtime, null, notifications, users, null, null, repositories, null, federation); diff --git a/src/main/java/com/gitblit/MigrateTickets.java b/src/main/java/com/gitblit/MigrateTickets.java index b6d72376..ad1c63ea 100644 --- a/src/main/java/com/gitblit/MigrateTickets.java +++ b/src/main/java/com/gitblit/MigrateTickets.java @@ -135,7 +135,7 @@ public class MigrateTickets { settings.overrideSetting(ITicketService.SETTING_UPDATE_DIFFSTATS, false); IRuntimeManager runtimeManager = new RuntimeManager(settings, baseFolder).start(); - IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, null).start(); + IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, null, null).start(); String inputServiceName = settings.getString(Keys.tickets.service, BranchTicketService.class.getSimpleName()); if (StringUtils.isEmpty(inputServiceName)) { diff --git a/src/main/java/com/gitblit/ReindexTickets.java b/src/main/java/com/gitblit/ReindexTickets.java index 51ca1657..5a614481 100644 --- a/src/main/java/com/gitblit/ReindexTickets.java +++ b/src/main/java/com/gitblit/ReindexTickets.java @@ -127,7 +127,7 @@ public class ReindexTickets { settings.overrideSetting(Keys.web.activityCacheDays, 0); IRuntimeManager runtimeManager = new RuntimeManager(settings, baseFolder).start(); - IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, null).start(); + IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, null, null).start(); String serviceName = settings.getString(Keys.tickets.service, BranchTicketService.class.getSimpleName()); if (StringUtils.isEmpty(serviceName)) { diff --git a/src/main/java/com/gitblit/extensions/RepositoryLifeCycleListener.java b/src/main/java/com/gitblit/extensions/RepositoryLifeCycleListener.java new file mode 100644 index 00000000..5ef03af7 --- /dev/null +++ b/src/main/java/com/gitblit/extensions/RepositoryLifeCycleListener.java @@ -0,0 +1,45 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.extensions; + +import ro.fortsoft.pf4j.ExtensionPoint; + +import com.gitblit.models.RepositoryModel; + +/** + * Extension point to allow plugins to listen to major repository lifecycle events. + * + * @author James Moger + * @since 1.6.0 + */ +public abstract class RepositoryLifeCycleListener implements ExtensionPoint { + + /** + * Called after a repository has been created. + * + * @param repository + * @since 1.6.0 + */ + public abstract void onCreation(RepositoryModel repository); + + /** + * Called after a repository has been deleted. + * + * @param repository + * @since 1.6.0 + */ + public abstract void onDeletion(RepositoryModel repository); +} diff --git a/src/main/java/com/gitblit/extensions/UserTeamLifeCycleListener.java b/src/main/java/com/gitblit/extensions/UserTeamLifeCycleListener.java new file mode 100644 index 00000000..6f4cd9ba --- /dev/null +++ b/src/main/java/com/gitblit/extensions/UserTeamLifeCycleListener.java @@ -0,0 +1,62 @@ +/* + * Copyright 2014 gitblit.com. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gitblit.extensions; + +import ro.fortsoft.pf4j.ExtensionPoint; + +import com.gitblit.models.TeamModel; +import com.gitblit.models.UserModel; + +/** + * Extension point to allow plugins to listen to major user and team lifecycle events. + * + * @author James Moger + * @since 1.6.0 + */ +public abstract class UserTeamLifeCycleListener implements ExtensionPoint { + + /** + * Called after a user has been created. + * + * @param user + * @since 1.6.0 + */ + public abstract void onCreation(UserModel user); + + /** + * Called after a user has been deleted. + * + * @param user + * @since 1.6.0 + */ + public abstract void onDeletion(UserModel user); + + /** + * Called after a team has been created. + * + * @param team + * @since 1.6.0 + */ + public abstract void onCreation(TeamModel team); + + /** + * Called after a team has been deleted. + * + * @param team + * @since 1.6.0 + */ + public abstract void onDeletion(TeamModel team); +} diff --git a/src/main/java/com/gitblit/manager/RepositoryManager.java b/src/main/java/com/gitblit/manager/RepositoryManager.java index 31d6b341..e0721c7c 100644 --- a/src/main/java/com/gitblit/manager/RepositoryManager.java +++ b/src/main/java/com/gitblit/manager/RepositoryManager.java @@ -66,6 +66,7 @@ import com.gitblit.Constants.RegistrantType; import com.gitblit.GitBlitException; import com.gitblit.IStoredSettings; import com.gitblit.Keys; +import com.gitblit.extensions.RepositoryLifeCycleListener; import com.gitblit.models.ForkModel; import com.gitblit.models.Metric; import com.gitblit.models.RefModel; @@ -114,6 +115,8 @@ public class RepositoryManager implements IRepositoryManager { private final IRuntimeManager runtimeManager; + private final IPluginManager pluginManager; + private final IUserManager userManager; private final File repositoriesFolder; @@ -126,10 +129,12 @@ public class RepositoryManager implements IRepositoryManager { public RepositoryManager( IRuntimeManager runtimeManager, + IPluginManager pluginManager, IUserManager userManager) { this.settings = runtimeManager.getSettings(); this.runtimeManager = runtimeManager; + this.pluginManager = pluginManager; this.userManager = userManager; this.repositoriesFolder = runtimeManager.getFileOrFolder(Keys.git.repositoriesFolder, "${baseFolder}/git"); } @@ -1420,6 +1425,16 @@ public class RepositoryManager implements IRepositoryManager { removeFromCachedRepositoryList(repositoryName); // model will actually be replaced on next load because config is stale addToCachedRepositoryList(repository); + + if (isCreate && pluginManager != null) { + for (RepositoryLifeCycleListener listener : pluginManager.getExtensions(RepositoryLifeCycleListener.class)) { + try { + listener.onCreation(repository); + } catch (Throwable t) { + logger.error(String.format("failed to call plugin onCreation %s", repositoryName), t); + } + } + } } /** @@ -1588,6 +1603,16 @@ public class RepositoryManager implements IRepositoryManager { FileUtils.delete(folder, FileUtils.RECURSIVE | FileUtils.RETRY); if (userManager.deleteRepositoryRole(repositoryName)) { logger.info(MessageFormat.format("Repository \"{0}\" deleted", repositoryName)); + + if (pluginManager != null) { + for (RepositoryLifeCycleListener listener : pluginManager.getExtensions(RepositoryLifeCycleListener.class)) { + try { + listener.onDeletion(repository); + } catch (Throwable t) { + logger.error(String.format("failed to call plugin onDeletion %s", repositoryName), t); + } + } + } return true; } } diff --git a/src/main/java/com/gitblit/manager/UserManager.java b/src/main/java/com/gitblit/manager/UserManager.java index 67b1d68f..2b82ffb6 100644 --- a/src/main/java/com/gitblit/manager/UserManager.java +++ b/src/main/java/com/gitblit/manager/UserManager.java @@ -32,6 +32,7 @@ import com.gitblit.Constants; import com.gitblit.IStoredSettings; import com.gitblit.IUserService; import com.gitblit.Keys; +import com.gitblit.extensions.UserTeamLifeCycleListener; import com.gitblit.models.TeamModel; import com.gitblit.models.UserModel; import com.gitblit.utils.StringUtils; @@ -50,13 +51,16 @@ public class UserManager implements IUserManager { private final IRuntimeManager runtimeManager; + private final IPluginManager pluginManager; + private final Map legacyBackingServices; private IUserService userService; - public UserManager(IRuntimeManager runtimeManager) { + public UserManager(IRuntimeManager runtimeManager, IPluginManager pluginManager) { this.settings = runtimeManager.getSettings(); this.runtimeManager = runtimeManager; + this.pluginManager = pluginManager; // map of legacy realm backing user services legacyBackingServices = new HashMap(); @@ -209,7 +213,14 @@ public class UserManager implements IUserManager { */ @Override public boolean updateUserModel(UserModel model) { - return userService.updateUserModel(model); + final boolean isCreate = null == userService.getUserModel(model.username); + if (userService.updateUserModel(model)) { + if (isCreate) { + callCreateUserListeners(model); + } + return true; + } + return false; } /** @@ -236,7 +247,14 @@ public class UserManager implements IUserManager { */ @Override public boolean updateUserModel(String username, UserModel model) { - return userService.updateUserModel(username, model); + final boolean isCreate = null == userService.getUserModel(username); + if (userService.updateUserModel(username, model)) { + if (isCreate) { + callCreateUserListeners(model); + } + return true; + } + return false; } /** @@ -247,7 +265,11 @@ public class UserManager implements IUserManager { */ @Override public boolean deleteUserModel(UserModel model) { - return userService.deleteUserModel(model); + if (userService.deleteUserModel(model)) { + callDeleteUserListeners(model); + return true; + } + return false; } /** @@ -262,7 +284,12 @@ public class UserManager implements IUserManager { return false; } String usernameDecoded = StringUtils.decodeUsername(username); - return userService.deleteUser(usernameDecoded); + UserModel user = getUserModel(usernameDecoded); + if (userService.deleteUser(usernameDecoded)) { + callDeleteUserListeners(user); + return true; + } + return false; } /** @@ -349,7 +376,14 @@ public class UserManager implements IUserManager { */ @Override public boolean updateTeamModel(TeamModel model) { - return userService.updateTeamModel(model); + final boolean isCreate = null == userService.getTeamModel(model.name); + if (userService.updateTeamModel(model)) { + if (isCreate) { + callCreateTeamListeners(model); + } + return true; + } + return false; } /** @@ -377,7 +411,14 @@ public class UserManager implements IUserManager { */ @Override public boolean updateTeamModel(String teamname, TeamModel model) { - return userService.updateTeamModel(teamname, model); + final boolean isCreate = null == userService.getTeamModel(teamname); + if (userService.updateTeamModel(teamname, model)) { + if (isCreate) { + callCreateTeamListeners(model); + } + return true; + } + return false; } /** @@ -389,7 +430,11 @@ public class UserManager implements IUserManager { */ @Override public boolean deleteTeamModel(TeamModel model) { - return userService.deleteTeamModel(model); + if (userService.deleteTeamModel(model)) { + callDeleteTeamListeners(model); + return true; + } + return false; } /** @@ -401,7 +446,12 @@ public class UserManager implements IUserManager { */ @Override public boolean deleteTeam(String teamname) { - return userService.deleteTeam(teamname); + TeamModel team = userService.getTeamModel(teamname); + if (userService.deleteTeam(teamname)) { + callDeleteTeamListeners(team); + return true; + } + return false; } /** @@ -440,4 +490,60 @@ public class UserManager implements IUserManager { public boolean deleteRepositoryRole(String role) { return userService.deleteRepositoryRole(role); } + + protected void callCreateUserListeners(UserModel user) { + if (pluginManager == null || user == null) { + return; + } + + for (UserTeamLifeCycleListener listener : pluginManager.getExtensions(UserTeamLifeCycleListener.class)) { + try { + listener.onCreation(user); + } catch (Throwable t) { + logger.error(String.format("failed to call plugin.onCreation%s", user.username), t); + } + } + } + + protected void callCreateTeamListeners(TeamModel team) { + if (pluginManager == null || team == null) { + return; + } + + for (UserTeamLifeCycleListener listener : pluginManager.getExtensions(UserTeamLifeCycleListener.class)) { + try { + listener.onCreation(team); + } catch (Throwable t) { + logger.error(String.format("failed to call plugin.onCreation %s", team.name), t); + } + } + } + + protected void callDeleteUserListeners(UserModel user) { + if (pluginManager == null || user == null) { + return; + } + + for (UserTeamLifeCycleListener listener : pluginManager.getExtensions(UserTeamLifeCycleListener.class)) { + try { + listener.onDeletion(user); + } catch (Throwable t) { + logger.error(String.format("failed to call plugin.onDeletion %s", user.username), t); + } + } + } + + protected void callDeleteTeamListeners(TeamModel team) { + if (pluginManager == null || team == null) { + return; + } + + for (UserTeamLifeCycleListener listener : pluginManager.getExtensions(UserTeamLifeCycleListener.class)) { + try { + listener.onDeletion(team); + } catch (Throwable t) { + logger.error(String.format("failed to call plugin.onDeletion %s", team.name), t); + } + } + } } diff --git a/src/main/java/com/gitblit/servlet/GitblitContext.java b/src/main/java/com/gitblit/servlet/GitblitContext.java index 50f22d5a..d5b4092c 100644 --- a/src/main/java/com/gitblit/servlet/GitblitContext.java +++ b/src/main/java/com/gitblit/servlet/GitblitContext.java @@ -175,6 +175,9 @@ public class GitblitContext extends DaggerContext { runtime.start(); managers.add(runtime); + // create the plugin manager instance but do not start it + loadManager(injector, IPluginManager.class); + // start all other managers startManager(injector, INotificationManager.class); startManager(injector, IUserManager.class); @@ -215,9 +218,14 @@ public class GitblitContext extends DaggerContext { return null; } + protected X loadManager(ObjectGraph injector, Class clazz) { + X x = injector.get(clazz); + return x; + } + protected X startManager(ObjectGraph injector, Class clazz) { + X x = loadManager(injector, clazz); logManager(clazz); - X x = injector.get(clazz); x.start(); managers.add(x); return x; diff --git a/src/site/plugins_extensions.mkd b/src/site/plugins_extensions.mkd index 99b6400f..0e066438 100644 --- a/src/site/plugins_extensions.mkd +++ b/src/site/plugins_extensions.mkd @@ -286,7 +286,7 @@ public class MyNavLink extends NavLinkExtension { } ``` -### Lifecycle Listener +### Server Lifecycle Listener *SINCE 1.6.0* @@ -313,4 +313,75 @@ public class MyLifeCycleListener extends LifeCycleListener { log.info("Gitblit is Going Down!!"); } } -``` \ No newline at end of file +``` + +### Repository Lifecycle Listener + +*SINCE 1.6.0* + +You can provide a lifecycle listener to be notified when Gitblit has created or deleted a repository. + +```java +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ro.fortsoft.pf4j.Extension; +import com.gitblit.extensions.RepositoryLifeCycleListener; +import com.gitblit.models.RepositoryModel; + +@Extension +public class MyRepoLifeCycleListener extends RepositoryLifeCycleListener { + + final Logger log = LoggerFactory.getLogger(getClass()); + + @Override + public void onCreation(RepositoryModel repo) { + log.info("Gitblit created {}", repo); + } + + @Override + public void onDeletion(RepositoryModel repo) { + log.info("Gitblit deleted {}", repo); + } +} +``` + +### User/Team Lifecycle Listener + +*SINCE 1.6.0* + +You can provide a lifecycle listener to be notified when Gitblit has created or deleted a user or a team. + +```java +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import ro.fortsoft.pf4j.Extension; +import com.gitblit.extensions.UserTeamLifeCycleListener; +import com.gitblit.models.TeamModel; +import com.gitblit.models.UserModel; + +@Extension +public class MyUserTeamLifeCycleListener extends UserTeamLifeCycleListener { + + final Logger log = LoggerFactory.getLogger(getClass()); + + @Override + public void onCreation(UserModel user) { + log.info("Gitblit created user {}", user); + } + + @Override + public void onDeletion(UserModel user) { + log.info("Gitblit deleted user {}", user); + } + + @Override + public void onCreation(TeamModel team) { + log.info("Gitblit created team {}", team); + } + + @Override + public void onDeletion(TeamModel team) { + log.info("Gitblit deleted team {}", team); + } +} +``` diff --git a/src/test/config/test-users.conf b/src/test/config/test-users.conf index 1d01f846..4361410c 100644 --- a/src/test/config/test-users.conf +++ b/src/test/config/test-users.conf @@ -2,13 +2,9 @@ password = admin cookie = dd94709528bb1c83d08f3088d4043f4742891f4f accountType = LOCAL + emailMeOnMyTicketChanges = true role = "#admin" role = "#notfederated" -[user "sampleuser"] - password = sampleuser - cookie = 6e07ed42149fc166206319faffdfba2e2ec82e43 - accountType = LOCAL - role = "#none" [team "admins"] role = "#none" accountType = LOCAL diff --git a/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java b/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java index 84a2b749..f1d2711e 100644 --- a/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java +++ b/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java @@ -43,7 +43,7 @@ public class AuthenticationManagerTest extends GitblitUnitTest { IAuthenticationManager newAuthenticationManager() { RuntimeManager runtime = new RuntimeManager(getSettings(), GitBlitSuite.BASEFOLDER).start(); - users = new UserManager(runtime).start(); + users = new UserManager(runtime, null).start(); AuthenticationManager auth = new AuthenticationManager(runtime, users).start(); return auth; } diff --git a/src/test/java/com/gitblit/tests/BranchTicketServiceTest.java b/src/test/java/com/gitblit/tests/BranchTicketServiceTest.java index 6119b8db..cc404abf 100644 --- a/src/test/java/com/gitblit/tests/BranchTicketServiceTest.java +++ b/src/test/java/com/gitblit/tests/BranchTicketServiceTest.java @@ -54,8 +54,8 @@ public class BranchTicketServiceTest extends TicketServiceTest { IRuntimeManager runtimeManager = new RuntimeManager(settings).start(); IPluginManager pluginManager = new PluginManager(runtimeManager).start(); INotificationManager notificationManager = new NotificationManager(settings).start(); - IUserManager userManager = new UserManager(runtimeManager).start(); - IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, userManager).start(); + IUserManager userManager = new UserManager(runtimeManager, pluginManager).start(); + IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, pluginManager, userManager).start(); BranchTicketService service = new BranchTicketService( runtimeManager, diff --git a/src/test/java/com/gitblit/tests/FileTicketServiceTest.java b/src/test/java/com/gitblit/tests/FileTicketServiceTest.java index 20cde26b..6ede042a 100644 --- a/src/test/java/com/gitblit/tests/FileTicketServiceTest.java +++ b/src/test/java/com/gitblit/tests/FileTicketServiceTest.java @@ -53,8 +53,8 @@ public class FileTicketServiceTest extends TicketServiceTest { IRuntimeManager runtimeManager = new RuntimeManager(settings).start(); IPluginManager pluginManager = new PluginManager(runtimeManager).start(); INotificationManager notificationManager = new NotificationManager(settings).start(); - IUserManager userManager = new UserManager(runtimeManager).start(); - IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, userManager).start(); + IUserManager userManager = new UserManager(runtimeManager, pluginManager).start(); + IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, pluginManager, userManager).start(); FileTicketService service = new FileTicketService( runtimeManager, diff --git a/src/test/java/com/gitblit/tests/HtpasswdAuthenticationTest.java b/src/test/java/com/gitblit/tests/HtpasswdAuthenticationTest.java index 4e1c3ac1..f4e24d4e 100644 --- a/src/test/java/com/gitblit/tests/HtpasswdAuthenticationTest.java +++ b/src/test/java/com/gitblit/tests/HtpasswdAuthenticationTest.java @@ -75,15 +75,15 @@ public class HtpasswdAuthenticationTest extends GitblitUnitTest { private HtpasswdAuthProvider newHtpasswdAuthentication(IStoredSettings settings) { RuntimeManager runtime = new RuntimeManager(settings, GitBlitSuite.BASEFOLDER).start(); - UserManager users = new UserManager(runtime).start(); + UserManager users = new UserManager(runtime, null).start(); HtpasswdAuthProvider htpasswd = new HtpasswdAuthProvider(); htpasswd.setup(runtime, users); return htpasswd; } - + private AuthenticationManager newAuthenticationManager(IStoredSettings settings) { RuntimeManager runtime = new RuntimeManager(settings, GitBlitSuite.BASEFOLDER).start(); - UserManager users = new UserManager(runtime).start(); + UserManager users = new UserManager(runtime, null).start(); HtpasswdAuthProvider htpasswd = new HtpasswdAuthProvider(); htpasswd.setup(runtime, users); AuthenticationManager auth = new AuthenticationManager(runtime, users); @@ -191,7 +191,7 @@ public class HtpasswdAuthenticationTest extends GitblitUnitTest { assertEquals("leading", user.username); } - + @Test public void testAuthenticationManager() { diff --git a/src/test/java/com/gitblit/tests/LdapAuthenticationTest.java b/src/test/java/com/gitblit/tests/LdapAuthenticationTest.java index 21063d58..646f7e9f 100644 --- a/src/test/java/com/gitblit/tests/LdapAuthenticationTest.java +++ b/src/test/java/com/gitblit/tests/LdapAuthenticationTest.java @@ -68,7 +68,7 @@ public class LdapAuthenticationTest extends GitblitUnitTest { private static InMemoryDirectoryServer ds; private IUserManager userManager; - + private AuthenticationManager auth; private MemorySettings settings; @@ -97,12 +97,12 @@ public class LdapAuthenticationTest extends GitblitUnitTest { private LdapAuthProvider newLdapAuthentication(IStoredSettings settings) { RuntimeManager runtime = new RuntimeManager(settings, GitBlitSuite.BASEFOLDER).start(); - userManager = new UserManager(runtime).start(); + userManager = new UserManager(runtime, null).start(); LdapAuthProvider ldap = new LdapAuthProvider(); ldap.setup(runtime, userManager); return ldap; } - + private AuthenticationManager newAuthenticationManager(IStoredSettings settings) { RuntimeManager runtime = new RuntimeManager(settings, GitBlitSuite.BASEFOLDER).start(); AuthenticationManager auth = new AuthenticationManager(runtime, userManager); @@ -258,7 +258,7 @@ public class LdapAuthenticationTest extends GitblitUnitTest { assertNull(userThreeModel.getTeam("git_admins")); assertTrue(userThreeModel.canAdmin); } - + @Test public void testBindWithUser() { settings.put(Keys.realm.ldap.bindpattern, "CN=${username},OU=US,OU=Users,OU=UserControl,OU=MyOrganization,DC=MyDomain"); @@ -267,7 +267,7 @@ public class LdapAuthenticationTest extends GitblitUnitTest { UserModel userOneModel = auth.authenticate("UserOne", "userOnePassword".toCharArray()); assertNotNull(userOneModel); - + UserModel userOneModelFailedAuth = auth.authenticate("UserOne", "userTwoPassword".toCharArray()); assertNull(userOneModelFailedAuth); } diff --git a/src/test/java/com/gitblit/tests/LuceneExecutorTest.java b/src/test/java/com/gitblit/tests/LuceneExecutorTest.java index 319c09c1..5c319e65 100644 --- a/src/test/java/com/gitblit/tests/LuceneExecutorTest.java +++ b/src/test/java/com/gitblit/tests/LuceneExecutorTest.java @@ -49,8 +49,8 @@ public class LuceneExecutorTest extends GitblitUnitTest { MemorySettings settings = new MemorySettings(); settings.put(Keys.git.repositoriesFolder, GitBlitSuite.REPOSITORIES); RuntimeManager runtime = new RuntimeManager(settings, GitBlitSuite.BASEFOLDER).start(); - UserManager users = new UserManager(runtime).start(); - RepositoryManager repos = new RepositoryManager(runtime, users); + UserManager users = new UserManager(runtime, null).start(); + RepositoryManager repos = new RepositoryManager(runtime, null, users); return new LuceneService(settings, repos); } diff --git a/src/test/java/com/gitblit/tests/RedisTicketServiceTest.java b/src/test/java/com/gitblit/tests/RedisTicketServiceTest.java index 94391a15..b782b449 100644 --- a/src/test/java/com/gitblit/tests/RedisTicketServiceTest.java +++ b/src/test/java/com/gitblit/tests/RedisTicketServiceTest.java @@ -61,8 +61,8 @@ public class RedisTicketServiceTest extends TicketServiceTest { IRuntimeManager runtimeManager = new RuntimeManager(settings).start(); IPluginManager pluginManager = new PluginManager(runtimeManager).start(); INotificationManager notificationManager = new NotificationManager(settings).start(); - IUserManager userManager = new UserManager(runtimeManager).start(); - IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, userManager).start(); + IUserManager userManager = new UserManager(runtimeManager, pluginManager).start(); + IRepositoryManager repositoryManager = new RepositoryManager(runtimeManager, pluginManager, userManager).start(); RedisTicketService service = new RedisTicketService( runtimeManager, diff --git a/src/test/java/com/gitblit/tests/RedmineAuthenticationTest.java b/src/test/java/com/gitblit/tests/RedmineAuthenticationTest.java index 6ede8313..3b6b7bba 100644 --- a/src/test/java/com/gitblit/tests/RedmineAuthenticationTest.java +++ b/src/test/java/com/gitblit/tests/RedmineAuthenticationTest.java @@ -26,7 +26,7 @@ public class RedmineAuthenticationTest extends GitblitUnitTest { RedmineAuthProvider newRedmineAuthentication(IStoredSettings settings) { RuntimeManager runtime = new RuntimeManager(settings, GitBlitSuite.BASEFOLDER).start(); - UserManager users = new UserManager(runtime).start(); + UserManager users = new UserManager(runtime, null).start(); RedmineAuthProvider redmine = new RedmineAuthProvider(); redmine.setup(runtime, users); return redmine; @@ -35,10 +35,10 @@ public class RedmineAuthenticationTest extends GitblitUnitTest { RedmineAuthProvider newRedmineAuthentication() { return newRedmineAuthentication(getSettings()); } - + AuthenticationManager newAuthenticationManager() { RuntimeManager runtime = new RuntimeManager(getSettings(), GitBlitSuite.BASEFOLDER).start(); - UserManager users = new UserManager(runtime).start(); + UserManager users = new UserManager(runtime, null).start(); RedmineAuthProvider redmine = new RedmineAuthProvider(); redmine.setup(runtime, users); redmine.setTestingCurrentUserAsJson(JSON); -- cgit v1.2.3 From 2bfea381bbcea934f7e20f8c00db86e990c2fc93 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 14:11:05 -0400 Subject: Documentation --- releases.moxie | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/releases.moxie b/releases.moxie index c1e11d98..3cd7cee3 100644 --- a/releases.moxie +++ b/releases.moxie @@ -5,9 +5,26 @@ r24: { title: ${project.name} ${project.version} released id: ${project.version} date: ${project.buildDate} - note: ~ + note: '' + The next major release (v1.7.0) will focus on: + * ticket-75: making projects more useful including the concept of project ownership + + This improvement will require a NON-BACKWARDS-COMPATIBLE migration of repository ownership from the RpeositoryModel to the UserModel + + * ticket-55: facilitating usage of tickets & git-flow in the web ui + '' html: ~ - text: ~ + text: '' + Highlights: + + * My Tickets page + * User Preferences web ui + * SSH key management web ui + * Basic CRUD pages for ticket milestones + * Overhaul repository creation, editing, and empty repository pages + + The OpenShift Express build has been dropped. You can deploy GO or WAR on Express so this build is no longer necessary. + '' security: ~ fixes: - Allow ticket responsible selection if anonymous push is enabled (issue-425, ticket-71) -- cgit v1.2.3 From 1ac6d11165dffed9ca244b3e62545506f7e9c284 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 18:36:17 -0400 Subject: Fix invalid generated SSH url for port 22 --- src/main/java/com/gitblit/transport/ssh/SshDaemon.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java index 7c512907..261daa66 100644 --- a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java +++ b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java @@ -142,7 +142,7 @@ public class SshDaemon { public String formatUrl(String gituser, String servername, String repository) { if (sshd.getPort() == DEFAULT_PORT) { // standard port - return MessageFormat.format("{0}@{1}/{2}", gituser, servername, + return MessageFormat.format("ssh://{0}@{1}/{2}", gituser, servername, repository); } else { // non-standard port -- cgit v1.2.3 From deba6e10a878141aa80bdae603b2549e76d07b95 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 18:39:15 -0400 Subject: Documentation --- releases.moxie | 1 + 1 file changed, 1 insertion(+) diff --git a/releases.moxie b/releases.moxie index 3cd7cee3..ce754209 100644 --- a/releases.moxie +++ b/releases.moxie @@ -36,6 +36,7 @@ r24: { - Removed Ticket responsible team permission exclusion (ticket-87) - Fixed SSH daemon thread exhaustion (ticket-89) - Fixed Ticket responsible selections not considering the AUTHENTICATED authorization control (ticket-91) + - Fixed invalid generated SSH url for port 22 (issue-444, ticket-98) changes: - Split the pages servlet into a raw servlet and a pages servlet. All raw links now use the raw servlet (issue-413, ticket-49) - Drop deprecated --set-upstream syntax for -u (ticket-59) -- cgit v1.2.3 From d2d5fc600f72498007d0c78d84f058ae68b79815 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 18:45:22 -0400 Subject: Fix milestone link statii query parameters --- src/main/java/com/gitblit/wicket/pages/TicketsPage.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java index dfa7b021..658cddec 100644 --- a/src/main/java/com/gitblit/wicket/pages/TicketsPage.java +++ b/src/main/java/com/gitblit/wicket/pages/TicketsPage.java @@ -536,7 +536,13 @@ public class TicketsPage extends RepositoryPage { item.add(entryPanel); final TicketMilestone tm = item.getModelObject(); - PageParameters params = queryParameters(null, tm.name, null, null, null, true, 1); + String [] states; + if (tm.isOpen()) { + states = TicketsUI.openStatii; + } else { + states = TicketsUI.closedStatii; + } + PageParameters params = queryParameters(null, tm.name, states, null, null, true, 1); entryPanel.add(new LinkPanel("milestoneName", null, tm.name, TicketsPage.class, params).setRenderBodyOnly(true)); String css; -- cgit v1.2.3 From a5086dcf7c70326c810906c57c978586e34a5ed0 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 9 Jun 2014 21:36:43 -0400 Subject: Documentation --- build.xml | 6 ++++-- src/site/roadmap.mkd | 7 +++---- src/site/setup_transport_ssh.mkd | 12 ++++++++++-- src/site/siteindex.mkd | 22 ++++++++++++++++++++-- src/site/tickets_replication.mkd | 4 ++-- src/site/tickets_setup.mkd | 2 +- 6 files changed, 40 insertions(+), 13 deletions(-) diff --git a/build.xml b/build.xml index c405d06d..39fdb2e7 100644 --- a/build.xml +++ b/build.xml @@ -560,6 +560,8 @@ + + @@ -574,7 +576,7 @@ - + @@ -860,7 +862,7 @@ - + diff --git a/src/site/roadmap.mkd b/src/site/roadmap.mkd index 03d69dfb..ea643218 100644 --- a/src/site/roadmap.mkd +++ b/src/site/roadmap.mkd @@ -3,7 +3,6 @@ This is not exactly a formal roadmap but it is a priority list of what might be implemented in future releases. This list is volatile and may not reflect what will be in the next release. -* **In-Progress**: Integrate an SSH daemon (issue-369) -* Diff should highlight inserted/removed fragment compared to original line -* Respect Gerrit branch permissions, if found (issue 36) - +* Add support for Project owners/administrators (ticket-75) +* Add Project create/update pages +* Integrate improvements for git-flow (ticket-55) diff --git a/src/site/setup_transport_ssh.mkd b/src/site/setup_transport_ssh.mkd index 0f359105..c18dac46 100644 --- a/src/site/setup_transport_ssh.mkd +++ b/src/site/setup_transport_ssh.mkd @@ -23,14 +23,22 @@ First you'll need to create an SSH key pair, if you don't already have one or if ssh-keygen +**NOTE:** It is important to note that *ssh-keygen* generates a public/private keypair (e.g. id_rsa and id_rsa.pub). You want to upload the *public* key, which is denoted by the *.pub* file extension. + +#### Uploading your public key from the command-line + Then you can upload your *public* key right from the command-line. cat ~/.ssh/id_rsa.pub | ssh -l -p 29418 keys add cat c:\\.ssh\id_rsa.pub | ssh -l -p 29418 keys add -**NOTE:** It is important to note that *ssh-keygen* generates a public/private keypair (e.g. id_rsa and id_rsa.pub). You want to upload the *public* key, which is denoted by the *.pub* file extension. +#### Uploading your public key through the browser + +1. Navigate to your *profile* page from the dropdown user menu. +2. Click the *SSH Keys* tab and paste your public key into the *Add SSH Key* form. +3. Click the *Save* button -Once you've done both of those steps you should be able to execute the following command without a password prompt. +Once you ave uploaded your public key you should be able to execute the following command without a password prompt. ssh -l -p 29418 diff --git a/src/site/siteindex.mkd b/src/site/siteindex.mkd index cc8dc2fa..58e18af1 100644 --- a/src/site/siteindex.mkd +++ b/src/site/siteindex.mkd @@ -1,4 +1,14 @@
    +
    Current Release ${project.releaseVersion} (${project.releaseDate})
    release notes @@ -7,7 +17,7 @@
    - +
    @@ -46,11 +56,19 @@ Gitblit can be used as a dumb repository viewer with no administrative controls Gitblit can be used as a complete Git stack for cloning, pushing, and repository access control. Gitblit can be used without any other Git tooling (including actual Git) or it can cooperate with your established tools. +### All Transports + +The SSH, HTTP, & GIT protocols are supported and ready-to-go out of the box. + +### Issue tracking with branch-based pull requests + +Gitblit blends elements of GitHub, BitBucket, and Gerrit to provide a streamlined collaboration workflow based on branches within the primary repository. + ### Easy Remote Management Administrators can create and manage all repositories, user accounts, and teams from the *Web UI*. Administrators can create and manage all repositories, user accounts, and teams from the *JSON RPC interface* using the [Gitblit Manager](http://code.google.com/p/gitblit/downloads/detail?name=%MANAGER%) or your own custom tooling. -Administrators can create and manage all repositories, user accounts, and teams from the *command-line* using the [Powertools plugin](https://github.com/gitblit/gitblit-powertools-plugin). +Administrators can create and manage all repositories, user accounts, and teams from the *command-line* using SSH & the [Powertools plugin](https://github.com/gitblit/gitblit-powertools-plugin). ### Integration with Your Infrastructure diff --git a/src/site/tickets_replication.mkd b/src/site/tickets_replication.mkd index a72df27f..60f12cf6 100644 --- a/src/site/tickets_replication.mkd +++ b/src/site/tickets_replication.mkd @@ -145,9 +145,9 @@ For example, this would migrate tickets from the current ticket service configur migrate-tickets com.gitblit.tickets.RedisTicketService c:\gitblit-data -##### Gitblit WAR/Express +##### Gitblit WAR -Gitblit WAR/Express does not ship with anything other than the WAR, but you can still migrate tickets offline with a little extra effort. +Gitblit WAR does not ship with anything other than the WAR, but you can still migrate tickets offline with a little extra effort. *Windows* diff --git a/src/site/tickets_setup.mkd b/src/site/tickets_setup.mkd index aeecbeb1..f70d75cd 100644 --- a/src/site/tickets_setup.mkd +++ b/src/site/tickets_setup.mkd @@ -109,7 +109,7 @@ Gitblit has a simple review scoring mechanism designed to indicate overall impre #### Milestones -Milestones are a way to group tickets together. Currently milestones are specified at the repository level and are stored in the repository git config file. Gitblit's internal architecture has all the methods necessary to maintain milestones, but this functionality is not yet exposed through the web ui. For now you will have to control milestones manually with a text editor. +Milestones are a way to group tickets together. Milestones are specified for each repository and are stored in the repository git config file. Repository owners may create milestones through the web ui in the *Tickets* page on the *Milestones* tab. [milestone "v1.5.0"] status = Open -- cgit v1.2.3 From e29b6e3f7f3831c6063ca67082964b7c50b7ab50 Mon Sep 17 00:00:00 2001 From: Stardrad Yin Date: Tue, 10 Jun 2014 21:45:48 +0800 Subject: Chinese translation for release-v1.6.0(d2d5fc) at 2014_06_10. --- .../gitblit/wicket/GitBlitWebApp_zh_CN.properties | 74 +++++++++++++++++++++- .../wicket/pages/EmptyRepositoryPage_zh_CN.html | 6 +- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_CN.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_CN.properties index 5976614b..b5e4f658 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_CN.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_zh_CN.properties @@ -669,4 +669,76 @@ gb.repositoryIsFrozen = \u5f53\u524d\u7248\u672c\u5e93\u5df2\u88ab\u51bb\u7ed3\u gb.repositoryDoesNotAcceptPatchsets = \u5f53\u524d\u7248\u672c\u5e93\u4e0d\u5141\u8bb8\u8865\u4e01\u96c6\u3002 gb.serverDoesNotAcceptPatchsets = \u5f53\u524d\u670d\u52a1\u5668\u4e0d\u5141\u8bb8\u8865\u4e01\u96c6\u3002 gb.ticketIsClosed = \u5f53\u524d\u5de5\u5355\u5df2\u5173\u95ed\u3002 -gb.mergeToDescription = \u5408\u5e76\u5de5\u5355\u8865\u4e01\u96c6\u7684\u9ed8\u8ba4\u96c6\u6210\u5206\u652f \ No newline at end of file +gb.mergeToDescription = \u5408\u5e76\u5de5\u5355\u8865\u4e01\u96c6\u7684\u9ed8\u8ba4\u96c6\u6210\u5206\u652f +gb.anonymousCanNotPropose = \u7981\u6b62\u533f\u540d\u7528\u6237\u63d0\u4ea4\u8865\u4e01\u96c6\u3002 +gb.youDoNotHaveClonePermission = \u60a8\u6ca1\u6709\u6743\u9650\u514b\u9686\u5f53\u524d\u7248\u672c\u5e93\u3002 +gb.myTickets = \u6211\u7684\u5de5\u5355 +gb.yourAssignedTickets = \u8d23\u4efb\u5de5\u5355 +gb.newMilestone = \u65b0\u5efa milestone +gb.editMilestone = \u7f16\u8f91 milestone +gb.deleteMilestone = \u5220\u9664 milestone \\"{0}\\"? +gb.milestoneDeleteFailed = \u5220\u9664 milestone ''{0}'' \u5931\u8d25! +gb.notifyChangedOpenTickets = \u5bf9\u53d1\u751f\u53d8\u52a8\u7684\u5df2\u5f00\u542f\u5de5\u5355\u53d1\u9001\u901a\u77e5 +gb.overdue = \u8fc7\u671f +gb.openMilestones = \u5df2\u5f00\u542f milestones +gb.closedMilestones = \u5df2\u5173\u95ed milestones +gb.administration = \u7ba1\u7406 +gb.plugins = \u63d2\u4ef6 +gb.extensions = \u6269\u5c55 +gb.pleaseSelectProject = \u8bf7\u9009\u62e9\u9879\u76ee! +gb.accessPolicy = \u8bbf\u95ee\u7b56\u7565 +gb.accessPolicyDescription = \u8bf7\u9009\u62e9\u4e00\u4e2a\u63a7\u5236\u7248\u672c\u5e93\u53ef\u89c1\u6027\u4ee5\u53caGit\u8bbf\u95ee\u6743\u9650\u7684\u8bbf\u95ee\u7b56\u7565\u3002 +gb.anonymousPolicy = \u533f\u540d\u67e5\u770b, \u514b\u9686\u548c\u63a8\u9001 +gb.anonymousPolicyDescription = \u4efb\u4f55\u4eba\u90fd\u53ef\u4ee5\u67e5\u770b\uff0c\u514b\u9686\u4ee5\u53ca\u63a8\u9001\u81f3\u6b64\u7248\u672c\u5e93\u3002 +gb.authenticatedPushPolicy = \u9650\u5236\u63a8\u9001 (\u6388\u6743\u8bbf\u95ee) +gb.authenticatedPushPolicyDescription = \u4efb\u4f55\u4eba\u90fd\u53ef\u4ee5\u67e5\u770b\u4ee5\u53ca\u514b\u9686\u6b64\u7248\u672c\u5e93\u3002\u4efb\u4f55\u5df2\u6388\u6743\u7528\u6237\u62e5\u6709RW+\u63a8\u9001\u6743\u9650\u3002 +gb.namedPushPolicy = \u9650\u5236\u63a8\u9001 (\u6307\u5b9a\u7528\u6237) +gb.namedPushPolicyDescription = \u4efb\u4f55\u4eba\u90fd\u53ef\u4ee5\u67e5\u770b\u4ee5\u53ca\u514b\u9686\u6b64\u7248\u672c\u5e93\u3002 \u60a8\u53ef\u4ee5\u9009\u62e9\u62e5\u6709\u63a8\u9001\u6743\u9650\u7684\u7528\u6237\u3002 +gb.clonePolicy = \u9650\u5236\u514b\u9686\uff0c\u63a8\u9001 +gb.clonePolicyDescription = \u4efb\u4f55\u4eba\u90fd\u53ef\u4ee5\u770b\u5230\u6b64\u7248\u672c\u5e93\u3002\u60a8\u53ef\u4ee5\u9009\u62e9\u62e5\u6709\u514b\u9686\u548c\u63a8\u9001\u6743\u9650\u7684\u7528\u6237\u3002 +gb.viewPolicy = \u9650\u5236\u67e5\u770b\uff0c\u514b\u9686\u548c\u63a8\u9001 +gb.viewPolicyDescription = \u60a8\u53ef\u4ee5\u9009\u62e9\u62e5\u6709\u67e5\u770b\uff0c\u514b\u9686\u548c\u63a8\u9001\u6743\u9650\u7684\u7528\u6237\u3002 +gb.initialCommit = \u521d\u59cb\u5316\u63d0\u4ea4 +gb.initialCommitDescription = \u6b64\u529f\u80fd\u76f8\u5f53\u4e8e\u76f4\u63a5\u5bf9\u5f53\u524d\u7248\u672c\u5e93\u8fdb\u884c git clone \u3002 \u5982\u679c\u8df3\u8fc7\u6b64\u6b65\uff0c\u60a8\u5fc5\u987b\u5728\u672c\u5730\u8fdb\u884c git init \u3002 +gb.initWithReadme = \u52a0\u5165 README +gb.initWithReadmeDescription = \u6b64\u529f\u80fd\u4f1a\u81ea\u52a8\u751f\u6210\u4e00\u4e2a\u60a8\u7684\u7248\u672c\u5e93\u7684 README \u6587\u4ef6\u3002 +gb.initWithGitignore = \u52a0\u5165 .gitignore \u6587\u4ef6 +gb.initWithGitignoreDescription = \u6b64\u529f\u80fd\u4f1a\u751f\u6210\u4e00\u4e2a\u914d\u7f6e\u6587\u4ef6\uff0c\u65e8\u5728\u63d0\u793a Git \u5ba2\u6237\u7aef\u5ffd\u7565\u5bf9\u5e94\u7684\u6587\u4ef6\u6216\u6587\u4ef6\u5939\u3002 +gb.pleaseSelectGitIgnore = \u8bf7\u9009\u62e9\u4e00\u4e2a .gitignore \u6587\u4ef6 +gb.receive = receive +gb.permissions = permissions +gb.ownersDescription = \u7248\u672c\u5e93\u62e5\u6709\u8005\u62e5\u6709\u7248\u672c\u5e93\u7684\u6240\u6709\u7ba1\u7406\u6743\u9650\uff0c\u4f46\u662f\u53ea\u5141\u8bb8\u4fee\u6539\u79c1\u6709\u7248\u672c\u5e93\u7684\u540d\u79f0\u3002 +gb.userPermissionsDescription = \u60a8\u53ef\u4ee5\u8bbe\u7f6e\u79c1\u6709\u7528\u6237\u6743\u9650\u3002 \u6b64\u8bbe\u7f6e\u4f1a\u8986\u76d6\u56e2\u961f\u6743\u9650\u4ee5\u53caregex\u6743\u9650\u3002 +gb.teamPermissionsDescription = \u60a8\u53ef\u4ee5\u8bbe\u7f6e\u79c1\u6709\u56e2\u961f\u6743\u9650\u3002 \u6b64\u8bbe\u7f6e\u4f1a\u8986\u76d6regex\u6743\u9650\u3002 +gb.ticketSettings = \u5de5\u5355\u8bbe\u7f6e +gb.receiveSettings = Receive \u8bbe\u7f6e +gb.receiveSettingsDescription = Receive\u8bbe\u7f6e\u8bbe\u5b9a\u63a8\u9001\u81f3\u7248\u672c\u5e93\u65f6\u7684\u884c\u4e3a\u3002 +gb.preReceiveDescription = Pre-receive hooks \u4f1a\u5728\u63a8\u9001\u63a5\u6536\u540e\uff0c refs \u66f4\u65b0\u4e4b\u524d\u6267\u884c\u3002

    \u8fd9\u79cdhook\u662f\u8fdb\u884c\u63a8\u9001\u62d2\u7edd\u7684\u597d\u5de5\u5177\u3002

    +gb.postReceiveDescription = Post-receive hooks \u4f1a\u5728\u63a8\u9001\u63a5\u6536\u540e\uff0c refs \u66f4\u65b0\u4e4b\u540e\u6267\u884c\u3002

    \u8fd9\u79cdhook\u662f\u8fdb\u884c\u901a\u77e5\uff0c\u4f7f\u7528\u6784\u5efa\u89e6\u53d1\u5668\u7b49\u7684\u597d\u5de5\u5177\u3002

    +gb.federationStrategyDescription = \u8bbe\u7f6e\u662f\u5426\u4ee5\u53ca\u5982\u4f55\u5c06\u5f53\u524d\u7248\u672c\u5e93\u4e0e\u5176\u4ed6Gitblit\u8fdb\u884cfederate\u3002 +gb.federationSetsDescription = \u5f53\u524d\u7248\u672c\u5e93\u5c06\u4f1a\u88ab\u5305\u542b\u8fdb\u9009\u5b9a\u7684federation\u96c6\u4e2d\u3002 +gb.miscellaneous = miscellaneous +gb.originDescription = \u5f53\u524d\u7248\u672c\u5e93\u7684\u514b\u9686\u6e90\u5730\u5740\u3002 +gb.gc = GC +gb.garbageCollection = \u5783\u573e\u6536\u96c6 +gb.garbageCollectionDescription = \u5783\u573e\u6536\u96c6\u5668\u4f1a\u5c06\u5ba2\u6237\u7aef\u6240\u53d1\u9001\u7684\u677e\u6563\u6587\u4ef6\u6253\u5305\u5e76\u5220\u9664\u5f53\u524d\u7248\u672c\u5e93\u4e2d\u672a\u88ab\u5f15\u7528\u7684\u5bf9\u8c61\u3002 +gb.commitMessageRendererDescription = \u53ef\u4ee5\u5c06\u63d0\u4ea4\u4fe1\u606f\u663e\u793a\u4e3a\u7eaf\u6587\u672c\u6216\u8005\u5df2\u6392\u7248\u7684Markup\u6587\u672c +gb.preferences = \u504f\u597d +gb.accountPreferences = \u7528\u6237\u504f\u597d +gb.accountPreferencesDescription = \u8bbe\u7f6e\u60a8\u7684\u7528\u6237\u504f\u597d +gb.languagePreference = \u8bed\u8a00\u504f\u597d +gb.languagePreferenceDescription = \u9009\u62e9\u60a8\u559c\u6b22\u7684Gitblit\u7ffb\u8bd1 +gb.emailMeOnMyTicketChanges = \u5728\u6211\u7684\u5de5\u5355\u53d1\u751f\u53d8\u5316\u540e\u90ae\u4ef6\u901a\u77e5\u6211 +gb.emailMeOnMyTicketChangesDescription = \u5bf9\u6211\u5728\u5de5\u5355\u4e2d\u4f5c\u51fa\u7684\u4fee\u6539\u53d1\u9001\u90ae\u4ef6\u901a\u77e5\u3002 +gb.displayNameDescription = \u9009\u62e9\u663e\u793a\u540d\u79f0 +gb.emailAddressDescription = \u63a5\u6536\u901a\u77e5\u7684\u4e3b\u8981\u90ae\u7bb1\u5730\u5740 +gb.sshKeys = SSH Keys +gb.sshKeysDescription = SSH \u516c\u7ea6\u8ba4\u8bc1\u662f\u4e00\u79cd\u4e0d\u540c\u4e8e\u5bc6\u7801\u8ba4\u8bc1\u7684\u5b89\u5168\u8ba4\u8bc1\u65b9\u6cd5\u3002 +gb.addSshKey = \u6dfb\u52a0 SSH Key +gb.key = Key +gb.comment = \u53d1\u8868 +gb.sshKeyCommentDescription = \u8f93\u5165\u8bc4\u8bba\uff08\u53ef\u4e3a\u7a7a\uff09. \u5982\u679c\u4e3a\u7a7a\uff0c \u8bc4\u8bba\u5185\u5bb9\u5c06\u4f1a\u4ece\u4e3b\u8981\u6570\u636e\u4e2d\u63d0\u53d6\u3002 +gb.permission = \u6743\u9650 +gb.sshKeyPermissionDescription = \u8bbe\u7f6eSSH key\u7684\u8bbf\u95ee\u6743\u9650 +gb.transportPreference = Transport \u504f\u597d +gb.transportPreferenceDescription = \u9009\u62e9\u60a8\u7528\u6765\u514b\u9686\u7684 Transport \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_zh_CN.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_zh_CN.html index 1acf4f82..72ce051e 100644 --- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_zh_CN.html +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_zh_CN.html @@ -20,11 +20,11 @@ 当你推é€å®Œæ¯•åŽä½ å¯ä»¥ 刷新 此页é¢é‡æ–°æŸ¥çœ‹æ‚¨çš„版本库。 -

    Create a new repository on the command-line

    +

    通过命令行创建一个新的版本库

    
     
    -	

    Push an existing repository from the command-line

    +

    通过命令行推é€ä¸€ä¸ªå·²å­˜åœ¨çš„版本库

    
     
    @@ -46,7 +46,7 @@
     		

    商业/é—­æº Git 客户端

    - + -- cgit v1.2.3 From 52ae7c2a89cfa6db9096eed76a484c820a612fcc Mon Sep 17 00:00:00 2001 From: James Moger Date: Tue, 10 Jun 2014 22:30:57 -0400 Subject: Documentation --- HOME.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/HOME.md b/HOME.md index 6d19d0d2..7c5449d3 100644 --- a/HOME.md +++ b/HOME.md @@ -18,11 +18,6 @@ This documentation is the source content from which the [Gitblit website](http:/ [[src/site/setup_war.mkd]] [[src/site/upgrade_war.mkd]] -### Gitblit Express for OpenShift - -[[src/site/setup_express.mkd]] -[[src/site/upgrade_express.mkd]] - ### General Configuration & Administration [[src/site/setup_authentication.mkd]] -- cgit v1.2.3 From c132e7313580e536ca32c4a626f8384624235f89 Mon Sep 17 00:00:00 2001 From: Leif Jantzen Date: Wed, 11 Jun 2014 10:04:48 +0200 Subject: Updated norwegian translation --- .../com/gitblit/wicket/GitBlitWebApp_no.properties | 73 ++++++++++++++++++++++ .../wicket/pages/EmptyRepositoryPage_no.html | 60 ++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_no.html diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties index 67920768..efc13a1e 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_no.properties @@ -100,6 +100,9 @@ gb.blob = blob gb.commitActivityTrend = aktivitetstrend for commits gb.commitActivityDOW = commit aktivitet gruppert p\u00e5 ukedag gb.commitActivityAuthors = prim\u00e6rforfattere etter aktivitet +gb.feed = feed +gb.cancel = avbryt +gb.changePassword = endre passord gb.isFederated = er federert gb.federateThis = federer dette repositoriet gb.federateOrigin = federere origin @@ -669,3 +672,73 @@ gb.ticketIsClosed = Denne ticketen er lukket gb.mergeToDescription = standard integration branch for merging av ticket patchsett gb.anonymousCanNotPropose = Anonyme brukere kan ikke foresl\u00e5 patchsett gb.youDoNotHaveClonePermission = Du har ikke tillatelse til \u00e5 klone dette repositoriet. +gb.myTickets = mine tickets +gb.yourAssignedTickets = tilordnet deg +gb.newMilestone = ny milep\u00e6l +gb.editMilestone = endre milep\u00e6l +gb.deleteMilestone = Slette milep\u00e6l \"{0}\"? +gb.milestoneDeleteFailed = Greide ikke å slette milep\u00e6l ''{0}''! +gb.notifyChangedOpenTickets = send meldin om endrede \u00e5pne tickets +gb.overdue = forfalt +gb.openMilestones = \u00e5pne milep\u00e6ler +gb.closedMilestones = lukkede milep\u00e6ler +gb.administration = administrasjon +gb.plugins = plugins +gb.extensions = extensions +gb.pleaseSelectProject = Vennligst velg prosjekt! +gb.accessPolicy = Tilgangspolicy +gb.accessPolicyDescription = Velg en tilgangspolicy for å kontrollere synlighet og tilganger. +gb.anonymousPolicy = Anonym view, clone og push +gb.anonymousPolicyDescription = Alle kan se, clone ofg pushe til dette repositoriet. +gb.authenticatedPushPolicy = Begrens push (Autentisert) +gb.authenticatedPushPolicyDescription = Alle kan se og klone dette repositoriet. Alle autentiserte brukere har lese og skrivetilgang. +gb.namedPushPolicy = Begrens push (navngitt) +gb.namedPushPolicyDescription = Alle kan se og klone repositoriet. Du bestemmer hvem som kan pushe. +gb.clonePolicy = Begrens Clone og Push +gb.clonePolicyDescription = Alle kan se dette repositoriet. Du bestemmer hvem som kan clone og pushe. +gb.viewPolicy = Begrense View, Clone og Push +gb.viewPolicyDescription = Du bestemmer hvem som kan se, clone og pushe til dette repositoriet. +gb.initialCommit = F\u00F8rste commit +gb.initialCommitDescription = Dette vil la deg kunne git clone repositoriet med en gang. Hopp over dette skrittet hvis du allerede har kj\u0F8rt if git init lokalt. +gb.initWithReadme = Inkluder en README +gb.initWithReadmeDescription = Dette vil generere en enkel README-fil i ditt repository. +gb.initWithGitignore = Inkluder en .gitignore fil +gb.initWithGitignoreDescription = Dette vil inkludere en konfigurasjonsfil som instruerer git-klienter til å ignorerer filer og kataloger som matcher definerte m\u00F8nstre. +gb.pleaseSelectGitIgnore = Vennligst velg en .gitignore fil +gb.receive = motta +gb.permissions = rettigheter +gb.ownersDescription = Eiere kan administrere alle repositoriets innstillinger men de kan ikke endre p\u00e5 repositoriets navn med mindre det er deres eget repository. +gb.userPermissionsDescription = Du kan spesifisere individuelle brukerrettigheter. Disse innstillingene overstyrer team- eller regul\u00e6ruttrykk-baserte rettigheter. +gb.teamPermissionsDescription = Du kan spesifisere individuelle team-rettigheter. Disse innstillingene overstyrer regul\u00e6ruttrykk-baserte rettigheter.. +gb.ticketSettings = Ticket innstillinger +gb.receiveSettings = Innstillinger for mottak av push +gb.receiveSettingsDescription = Kontrollerer pushing til repositoriet. +gb.preReceiveDescription = Pre-receive hooks blir utf\u00F8rt etter en committ er mottatt men F\u00D8 refs har blitt oppdatert.

    Dette er det passende stedet \u00e5 avvise en push.

    +gb.postReceiveDescription = Post-receive hooks blir utf\u00F8rt etter en committ er mottatt og ETTER refs har blitt oppdatert.

    Dette er det passende stedet for notifikasjoner, build triggers osv.

    +gb.federationStrategyDescription = Kontroller om og hvordan dette repositoriet skal federeres med en annen Gitblit instans. +gb.federationSetsDescription = Dette repositoriet vil bli inkludert i de valgte federeringssettene. +gb.miscellaneous = ymse +gb.originDescription = URL'en som dette repositoriet ble klonet fra. +gb.gc = GC +gb.garbageCollection = Garbage Collection +gb.garbageCollectionDescription = Garbage collectoren vil pakke sammen l\u00F8se objekter pushet fra klientene og fjerne objekter det ikke refereres til fra minnet. +gb.commitMessageRendererDescription = Commit-meldinger kan vises som ren tekst, eller som markup. +gb.preferences = innstillinger +gb.accountPreferences = Kontoinnstillinger +gb.accountPreferencesDescription = Velg dine kontoinnstillinger +gb.languagePreference = Foretrukket spr\u00e5k +gb.languagePreferenceDescription = Velg ditt foretrukne spr\u00e5k for Gitblit +gb.emailMeOnMyTicketChanges = Send meg en epost når ticketen min endrer seg +gb.emailMeOnMyTicketChangesDescription = Send meg en epost for endringer jeg gjør på en ticket. +gb.displayNameDescription = Foretrukket visningsnavn +gb.emailAddressDescription = Prim\u00e6r epostadresse for notifikasjoner +gb.sshKeys = SSH n\u00F8kler +gb.sshKeysDescription = SSH public key autentisering er et sikkert alternativ til autentisering med passord +gb.addSshKey = Legg til SSH n\u00F8kkel +gb.key = N\u00F8kkel +gb.comment = Kommentar +gb.sshKeyCommentDescription = Angi en valgfri kommentar. Kommentaren vil bli ekstrahert fra n\u00F8kkeldataene hvis blank +gb.permission = Tilgang +gb.sshKeyPermissionDescription = Angi tilgangsrettinghet for SSH n\u00F8kkelen +gb.transportPreference = Foretrukket transport +gb.transportPreferenceDescription = Sett transportmetoden du foretrekker for cloning \ No newline at end of file diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_no.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_no.html new file mode 100644 index 00000000..273e15f9 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_no.html @@ -0,0 +1,60 @@ + + + + + +
    +
    +
    +
    +

    Tomt Repository

    +
    + [repository] er et tomt repository som ikke kan vises av Gitblit. +

    + Vennligst push noen endringer inn til +
    + Etter at du har pushet noen endringer, kan du oppfriske denne siden for \u00e5 se repositoriet. +
    + +

    Opprett et nytt repository fra kommandolinjen

    + +
    
    +
    +	

    Push et eksisternde repository fra kommandolinjen

    + +
    
    +
    +	
    +

    L\u00e6r Git

    +

    Hvis du er usikker p\u00e5 hvordan du kan benytte denne informasjonen, vurder \u00e5 lese Git Community Book eller Pro Git for \u00e5 f\u00e5 en bedre forst\u00e5else av hvordan du kan bruke Git.

    + +

    Open Source Git Clients

    +
    SmartGit/HgJava ç‰ˆæœ¬çš„æ”¯æŒ Git, Mercurial å’Œ SVN 客户端应用 (需è¦å®˜æ–¹, 命令行 Git 的支æŒ)
    SmartGit/HgJava ç‰ˆæœ¬çš„æ”¯æŒ Git, Mercurial å’Œ SVN 客户端应用
    SourceTreeå…费的 Mac Git Mercurial ä»¥åŠ SVN 客户端 and Mercurial
    TowerMac OS X Git 客户端
    + + + + + + + +
    a href="http://git-scm.com">Git - den offisielle, kommando-linje git
    a href="http://tortoisegit.googlecode.com">TortoiseGit - Windows filutforsker integrasjon (krever den offisielle kommando-linje git versjonen installert
    Eclipse/EGit - Git for Eclipse IDE (basert p\u00e5 JGit, akkurat som Gitblit er)
    Git Extensions - En C# frontend for Git som integrerer med filutforskeren og Visual Studio.
    GitX-dev - En git klient for OS X
    + +

    Commercial/Closed-Source Git Clients

    + + + + + + +
    SmartGit/Hg - En Git og Mercurial klient for Windows, Mac, og Linux
    SourceTree - En gratis Git og Mercurial klient for Windows og Mac
    a href="http://www.git-tower.com/">Tower - En git klient for Mac OS X
    +
    +
    +
    +
    +
    +
    + + -- cgit v1.2.3 From 845271c3c738f1b3b2aab5d3ad4c657adda3b960 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 12 Jun 2014 18:56:38 -0400 Subject: Documentation --- releases.moxie | 1 + 1 file changed, 1 insertion(+) diff --git a/releases.moxie b/releases.moxie index ce754209..c473d4fc 100644 --- a/releases.moxie +++ b/releases.moxie @@ -37,6 +37,7 @@ r24: { - Fixed SSH daemon thread exhaustion (ticket-89) - Fixed Ticket responsible selections not considering the AUTHENTICATED authorization control (ticket-91) - Fixed invalid generated SSH url for port 22 (issue-444, ticket-98) + - Fix cloning repositories with `+` in their names. (revert pr-136, issue-362, ticket-100) changes: - Split the pages servlet into a raw servlet and a pages servlet. All raw links now use the raw servlet (issue-413, ticket-49) - Drop deprecated --set-upstream syntax for -u (ticket-59) -- cgit v1.2.3 From 9793855caf01d4ce9740dd99971e771cca6715a6 Mon Sep 17 00:00:00 2001 From: James Moger Date: Fri, 13 Jun 2014 08:22:27 -0400 Subject: Fix NPE in GitblitClient --- releases.moxie | 1 + src/main/java/com/gitblit/client/GitblitClient.java | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/releases.moxie b/releases.moxie index c473d4fc..7314160d 100644 --- a/releases.moxie +++ b/releases.moxie @@ -38,6 +38,7 @@ r24: { - Fixed Ticket responsible selections not considering the AUTHENTICATED authorization control (ticket-91) - Fixed invalid generated SSH url for port 22 (issue-444, ticket-98) - Fix cloning repositories with `+` in their names. (revert pr-136, issue-362, ticket-100) + - Fixed NPE in GitblitClient (ticket-102) changes: - Split the pages servlet into a raw servlet and a pages servlet. All raw links now use the raw servlet (issue-413, ticket-49) - Drop deprecated --set-upstream syntax for -u (ticket-59) diff --git a/src/main/java/com/gitblit/client/GitblitClient.java b/src/main/java/com/gitblit/client/GitblitClient.java index 66625a8e..f5bba1ad 100644 --- a/src/main/java/com/gitblit/client/GitblitClient.java +++ b/src/main/java/com/gitblit/client/GitblitClient.java @@ -253,9 +253,11 @@ public class GitblitClient implements Serializable { // create list of available scripts by excluding inherited scripts List scripts = new ArrayList(); - for (String script : settings.pushScripts) { - if (!inherited.contains(script)) { - scripts.add(script); + if (!ArrayUtils.isEmpty(settings.pushScripts)) { + for (String script : settings.pushScripts) { + if (!inherited.contains(script)) { + scripts.add(script); + } } } return scripts; -- cgit v1.2.3 From 59509ab675deefe6ede2dbe16ca30b1b0547632a Mon Sep 17 00:00:00 2001 From: Carsten Lenz Date: Tue, 10 Jun 2014 14:36:02 +0200 Subject: Add german translation of GitBlitWebApp.properties --- .../com/gitblit/wicket/GitBlitWebApp_de.properties | 745 +++++++++++++++++++++ 1 file changed, 745 insertions(+) create mode 100644 src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties new file mode 100644 index 00000000..3ec330b7 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_de.properties @@ -0,0 +1,745 @@ +gb.repository = Repository +gb.owner = Besitzer +gb.description = Beschreibung +gb.lastChange = Letzte \u00c4nderung +gb.refs = Refs +gb.tag = Tag +gb.tags = Tags +gb.author = Autor +gb.committer = Committer +gb.commit = Commit +gb.age = Alter +gb.tree = Dateibaum +gb.parent = Parent +gb.url = URL +gb.history = Historie +gb.raw = Raw +gb.object = Object +gb.ticketId = Ticket Id +gb.ticketAssigned = Zugewiesen +gb.ticketOpenDate = Erstellt +gb.ticketStatus = Status +gb.ticketComments = Kommentare +gb.view = Ansicht +gb.local = Lokal +gb.remote = Remote +gb.branches = Branches +gb.patch = Patch +gb.diff = Diff +gb.log = Log +gb.moreLogs = Weitere Commits... +gb.allTags = Alle Tags... +gb.allBranches = Alle Branches... +gb.summary = \u00dcbersicht +gb.ticket = Ticket +gb.newRepository = Neues Repository +gb.newUser = Neuer Benutzer +gb.commitdiff = Commitdiff +gb.tickets = Tickets +gb.pageFirst = Anfang +gb.pagePrevious = Zur\u00fcck +gb.pageNext = Weiter +gb.head = HEAD +gb.blame = Blame +gb.login = Login +gb.logout = Logout +gb.username = Benutzername +gb.password = Passwort +gb.tagger = Tagger +gb.moreHistory = Mehr Historie... +gb.difftocurrent = Diff zu aktuellem Stand +gb.search = Suche +gb.searchForAuthor = Suche nach Commits von Autor +gb.searchForCommitter = Suche nach Commits von Committer +gb.addition = Neu +gb.modification = Modifikation +gb.deletion = L\u00f6schung +gb.rename = Umbenennung +gb.metrics = Metriken +gb.stats = Statistiken +gb.markdown = Markdown +gb.changedFiles = Ge\u00e4nderte Dateien +gb.filesAdded = {0} Dateien hinzugef\u00fcgt +gb.filesModified = {0} Dateien ge\u00e4ndert +gb.filesDeleted = {0} Dateien gel\u00f6scht +gb.filesCopied = {0} Dateien kopiert +gb.filesRenamed = {0} Dateien umbenannt +gb.missingUsername = Fehlender Benutzername +gb.edit = Bearbeiten +gb.searchTypeTooltip = Suchart ausw\u00e4hlen +gb.searchTooltip = Suche {0} +gb.delete = L\u00f6schen +gb.docs = Dokumentation +gb.accessRestriction = Zugriffsbeschr\u00e4nkung +gb.name = Name +gb.enableTickets = Tickets aktivieren +gb.enableDocs = Docs aktivieren +gb.save = Speichern +gb.showRemoteBranches = Zeige Remote Branches +gb.editUsers = Benutzer bearbeiten +gb.confirmPassword = Passwort best\u00e4tigen +gb.restrictedRepositories = Zugriffsbeschr\u00e4nkte Repositories +gb.canAdmin = Kann administrieren +gb.notRestricted = Anonymes Anzeigen, Klonen und Pushen +gb.pushRestricted = Authentifiziertes Pushen +gb.cloneRestricted = Authentifiziertes Klonen und Pushen +gb.viewRestricted = Authentifiziertes Anzeigen, Klonen und Pushen +gb.useTicketsDescription = Lesende Darstellung von Ticgit Issues +gb.useDocsDescription = Listet Markdown Dokumentation im Repository auf +gb.showRemoteBranchesDescription = Zeige Remote Branches +gb.canAdminDescription = Kann Gitblit Server administrieren +gb.permittedUsers = Zugelassene Benutzer +gb.isFrozen = ist eingefroren +gb.isFrozenDescription = Verbiete Push +gb.zip = Zip +gb.showReadme = Zeige Readme +gb.showReadmeDescription = Zeigt eine \"Readme\" Markdown Datei auf der Zusammenfassungsseite +gb.nameDescription = Verwenden Sie '/' um Repositories zu gruppieren. Z.B. libraries/mycoollib.git +gb.ownerDescription = Der Besitzer kann Repository-Einstellungen \u00e4ndern +gb.blob = Blob +gb.commitActivityTrend = Commit-Aktivit\u00e4tstrend +gb.commitActivityDOW = Commit-Aktivit\u00e4t nach Wochentag +gb.commitActivityAuthors = Prim\u00e4re Autoren nach Commit-Aktivit\u00e4t +gb.feed = Feed +gb.cancel = Abbrechen +gb.changePassword = Passwort \u00e4ndern +gb.isFederated = ist verbunden +gb.federateThis = Dieses Repository verbinden (Federation) +gb.federateOrigin = Ursprung (origin) verbinden (Federation) +gb.excludeFromFederation = Von Verbindung ausschlie\u00dfen (Federation) +gb.excludeFromFederationDescription = Verbiete verbundenen Gitblit Instanzen, von diesem Konto zu pullen (Federation) +gb.tokens = Federation Tokens +gb.tokenAllDescription = Alle Repositories, Benutzer und Einstellungen +gb.tokenUnrDescription = Alle Repositories und Benutzer +gb.tokenJurDescription = Alle Repositories +gb.federatedRepositoryDefinitions = Repositorydefinitionen +gb.federatedUserDefinitions = Benutzerdefinitionen +gb.federatedSettingDefinitions = Einstellungsdefinitionen +gb.proposals = Verbindungsanfrage (Federation) +gb.received = empfangen +gb.type = Typ +gb.token = Token +gb.repositories = Repositories +gb.proposal = Anfrage +gb.frequency = Frequenz +gb.folder = Ordner +gb.lastPull = Letzter Pull +gb.nextPull = N\u00e4chster Pull +gb.inclusions = Inclusions +gb.exclusions = Exclusions +gb.registration = Registrierungen +gb.registrations = Verbindungsregistrierungen +gb.sendProposal = Vorschlagen +gb.status = Status +gb.origin = Ursprung +gb.headRef = Default Branch (HEAD) +gb.headRefDescription = Der Default Branch, welcher gecloned und auf der Zusammenfassungsseite dargestellt wird +gb.federationStrategy = Verbindungsstrategie +gb.federationRegistration = Verbindungsregistrierung +gb.federationResults = Verbindungs-Pull-Ergebnis +gb.federationSets = federation sets +gb.message = Nachricht +gb.myUrlDescription = Die \u00f6ffentlich zugreifbare URL f\u00fcr Ihre Gitblit-Instanz +gb.destinationUrl = Senden an +gb.destinationUrlDescription = Die URL der Gitblit-Instanz, an welche die Anfrage gestellt werden soll +gb.users = Benutzer +gb.federation = Verbindungen (Federation) +gb.error = Fehler +gb.refresh = Aktualisieren +gb.browse = Durchsuchen +gb.clone = Clonen +gb.filter = Filter +gb.create = Erstellen +gb.servers = Server +gb.recent = K\u00fcrzlich +gb.available = Verf\u00fcgbar +gb.selected = Ausgew\u00e4hlt +gb.size = Gr\u00f6\u00dfe +gb.downloading = Wird heruntergeladen +gb.loading = Wird geladen +gb.starting = Wird gestartet +gb.general = Allgemein +gb.settings = Einstellungen +gb.manage = Verwalten +gb.lastLogin = Letzter Login +gb.skipSizeCalculation = \u00dcberspringe Gr\u00f6\u00dfenberechnung +gb.skipSizeCalculationDescription = Nicht die Gr\u00f6\u00dfe des Repositories berechnen (reduziert die Seitenladezeit) +gb.skipSummaryMetrics = \u00dcberspringe zusammenfassende Metriken +gb.skipSummaryMetricsDescription = Nicht die Metriken auf der Zusammenfassungsseite berechnen (reduziert die Seitenladezeit) +gb.accessLevel = Zugangsebene +gb.default = Default +gb.setDefault = Setze Default +gb.since = seit +gb.status = Status +gb.bootDate = Boot-Zeitpunkt +gb.servletContainer = Servlet container +gb.heapMaximum = Maximaler Heap +gb.heapAllocated = Allokierter Heap +gb.heapUsed = Verwendeter Heap +gb.free = Verf\u00fcgbar +gb.version = Version +gb.releaseDate = Releasedatum +gb.date = Datum +gb.activity = Aktivit\u00e4t +gb.subscribe = Subscribe +gb.branch = Branch +gb.maxHits = Max Hits +gb.recentActivity = K\u00fcrzliche Aktivit\u00e4t +gb.recentActivityStats = In den letzten {0} Tagen / {1} Commit(s) von {2} Autor(en) +gb.recentActivityNone = In den letzten {0} Tagen / Keine +gb.dailyActivity = T\u00e4gliche Aktivit\u00e4t +gb.activeRepositories = Aktive Repositories +gb.activeAuthors = Aktive Autoren +gb.commits = Commits +gb.teams = Teams +gb.teamName = Teamname +gb.teamMembers = Teammitglieder +gb.teamMemberships = Teammitgliedschaften +gb.newTeam = Neues Team +gb.permittedTeams = Zugelassene Teams +gb.emptyRepository = Leeres Repository +gb.repositoryUrl = Repository URL +gb.mailingLists = Mailinglisten +gb.preReceiveScripts = Pre-Receive Skripte +gb.postReceiveScripts = Post-Receive Skripte +gb.hookScripts = Hook Skripte +gb.customFields = Benutzerdefinierte Felder +gb.customFieldsDescription = Benutzerdefinierte Felder, die in Groovy Hooks zur Verf\u00fcgung stehen +gb.accessPermissions = Zugriffsberechtigungen +gb.filters = Filter +gb.generalDescription = Allgemeine Einstellungen +gb.accessPermissionsDescription = Zugriffseinschr\u00e4nkungen nach Benutzern und Teams +gb.accessPermissionsForUserDescription = Erstellen Sie Teammitgliedschaften oder gew\u00e4hren Sie Zugriff auf einzelnen Repositories +gb.accessPermissionsForTeamDescription = Weisen Sie Team Mitglieder zu oder gew\u00e4hren Sie Zugriff auf einzelne Repositories +gb.federationRepositoryDescription = Verbinden Sie dieses Repository mit anderen Gitblit Instanzen (Federation) +gb.hookScriptsDescription = Groovy Skripte beim Pushen auf diese Gitblit Instanz ausf\u00fchren +gb.reset = Reset +gb.pages = Seiten +gb.workingCopy = Arbeitskopie +gb.workingCopyWarning = Dieses Repository besitzt eine Arbeitskopie und kann keine Pushes empfangen +gb.query = Abfrage +gb.queryHelp = Standard Abfragesyntax wird unterst\u00fctzt.

    Unter Lucene Query Parser Syntax finden Sie weitere Details. +gb.queryResults = Ergebnisse {0} - {1} ({2} Treffer) +gb.noHits = Keine Treffer +gb.authored = ist Autor von +gb.committed = ist Comitter von +gb.indexedBranches = Indizierte Branches +gb.indexedBranchesDescription = W\u00e4hlen Sie die zu indizierenden Branches aus. +gb.noIndexedRepositoriesWarning = Keines Ihrer Repositories ist f\u00fcr die Indizierung durch Lucene konfiguriert. +gb.undefinedQueryWarning = Abfrage fehlt! +gb.noSelectedRepositoriesWarning = Bitte w\u00e4hlen Sie ein oder mehrere Repositories aus! +gb.luceneDisabled = Indizierung mit Lucene ist deaktiviert +gb.failedtoRead = Fehler beim Lesen +gb.isNotValidFile = ist keine g\u00fcltige Datei +gb.failedToReadMessage = Konnte Standard Nachricht von {0} nicht lesen! +gb.passwordsDoNotMatch = Passw\u00f6rter stimmen nicht \u00fcberein! +gb.passwordTooShort = Passwort ist zu kurz. Die minimale L\u00e4nge betr\u00e4gt {0} Zeichen. +gb.passwordChanged = Passwort erfolgreich ge\u00e4ndert. +gb.passwordChangeAborted = Passwort\u00e4nderung abgebrochen. +gb.pleaseSetRepositoryName = Bitte Repositorynamen angeben! +gb.illegalLeadingSlash = Pfade d\u00fcrfen nicht mit '/' beginnen. +gb.illegalRelativeSlash = Relative Pfade (../) sind nicht erlaubt. +gb.illegalCharacterRepositoryName = Repositoryname enth\u00e4lt nicht erlaubtes Zeichen ''{0}''! +gb.selectAccessRestriction = Bitte w\u00e4hlen Sie die Zugriffsbeschr\u00e4nkung aus! +gb.selectFederationStrategy = Bitte w\u00e4hlen Sie die Verbindungsstrategie (Federation) aus! +gb.pleaseSetTeamName = Bitte geben Sie einen Teamnamen an! +gb.teamNameUnavailable = Der Teamname ''{0}'' ist nicht verf\u00fcgbar. +gb.teamMustSpecifyRepository = Ein Team muss mindestens einem Repository zugewiesen sein. +gb.teamCreated = Neues Team ''{0}'' erfolgreich angelegt. +gb.pleaseSetUsername = Bitte geben Sie einen Benutzernamen an! +gb.usernameUnavailable = Benutzername ''{0}'' ist nicht verf\u00fcgbar. +gb.combinedMd5Rename = Gitblit ist f\u00fcr kombiniertes MD5-Passwort-Hashing konfiguriert. Sie m\u00fcssen beim Umbenennen des Kontos ein neues Passwort angeben. +gb.userCreated = Neuer Benutzer ''{0}'' erfolgreich angelegt. +gb.couldNotFindFederationRegistration = Konnte Verbindungsregistrierung (Federation) nicht finden! +gb.failedToFindGravatarProfile = Das Gravatar Profil f\u00fcr {0} konnte nicht gefunden werden +gb.branchStats = {0} Commit(s) und {1} Tag(s) seit {2} +gb.repositoryNotSpecified = Repository nicht angegeben! +gb.repositoryNotSpecifiedFor = Repository nicht angegeben f\u00fcr {0}! +gb.canNotLoadRepository = Repository kann nicht geladen werden +gb.commitIsNull = Commit ist null +gb.unauthorizedAccessForRepository = Nicht autorisierter Zugriff auf Repository +gb.failedToFindCommit = Commit \"{0}\" konnte nicht in {1} gefunden werden! +gb.couldNotFindFederationProposal = Verbindungsanfrage (Federation) konnte nicht gefunden werden! +gb.invalidUsernameOrPassword = Ung\u00fcltiger Benutzername oder Passwort! +gb.OneProposalToReview = Es gibt 1 unbeantwortete Verbindungsanfrage. +gb.nFederationProposalsToReview = Es gibt {0} unbeantwortete Verbindungsanfragen. +gb.couldNotFindTag = Der Tag {0} konnte nicht gefunden werden +gb.couldNotCreateFederationProposal = Die Verbindungsanfrage (Federation) konnte nicht erstellt werden. +gb.pleaseSetGitblitUrl = Bitte geben Sie Ihre Gitblit URL ein! +gb.pleaseSetDestinationUrl = Bitte geben Sie eine Ziel-URL f\u00fcr Ihre Anfrage ein! +gb.proposalReceived = Anfrage von {0} erfolgreich empfangen. +gb.noGitblitFound = Tut mir leid, {0} fand keine Gitblit Instanz in +gb.noProposals = Tut mir leid, {0} akzeptiert derzeit keine Anfragen. +gb.noFederation = Tut mir leid, {0} kann sich nicht mit anderen Gitblit Instanzen verbinden. +gb.proposalFailed = Tut mir leid, {0} hat keine Anfragedaten emfpangen! +gb.proposalError = Tut mir leid, {0} berichtet, dass ein unerwarteter Fehler aufgetreten ist! +gb.failedToSendProposal = Senden der Anfrage ist fehlgeschlagen! +gb.userServiceDoesNotPermitAddUser = {0} erlaubt das Anlegen von Benutzerkonten nicht. +gb.userServiceDoesNotPermitPasswordChanges = {0} erlaubt das \u00c4ndern von Passworten nicht! +gb.displayName = Anzeigename +gb.emailAddress = Emailadresse +gb.errorAdminLoginRequired = Administrierung erfordert eine Anmeldung +gb.errorOnlyAdminMayCreateRepository = Nur ein Administrator kann ein Repository erstellen +gb.errorOnlyAdminOrOwnerMayEditRepository = Nur ein Administrator oder der Besitzer kann ein Repository bearbeiten +gb.errorAdministrationDisabled = Administrierung ist deaktiviert +gb.lastNDays = letzte {0} Tage +gb.completeGravatarProfile = Komplettes Profil auf Gravatar.com +gb.none = keine +gb.line = Zeile +gb.content = Inhalt +gb.empty = leer +gb.inherited = vererbt +gb.deleteRepository = Repository \"{0}\" l\u00f6schen? +gb.repositoryDeleted = Repository ''{0}'' gel\u00f6scht. +gb.repositoryDeleteFailed = L\u00f6schen von Repository ''{0}'' fehlgeschlagen! +gb.deleteUser = Benutzer \"{0}\" l\u00f6schen? +gb.userDeleted = Benutzer ''{0}'' gel\u00f6scht. +gb.userDeleteFailed = L\u00f6schen von Benutzer ''{0}'' fehlgeschlagen! +gb.time.justNow = Gerade eben +gb.time.today = Heute +gb.time.yesterday = Gestern +gb.time.minsAgo = vor {0} Min. +gb.time.hoursAgo = vor {0} Std. +gb.time.daysAgo = vor {0} Tagen +gb.time.weeksAgo = vor {0} Wochen +gb.time.monthsAgo = vor {0} Monaten +gb.time.oneYearAgo = vor 1 Jahr +gb.time.yearsAgo = vor {0} Jahren +gb.duration.oneDay = 1 Tag +gb.duration.days = {0} Tage +gb.duration.oneMonth = 1 Monat +gb.duration.months = {0} Monaten +gb.duration.oneYear = 1 Jahr +gb.duration.years = {0} Jahren +gb.authorizationControl = Zugriffsrechte +gb.allowAuthenticatedDescription = Allen authentifizierten Benutzern RW+ Recht gew\u00e4hren +gb.allownameddescription = Benutzern und Teams feingranulare Rechte gew\u00e4hren +gb.markdownFailure = Markdown Inhalt konnte nicht geparst werden! +gb.clearCache = Cache leeren +gb.projects = Projekte +gb.project = Projekt +gb.allProjects = Alle Projekte +gb.copyToClipboard = in die Zwischenablage kopieren +gb.fork = Fork +gb.forks = Forks +gb.forkRepository = {0} forken? +gb.repositoryForked = Fork von {0} wurde erstellt +gb.repositoryForkFailed = Fork ist fehlgeschlagen +gb.personalRepositories = Pers\u00f6nliche Repositories +gb.allowForks = Forks erlauben +gb.allowForksDescription = Erlaube authentifizierten Benutzern dieses Repository zu forken +gb.forkedFrom = Fork von +gb.canFork = Kann forken +gb.canForkDescription = Kann autorisierte Repositories als pers\u00f6nliche Repositories forken +gb.myFork = Meinen Fork anschauen +gb.forksProhibited = Forks verboten +gb.forksProhibitedWarning = Dieses Repository verbietet Forks +gb.noForks = {0} hat keine Forks +gb.forkNotAuthorized = Entschuldigung, Sie sind nicht berechtigt einen Fork von {0} zu erstellen +gb.forkInProgress = Fork in Bearbeitung +gb.preparingFork = Ihr Fork wird vorbereitet... +gb.isFork = ist ein Fork +gb.canCreate = Kann Erstellen +gb.canCreateDescription = Kann pers\u00f6nliche Repositories erstellen +gb.illegalPersonalRepositoryLocation = your personal repository must be located at \"{0}\" +gb.verifyCommitter = Committer verifizieren +gb.verifyCommitterDescription = Die Committer Identit\u00e4t muss mit dem Gitblit Benutzerkonto \u00fcbereinstimmen, dass den Push durchf\u00fchrt +gb.verifyCommitterNote = Alle Merge Operationen ben\u00f6tigen "--no-ff" um die Committer Identit\u00e4t zu erzwingen +gb.repositoryPermissions = Repositoryberechtigungen +gb.userPermissions = Benutzerberechtigungen +gb.teamPermissions = Teamberechtigungen +gb.add = Hinzuf\u00fcgen +gb.noPermission = DIESE BERECHTIGUNG L\u00d6SCHEN +gb.excludePermission = {0} (Ausschlie\u00dfen) +gb.viewPermission = {0} (Ansicht) +gb.clonePermission = {0} (Clonen) +gb.pushPermission = {0} (Pushen) +gb.createPermission = {0} (Pushen, Erzeugen von Refs) +gb.deletePermission = {0} (Pushen, Erzeugen und L\u00f6schen von Refs) +gb.rewindPermission = {0} (Pushen, Erzeugen, L\u00f6schen und Umsetzen von Refs) +gb.permission = Berechtigung +gb.regexPermission = Diese Berechtigung ergibt sich aus dem regul\u00e4ren Ausdruck "{0}" +gb.accessDenied = Zugang verweigert +gb.busyCollectingGarbage = Tut mir leid, Gitblit f\u00fchrt gerade eine Garbage Collection in {0} durch +gb.gcPeriod = GC Intervall +gb.gcPeriodDescription = Zeitraum zwischen Garbage Collections +gb.gcThreshold = GC Schwellwert +gb.gcThresholdDescription = Minimale Gr\u00f6\u00dfe von losen Objekten, um eine vorzeitge Garbage Collection zu starten +gb.ownerPermission = Repositorybesitzer +gb.administrator = Administrator +gb.administratorPermission = Gitblit Administrator +gb.team = Team +gb.teamPermission = Berechtigung gesetzt durch Mitgliedschaft im Team \"{0}\" +gb.missing = fehlt! +gb.missingPermission = Das Repository f\u00fcr diese Berechtigung fehlt! +gb.mutable = ver\u00e4nderlich +gb.specified = angegeben +gb.effective = effektiv +gb.organizationalUnit = Organisatorische Einheit +gb.organization = Organisation +gb.locality = Lage +gb.stateProvince = Bundesland oder Provinz +gb.countryCode = L\u00e4ndercode +gb.properties = Eigenschaften +gb.issued = herausgegeben +gb.expires = l\u00e4uft ab +gb.expired = abgelaufen +gb.expiring = l\u00e4uft ab +gb.revoked = widerrufen +gb.serialNumber = Seriennummer +gb.certificates = Zertifkate +gb.newCertificate = Neues Zertifikat +gb.revokeCertificate = Zertifikat widerrufen +gb.sendEmail = Sende E-Mail +gb.passwordHint = Passwort Hinweis +gb.ok = OK +gb.invalidExpirationDate = Ung\u00fcltiges Ablaufdatum! +gb.passwordHintRequired = Passworthinweis ben\u00f6tigt! +gb.viewCertificate = Zertifikat anschauen +gb.subject = Betreff +gb.issuer = Aussteller +gb.validFrom = G\u00fcltig von +gb.validUntil = G\u00fcltig bis +gb.publicKey = \u00d6ffentlicher Schl\u00fcssel +gb.signatureAlgorithm = Signaturalgorithmus +gb.sha1FingerPrint = SHA-1 Fingerabdruck +gb.md5FingerPrint = MD5 Fingerabdruck +gb.reason = Grund +gb.revokeCertificateReason = Bitte w\u00e4hlen Sie einen Grund f\u00fcr den Widerruf des Zertifikats aus +gb.unspecified = nicht angegeben +gb.keyCompromise = Schl\u00fcssel kompromittiert +gb.caCompromise = CA kompromittiert +gb.affiliationChanged = Mitgliedschaft ge\u00e4ndert +gb.superseded = ersetzt +gb.cessationOfOperation = T\u00e4tigkeit eingestellt +gb.privilegeWithdrawn = Privilegien zur\u00fcckgezogen +gb.time.inMinutes = in {0} Minuten +gb.time.inHours = in {0} Stunden +gb.time.inDays = in {0} Tagen +gb.hostname = Hostname +gb.hostnameRequired = Bitte geben Sie einen Hostnamen ein +gb.newSSLCertificate = Neues Server-SSL-Zertifikat +gb.newCertificateDefaults = Voreinstellungen f\u00fcr neue Zertifikate +gb.duration = Dauer +gb.certificateRevoked = Zertifikat {0,number,0} wurde widerufen +gb.clientCertificateGenerated = Neues Client-Zertifikat f\u00fcr {0} wurde erfolgreich erstellt +gb.sslCertificateGenerated = Neues Server-SSL-Zertifikat f\u00fcr {0} wurde erfolgreich erstellt +gb.newClientCertificateMessage = ANMERKUNG:\nDas "Passwort" ist nicht das Passwort des Benutzers, es ist das Passwort, um den Keystore des Benutzers zu sch\u00fctzen. Dieses Passwort wird nicht gespeichert, also m\u00fcssen Sie einen "Hinweis" eingeben. Dieser Hinweis wird in den README Anweisungen des Benutzers hinterlegt. +gb.certificate = Zertifkat +gb.emailCertificateBundle = Client-Zertifikat-Bundle per Email senden +gb.pleaseGenerateClientCertificate = Bitte generieren Sie ein Client Zertifikat f\u00fcr {0} +gb.clientCertificateBundleSent = Client-Zertifikat-Bundel f\u00fcr {0} gesendet +gb.enterKeystorePassword = Bitte geben Sie das Gitblit-Keystore-Passwort ein +gb.warning = Warnung +gb.jcwWarning = Ihrem Java Runtime Environment fehlen die \"JCE Unlimited Strength Jurisdiction Policy\" Dateien.\nDies schr\u00e4nkt die L\u00e4nge der Passw\u00f6rter, die Sie zum Verschl\u00fcsseln Ihrer Keystores verwenden k\u00f6nnen, auf 7 Zeichen ein.\nDiese Policy-Dateien sind ein optionaler Download von Oracle.\n\nM\u00f6chten Sie fortfahren und die Zertifikat-Infrastruktur trotzdem erstellen?\n\nWenn Sie mit Nein antworten, wird Ihr Browser die Oracle Download-Seite \u00f6ffnen, auf welcher Sie die Policy-Dateien herunterladen k\u00f6nnen. +gb.maxActivityCommits = Maximale Commits Aktivit\u00e4t +gb.maxActivityCommitsDescription = Maximale Anzahl von Commits die auf der Aktivit\u00e4tsseite dargestellt werden +gb.noMaximum = Kein Maximum +gb.attributes = Attribute +gb.serveCertificate = Verwende dieses Zertifikat f\u00fcr HTTPS +gb.sslCertificateGeneratedRestart = Neues SSL-Server-Zertifikat f\u00fcr {0} erfolgreich erstellt.\nSie m\u00fcssen Gitblit neu starten, um dieses Zertifikat nutzen zu k\u00f6nnen.\n\nWenn Sie dem '--alias' Parameter starten, m\u00fcssen Sie diesen auf '--alias {0}' setzen. +gb.validity = G\u00fcltigkeit +gb.siteName = Seitenname +gb.siteNameDescription = Kurzer, beschreibender Name Ihres Servers +gb.excludeFromActivity = Von der Aktivi\u00e4tenseite ausschlie\u00dfen +gb.isSparkleshared = Repository ist in einem Sparkleshare +gb.owners = Besitzer +gb.sessionEnded = Die Sitzung wurde geschlossen +gb.closeBrowser = Bitte schlie\u00dfen Sie den Browser um die Sitzung ordentlich zu beenden. +gb.doesNotExistInTree = {0} existiert im Dateibaum {1} nicht +gb.enableIncrementalPushTags = Aktiviere inkrementelle Push-Tags +gb.useIncrementalPushTagsDescription = Erzeuge beim Push automatisch ein Tag mit aufsteigender Revisionsnummer auf der Spitze jedes Branches +gb.incrementalPushTagMessage = Auto-tagged [{0}] branch on push +gb.externalPermissions = {0} Zugangsberechtigungen werden extern verwaltet +gb.viewAccess = Sie haben keinen Gitblit Lese- oder Schreibzugriff +gb.overview = \u00dcbersicht +gb.dashboard = Dashboard +gb.monthlyActivity = Monatliche Aktivit\u00e4t +gb.myProfile = Mein Profil +gb.compare = Vergleichen +gb.manual = Manuell +gb.from = von +gb.to = nach +gb.at = bei +gb.of = von +gb.in = in +gb.moreChanges = alle \u00c4nderungen... +gb.pushedNCommitsTo = Push von {0} Commits nach +gb.pushedOneCommitTo = Push von einem Commit nach +gb.commitsTo = {0} commits nach +gb.oneCommitTo = 1 Commit nach +gb.byNAuthors = von {0} Autoren +gb.byOneAuthor = von {0} +gb.viewComparison = Zeige einen Vergleich von diesen {0} Commits \u00bb +gb.nMoreCommits = {0} weitere Commits \u00bb +gb.oneMoreCommit = 1 weiterer Commit \u00bb +gb.pushedNewTag = Push von neuem Tag +gb.createdNewTag = Neuer Tag angelegt +gb.deletedTag = Tag gel\u00f6scht +gb.pushedNewBranch = Push von neuem Branch durchgef\u00fchrt +gb.createdNewBranch = Neuer Branch angelegt +gb.deletedBranch = Branch gel\u00f6scht +gb.createdNewPullRequest = Neuer Pull Request gestellt +gb.mergedPullRequest = Merge des Pull Request durchgef\u00fchrt +gb.rewind = REWIND +gb.star = Favorisieren +gb.unstar = Nicht mehr favorisieren +gb.stargazers = Stargazers +gb.starredRepositories = Favorisierte Repositories +gb.failedToUpdateUser = Aktualisierung des Benutzerkontos fehlgeschlagen! +gb.myRepositories = Meine Repositories +gb.noActivity = In den letzten {0} Tagen gab es keine Aktivit\u00e4t +gb.findSomeRepositories = finde Repositories +gb.metricAuthorExclusions = Ausschl\u00fcsse von Autor-Metriken +gb.myDashboard = Mein Dashboard +gb.failedToFindAccount = Benutzerkonto "{0}" konnte nicht gefunden werden +gb.reflog = Reflog +gb.active = Aktiv +gb.starred = Favorisiert +gb.owned = Eigene +gb.starredAndOwned = Favorisiert und Eigene +gb.reviewPatchset = Review {0} Patchset {1} +gb.todaysActivityStats = Heute / {1} Commits von {2} Autoren +gb.todaysActivityNone = Heute / keine +gb.noActivityToday = Heute gab es keine Aktivit\u00e4t +gb.anonymousUser= Anonym +gb.commitMessageRenderer = Commit-Message Renderer +gb.diffStat = {0} Einf\u00fcgungen & {1} L\u00f6schungen +gb.home = Startseite +gb.isMirror = Dieses Repository ist ein Mirror +gb.mirrorOf = Mirror von {0} +gb.mirrorWarning = Dieses Repository ist ein Mirror und kann keine Pushes empfangen +gb.docsWelcome1 = Sie k\u00f6nnen Dokumente verwenden, um Ihr Repository zu dokumentieren. +gb.docsWelcome2 = Committen Sie eine README.md oder eine HOME.md Datei, um zu beginnen. +gb.createReadme = Eine README erstellen +gb.responsible = Bearbeiter +gb.createdThisTicket = erstellte dieses Ticket +gb.proposedThisChange = schlug diese \u00c4nderung vor +gb.uploadedPatchsetN = lud Patchset {0} hoch +gb.uploadedPatchsetNRevisionN = lud Patchset {0} Revision {1} hoch +gb.mergedPatchset = Merge des Patchset durchgef\u00fchrt +gb.commented = kommentierte +gb.noDescriptionGiven = keine Beschreibung hinterlegt +gb.toBranch = nach {0} +gb.createdBy = angelegt durch +gb.oneParticipant = {0} Teilnehmer +gb.nParticipants = {0} Teilnehmer +gb.noComments = keine Kommentare +gb.oneComment = {0} Kommentar +gb.nComments = {0} Kommentare +gb.oneAttachment = {0} Anhang +gb.nAttachments = {0} Anh\u00e4nge +gb.milestone = Meilenstein +gb.compareToMergeBase = Mit Merge-Basis vergleichen +gb.compareToN = mit {0} vergleichen +gb.open = Offen +gb.closed = Geschlossen +gb.merged = Merge erfolgt +gb.ticketPatchset = Ticket {0}, Patchset {1} +gb.patchsetMergeable = Dieses Patchset kann automatisch mit {0} zusammengef\u00fchrt werden. +gb.patchsetMergeableMore = Dieses Patchset kann auch auf der Kommandozeile mit {0} zusammengef\u00fchrt werden. +gb.patchsetAlreadyMerged = Dieses Patcheset wurde mit {0} zusammengef\u00fchrt. +gb.patchsetNotMergeable = Dieses Patchset kann nicht automatisch mit {0} zusammengef\u00fchrt werden. +gb.patchsetNotMergeableMore = Dieses Patchset ben\u00f6tigt einen Rebase oder muss manuell mit {0} zusammengef\u00fchrt werden, um Konflikte zu beheben. +gb.patchsetNotApproved = Diese Patchset-Revision wurde noch nicht zum Zusammenf\u00fchren mit {0} freigegeben. +gb.patchsetNotApprovedMore = Ein Reviewer muss dieses Patchset freigeben. +gb.patchsetVetoedMore = Ein Reviewer hat dieses Patchset abgelehnt. +gb.write = Verfassen +gb.comment = Kommentieren +gb.preview = Vorschau +gb.leaveComment = Hinterlasse einen Kommentar +gb.showHideDetails = Zeige/Verberge Details +gb.acceptNewPatchsets = Patchsets annehmen +gb.acceptNewPatchsetsDescription = Nimm Patchsets an dieses Repository per Push an +gb.acceptNewTickets = Erlaube neue Tickets +gb.acceptNewTicketsDescription = Erlaube das Erstellen von Fehlerberichten, Verbesserungsvorschl\u00e4gen, Aufgaben etc. +gb.requireApproval = Explizite Freigaben erforderlich +gb.requireApprovalDescription = Patchsets m\u00fcssen freigegeben werden, bevor der Merge Button aktiviert wird +gb.topic = Thema +gb.proposalTickets = Vorgeschlagene \u00c4nderungen +gb.bugTickets = Fehler +gb.enhancementTickets = Erweiterungen +gb.taskTickets = Aufgaben +gb.questionTickets = Fragen +gb.requestTickets = Erweiterungen und Aufgaben +gb.yourCreatedTickets = Von mir erstellt +gb.yourWatchedTickets = Von mir beobachtet +gb.mentionsMeTickets = Erw\u00e4hnungen +gb.updatedBy = aktualisiert von +gb.sort = Sortierung +gb.sortNewest = Neueste +gb.sortOldest = \u00c4lteste +gb.sortMostRecentlyUpdated = K\u00fcrzlich aktualisiert +gb.sortLeastRecentlyUpdated = Am l\u00e4ngsten nicht aktualisiert +gb.sortMostComments = Die meisten Kommentare +gb.sortLeastComments = Die wenigsten Kommentare +gb.sortMostPatchsetRevisions = Die meisten Patchset Revisions +gb.sortLeastPatchsetRevisions = Die wenigsten Patchset Revisions +gb.sortMostVotes = Die meisten Stimmen +gb.sortLeastVotes = Die wenigsten Stimmen +gb.topicsAndLabels = Themen & Labels +gb.milestones = Meilensteine +gb.noMilestoneSelected = Kein Meilenstein ausgew\u00e4hlt +gb.notSpecified = nicht angegebene +gb.due = f\u00e4llig am +gb.queries = Suchanfragen +gb.searchTicketsTooltip = Suche {0} Tickets +gb.searchTickets = Search Tickets +gb.new = Neu +gb.newTicket = Neues Ticket +gb.editTicket = Bearbeite Ticket +gb.ticketsWelcome = Sie k\u00f6nnen Tickets verwenden, um Ihre Todo-Liste zu verwalten, Fehler zu diskutieren und bei der Erstellung von Patchsets zusammen zu arbeiten. +gb.createFirstTicket = Erstellen Sie Ihr erstes Ticket +gb.title = \u00dcberschrift +gb.changedStatus = hat Status ge\u00e4ndert +gb.discussion = Diskussion +gb.updated = aktualisiert +gb.proposePatchset = Patchset Vorschlagen +gb.proposePatchsetNote = Bitte schlagen Sie ein Patchset f\u00fcr dieses Ticket vor. +gb.proposeInstructions = Um zu beginnen, erstellen Sie ein Patchset und laden Sie es mit Git hoch. Gitblit verkn\u00fcpft dieses Patchset mit diesem Ticket \u00fcber die Id. +gb.proposeWith = Ein Patchset mit {0} vorschlagen +gb.revisionHistory = Revisionshistorie +gb.merge = Zusammenf\u00fchren +gb.action = Aktion +gb.patchset = Patchset +gb.all = Alle +gb.mergeBase = Merge Basis +gb.checkout = Checkout +gb.checkoutViaCommandLine = Checkout per Kommandozeile +gb.checkoutViaCommandLineNote = Sie k\u00f6nnen diese \u00c4nderungen in Ihrem Clone des Repository per Checkout lokal testen. +gb.checkoutStep1 = Laden Sie das aktuelle Patchset \u2014 F\u00fchren Sie dies aus Ihrem lokalen Projektverzeichnis heraus aus +gb.checkoutStep2 = F\u00fchren Sie einen Checkout des Patchsets in einen neuen Branch durch und Sichten Sie die \u00c4nerungen +gb.mergingViaCommandLine = Merge per Kommandozeile +gb.mergingViaCommandLineNote = Wenn Sie den Merge Button nicht verwenden m\u00f6chten oder ein automatisches Zusammenf\u00fchren nicht durchgef\u00fchrt werden kann, dann k\u00f6nnen Sie das Zusammenf\u00fchren auch manuell auf der Kommandozeile durchf\u00fchren. +gb.mergeStep1 = Erstellen Sie einen neuen Branch um die \u00c4nderungen zu sichten \u2014 F\u00fchren Sie dies aus Ihrem lokalen Projektverzeichnis heraus aus +gb.mergeStep2 = Bringen Sie die vorgeschlagenen \u00c4nderungen ein und sichten Sie diese +gb.mergeStep3 = F\u00fchren Sie einen Merge durch und aktualisieren Sie den Server (Push) +gb.download = Herunterladen +gb.ptDescription = Das Gitblit Patchset Tool +gb.ptCheckout = Fetch & Checkout des aktuellen Patchset um ein Review des aktuellen Branch durchzuf\u00fchren +gb.ptMerge = Fetch & Merge des aktuellen Patchset in Ihren lokalen Branch +gb.ptDescription1 = Barnum ist ein Kommandozeilen-Werkzeug f\u00fcr Git um die Syntax f\u00fcr die Arbeit mit Gitblit Tickets und Patchsets zu vereinfachen. +gb.ptSimplifiedCollaboration = Vereinfachte Syntax f\u00fcr Zusammenarbeit +gb.ptSimplifiedMerge = Vereinfachte Syntax f\u00fcr das Zusammenf\u00fchren +gb.ptDescription2 = Barnum ben\u00f6tigt Python 3 und den nativen Git-Client. Es l\u00e4uft unter Windows, Linux und Mac OS X. +gb.stepN = Schritt {0} +gb.watchers = Beobachter +gb.votes = Stimmen +gb.vote = F\u00fcr {0} Abstimmen +gb.watch = {0} beobachten +gb.removeVote = Abstimmen r\u00fcckg\u00e4ngig machen +gb.stopWatching = Beobachten beenden +gb.watching = ich beobachte +gb.comments = Kommentare +gb.addComment = Kommentar hinzuf\u00fcgen +gb.export = Exportieren +gb.oneCommit = Ein Commit +gb.nCommits = {0} Commits +gb.addedOneCommit = 1 Commit hinzugef\u00fcgt +gb.addedNCommits = {0} Commits hinzugef\u00fcgt +gb.commitsInPatchsetN = Commits im Patchset {0} +gb.patchsetN = Patchset {0} +gb.reviewedPatchsetRev = Review von Patchset {0} Revision {1} durchgef\u00fchrt: {2} +gb.review = Review +gb.reviews = Reviews +gb.veto = Abgelehnt +gb.needsImprovement = Ben\u00f6tigt Verbesserungen +gb.looksGood = Sieht gut aus +gb.approve = Akzeptiert +gb.hasNotReviewed = kein Review durchgef\u00fchrt +gb.about = \u00dcber +gb.ticketN = Ticket #{0} +gb.disableUser = Benutzer deaktivieren +gb.disableUserDescription = Verhindert das Authentifizieren dieses Benutzer +gb.any = Alle +gb.milestoneProgress = {0} offen, {1} geschlossen +gb.nOpenTickets = {0} offen +gb.nClosedTickets = {0} geschlossen +gb.nTotalTickets = {0} insgesamt +gb.body = Body +gb.mergeSha = mergeSha +gb.mergeTo = Merge mit +gb.labels = Labels +gb.reviewers = Reviewer +gb.voters = Abstimmende +gb.mentions = Erw\u00e4hnungen +gb.canNotProposePatchset = Kann kein Patchset vorschlagen +gb.repositoryIsMirror = Dieses Repository ist ein Read-Only-Mirror. +gb.repositoryIsFrozen = Dieses Repository ist eingefroren. +gb.repositoryDoesNotAcceptPatchsets = Dieses Repository akzeptiert keine Patchsets. +gb.serverDoesNotAcceptPatchsets = Dieser Server akzeptiert keine Patchsets. +gb.ticketIsClosed = Dieses Ticket ist geschlossen. +gb.mergeToDescription = Standardm\u00e4\u00dfiger Integrationsbranch f\u00fcr den Merge von Ticket Patchsets +gb.anonymousCanNotPropose = Anonyme Benutzer k\u00f6nnen keine Patchsets vorschlagen. +gb.youDoNotHaveClonePermission = Sie sind nicht berechtigt, dieses Repository zu klonen. +gb.myTickets = Meine Tickets +gb.yourAssignedTickets = Mir zugewiesen +gb.newMilestone = Neuer Meilenstein +gb.editMilestone = Meilenstein bearbeiten +gb.deleteMilestone = Meilenstein \"{0}\" l\u00f6schen? +gb.milestoneDeleteFailed = L\u00f6schen des Meilensteins ''{0}'' fehlgeschlagen! +gb.notifyChangedOpenTickets = Sende Benachrichtigungen f\u00fcr ge\u00e4nderte, offene Tickets +gb.overdue = \u00dcberf\u00e4llig +gb.openMilestones = Offene Meilensteine +gb.closedMilestones = Geschlossene Meilensteine +gb.administration = Administration +gb.plugins = Plugins +gb.extensions = Erweiterungen +gb.pleaseSelectProject = Bitte w\u00e4hlen Sie das Projekt! +gb.accessPolicy = Zugriffsrichtlinie +gb.accessPolicyDescription = W\u00e4hlen Sie eine Zugriffsrichtlinie um die Sichtbarkeit des Repositories und die Zugriffsrechte von Git zu steuern. +gb.anonymousPolicy = Anonymes Anzeigen, Klonen und Pushen +gb.anonymousPolicyDescription = Jeder kann dieses Repository sehen, klonen und zu ihm pushen. +gb.authenticatedPushPolicy = Schr\u00e4nke Pushen ein (Authentifiziert) +gb.authenticatedPushPolicyDescription = Jeder kann dieses Repository sehen und klonen. Alle authentifizierten Benutzer haben RW+ Push Berechtigung. +gb.namedPushPolicy = Schr\u00e4nke Pushen ein (Benannt) +gb.namedPushPolicyDescription = Jeder kann dieses Repository sehen und klonen. Sie bestimmen, wer pushen kann. +gb.clonePolicy = Schr\u00e4nke Klonen und Pushen ein +gb.clonePolicyDescription = Jeder kann dieses Repository sehen. Sie bestimmen, wer klonen und pushen kann. +gb.viewPolicy = Schr\u00e4nke Anzeigen, Klonen und Pushen ein +gb.viewPolicyDescription = Sie bestimmen, wer dieses Repository anzeigen, klonen und zu ihm pushen kann. +gb.initialCommit = Initialer Commit +gb.initialCommitDescription = Dies erlaubt es Ihnen, mit git clone dieses Repository sofort zu klonen. \u00dcberspringen Sie diesen Schritt, falls Sie lokal bereits git init ausgef\u00fchrt haben. +gb.initWithReadme = README erstellen +gb.initWithReadmeDescription = Dies erstellt ein einfaches README Dokument f\u00fcr Ihr Repository. +gb.initWithGitignore = Eine .gitignore Datei erstellen +gb.initWithGitignoreDescription = Dies erstellt eine Konfigurationsdatei, die Ihren Git Client anweist, Dateien und Verzeichnisse zu ignorieren, die bestimmten Mustern entsprechen. +gb.pleaseSelectGitIgnore = Bitte w\u00e4hlen Sie eine .gitignore Datei aus +gb.receive = Empfangen +gb.permissions = Berechtigungen +gb.ownersDescription = Besitzer k\u00f6nnen alle Einstellungen des Repository ver\u00e4ndern, jedoch k\u00f6nnen Sie das Repository nur umbenennen, falls es ein pers\u00f6nliches Repository ist. +gb.userPermissionsDescription = Sie k\u00f6nnen individuelle Benutzerberechtigungen vergeben. Diese Einstellungen \u00fcbersteuern Team- oder Regexberechtigungen. +gb.teamPermissionsDescription = Sie k\u00f6nnen individuelle Teamberechtigungen vergeben. Diese Einstellungen \u00fcbersteuern Regexberechtigungen. +gb.ticketSettings = Ticketeinstellungen +gb.receiveSettings = Empfangseinstellungen +gb.receiveSettingsDescription = Die Empfangseinstellungen kontrollieren Pushes zum Repository. +gb.preReceiveDescription = Pre-Empfangs-Hooks werden ausgef\u00fchrt nachdem alle Commits empfangen wurden, aber BEVOR die Refs aktualisiert werden.

    Dies ist der geeignete Hook, um einen Push abzulehnen.

    +gb.postReceiveDescription = Post-Empfangs-Hooks werden ausgef\u00fchrt, nachdem alle Commits empfangen wurden und NACHDEM die Refs aktualisiert wurden.

    Dies ist der geeignete Hook f\u00fcr Benachrichtigungen, Build-Trigger, etc.

    +gb.federationStrategyDescription = Bestimmen Sie, ob und wie dieses Repository mit einer anderen Gitblit Instanz verbunden werden kann (Federation). +gb.federationSetsDescription = Dieses Repository wird in den ausgew\u00e4hlten Verbindungssets enthalten sein. +gb.miscellaneous = Sonstiges +gb.originDescription = Die URL, von welcher dieses Repository geklont wurde. +gb.gc = GC +gb.garbageCollection = Garbage Collection +gb.garbageCollectionDescription = Die Garbage Collection b\u00fcndelt freie Objekte, welche von Clients gepusht wurden und entfernt nicht mehr referenzierte Objekte aus dem Repository. +gb.commitMessageRendererDescription = Commit Messages k\u00f6nnen als reiner Text oder gerendertes Markup dargestellt werden. +gb.preferences = Einstellungen +gb.accountPreferences = Kontoeinstellungen +gb.accountPreferencesDescription = Geben Sie Ihre Kontoeinstellungen an +gb.languagePreference = Spracheinstellungen +gb.languagePreferenceDescription = W\u00e4hlen Sie Ihre bevorzugte \u00dcbersetzung f\u00fcr Gitblit +gb.emailMeOnMyTicketChanges = Sende Emails bei eigenen \u00c4nderungen an Tickets +gb.emailMeOnMyTicketChangesDescription = Sende mir Email-Benachrichtigungen f\u00fcr \u00c4nderungen, die ich an einem Ticket vornehme +gb.displayNameDescription = Bevorzugter Anzeigename +gb.emailAddressDescription = Die prim\u00e4re Emailadresse f\u00fcr den Empfang von Benachrichtigungen +gb.sshKeys = SSH Keys +gb.sshKeysDescription = SSH Public Key Authentifizierung ist eine sichere Alternative zur Authentifizierung mit Passwort +gb.addSshKey = SSH Key hinzuf\u00fcgen +gb.key = Key +gb.comment = Kommentar +gb.sshKeyCommentDescription = Geben Sie optional einen Kommentar ein. Falls Sie dies nicht tun, wird der Kommentar aus dem Key extrahiert. +gb.permission = Berechtigung + +gb.sshKeyPermissionDescription = Geben Sie die Zugriffberechtigung f\u00fcr den SSH Key an +gb.transportPreference = \u00dcbertragungseinstellungen +gb.transportPreferenceDescription = Geben Sie die \u00dcbertragungsart an, die Sie f\u00fcr das Klonen bevorzugen -- cgit v1.2.3 From 6be80398ba815192ecef3ada32b2b0f6bf7f74cf Mon Sep 17 00:00:00 2001 From: Carsten Lenz Date: Fri, 13 Jun 2014 09:16:04 +0200 Subject: Add german translation of EmptyrepositoryPage.html --- .../wicket/pages/EmptyRepositoryPage_de.html | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_de.html diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_de.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_de.html new file mode 100644 index 00000000..6888e1df --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_de.html @@ -0,0 +1,60 @@ + + + + + +
    +
    +
    +
    +

    Leeres Repository

    +
    + [repository] ist ein leeres Repository und kann von Gitblit nicht angezeigt werden. +

    + Bitte pushen Sie einige Commits nach +
    + Nachdem Sie Commits gepusht haben, können Sie diese Seite aktualisieren, um Ihr Repository anzuzeigen. +
    + +

    Neues Respository auf der Kommandozeile erstellen

    + +
    
    +
    +	

    Ein existierendes Repository von der Kommandozeile pushen

    + +
    
    +	
    +	
    +

    Git lernen

    +

    Falls Sie unsicher sind, was Sie mit diesen Informationen anfangen sollen, können Sie sich das Git Community Buch anschauen, um ein besseres Verständnis über die Verwendung von Git aufzubauen.

    + +

    Open Source Git Clients

    + + + + + + + + +
    Gitder offizielle Kommandozeilen-Git-Client
    TortoiseGitWindows Datei Explorer Integration (erfordert den offiziellen Kommandozeilen-Client)
    Eclipse/EGitGit für die Eclipse IDE (basiert auf JGit, ebenso wie Gitblit)
    Git ExtensionsC# Frontend für Git mit Windows Explorer und Visual Studio Integration
    GitX-devein Mac OS X Git Client
    + +

    Kommerzielle/Closed-Source Git Clients

    + + + + + + +
    SmartGit/HgEin Java Git und Mercurial Client für Windows, Mac und Linux
    SourceTreeEin freier Git und Mercurial Client für Windows und Mac
    TowerEin Mac OS X Git Client
    +
    +
    +
    +
    +
    +
    + + -- cgit v1.2.3 From be12c27513d066aa233ce631c1937f13b2231f8a Mon Sep 17 00:00:00 2001 From: Carsten Lenz Date: Fri, 13 Jun 2014 09:16:31 +0200 Subject: Add german translation of login.mkd --- src/main/java/login_de.mkd | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/main/java/login_de.mkd diff --git a/src/main/java/login_de.mkd b/src/main/java/login_de.mkd new file mode 100644 index 00000000..0c89092f --- /dev/null +++ b/src/main/java/login_de.mkd @@ -0,0 +1,3 @@ +## Bitte melden Sie sich an + +Bitte geben Sie Ihre Zugangsdaten ein um auf Gitblit zuzugreifen. -- cgit v1.2.3 From 077d23176a8f098766bf492081ae5ab9acb2d285 Mon Sep 17 00:00:00 2001 From: Carsten Lenz Date: Fri, 13 Jun 2014 09:16:44 +0200 Subject: Add german translation of welcome.mkd --- src/main/java/welcome_de.mkd | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 src/main/java/welcome_de.mkd diff --git a/src/main/java/welcome_de.mkd b/src/main/java/welcome_de.mkd new file mode 100644 index 00000000..d597ebef --- /dev/null +++ b/src/main/java/welcome_de.mkd @@ -0,0 +1,3 @@ +## Willkommen bei Gitblit + +Eine schnelle und einfache Art und Weise Ihre eigenen [Git](http://www.git-scm.com) Repositories zu hosten. -- cgit v1.2.3 From a65e7367e8b62ffcfa163c9850cf9e9c25c68ce0 Mon Sep 17 00:00:00 2001 From: James Moger Date: Fri, 13 Jun 2014 09:11:56 -0400 Subject: Documentation --- releases.moxie | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/releases.moxie b/releases.moxie index 7314160d..64039bc0 100644 --- a/releases.moxie +++ b/releases.moxie @@ -23,6 +23,8 @@ r24: { * Basic CRUD pages for ticket milestones * Overhaul repository creation, editing, and empty repository pages + If you are upgrading, you might consider copying the data/gitignore folder to your ${baseFolder} to allow selection & injection of a .gitignore when creating a repository. + The OpenShift Express build has been dropped. You can deploy GO or WAR on Express so this build is no longer necessary. '' security: ~ @@ -46,6 +48,7 @@ r24: { - BARNUM: Create ticket/N instead of topic/N for pt start N (ticket-61) - Move repository deletion functions to the edit repository page AND allow deletion to be disabled (pr-180, ticket-67) - Update the Korean translation (pr-184, ticket-69) + - Update the Dutch translation (pr-191) - Overhaul the EmptyRepositoryPage (ticket-73) - Overhauled the edit repository page (ticket-76) - Process bugtraq links in the ticket description and comments (ticket-78) @@ -65,6 +68,8 @@ r24: { - Tag server-side merges when incremental push tags are enabled (issue-432, ticket-85) - Add a user preference for the clone transport (ticket-90) - Add setting to control default thread pool size for miscellaneous background tasks (ticket-92) + - Add Norwegian transation (pr-186) + - Add German translation (pr-192) dependencyChanges: - Update to javax.mail 1.5.1 (issue-417, ticket-58) contributors: @@ -78,6 +83,14 @@ r24: { - Matthias Cullmann - Emmeran Seehuber - Sascha Vogt + - Carsten Lenz + - Matthias Sohn + - Leif Jantzen + - Stardrad Yin + - Jeroen Baten + - Dongsu Kim + - Karanbir Singh + - Tamás Papp settings: - { name: 'web.allowDeletingNonEmptyRepositories', defaultValue: 'true' } - { name: 'web.includePersonalRepositories', defaultValue: 'false' } -- cgit v1.2.3 From 13dd7599e2e86abe30949203b7e14ccd2cd2748e Mon Sep 17 00:00:00 2001 From: James Moger Date: Fri, 13 Jun 2014 09:24:13 -0400 Subject: Add Deutsch (de) language preference choice --- src/main/java/com/gitblit/wicket/pages/UserPage.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java index 306eea65..7c6b7b0e 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.java +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java @@ -172,6 +172,7 @@ public class UserPage extends RootPage { Form prefs = new Form("prefsForm"); List languages = Arrays.asList( + new Language("Deutsch","de"), new Language("English","en"), new Language("Español", "es"), new Language("Français", "fr"), -- cgit v1.2.3 From c634aa48c3b3bc2c0136c65547e1b42321ea4908 Mon Sep 17 00:00:00 2001 From: James Moger Date: Fri, 13 Jun 2014 09:54:23 -0400 Subject: Reorder "email on ticket changes" preference to follow "email address" --- src/main/java/com/gitblit/wicket/pages/UserPage.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.html b/src/main/java/com/gitblit/wicket/pages/UserPage.html index 8dccfee7..6bdd3cee 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.html +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.html @@ -64,8 +64,8 @@
    -
    +
    -- cgit v1.2.3 From b156c89409772fc5b21348f17d28f63de3a1df61 Mon Sep 17 00:00:00 2001 From: James Moger Date: Fri, 13 Jun 2014 09:54:47 -0400 Subject: Documentation --- src/site/features.mkd | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/site/features.mkd b/src/site/features.mkd index 5981f834..9aa81962 100644 --- a/src/site/features.mkd +++ b/src/site/features.mkd @@ -69,6 +69,8 @@ - Dutch - Simplified Chinese (zh_CN) - French + - German + - Norwegian ## Gitblit GO Features - Out-of-the-box integrated stack requiring minimal configuration -- cgit v1.2.3 From 9dae6484fe16201fde92cd2a3cc684399e777a3b Mon Sep 17 00:00:00 2001 From: "Dongsu, KIM" Date: Sat, 14 Jun 2014 19:35:39 +0900 Subject: Update Korean translation --- .../com/gitblit/wicket/GitBlitWebApp_ko.properties | 70 ++++++++++++++++++++++ .../wicket/pages/EmptyRepositoryPage_ko.html | 22 +++---- 2 files changed, 81 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_ko.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_ko.properties index 51e80f4a..404f0d28 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_ko.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_ko.properties @@ -672,3 +672,73 @@ gb.ticketIsClosed = \uc774 \ud2f0\ucf13\uc740 \ub2eb\ud600 \uc788\uc2b5\ub2c8\ub gb.mergeToDescription = \ud2f0\ucf13 \ud328\uce58\uc14b\uc744 \uba38\uc9c0\ud560 \uae30\ubcf8 \ud1b5\ud569 \ube0c\ub79c\uce58 gb.anonymousCanNotPropose = \uc775\uba85 \uc0ac\uc6a9\uc790\ub294 \ud328\uce58\uc14b\uc744 \uc81c\uc548\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. gb.youDoNotHaveClonePermission = \ub2f9\uc2e0\uc740 \uc774 \uc800\uc7a5\uc18c\ub97c \ud074\ub860\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +gb.myTickets = \ub0b4 \ud2f0\ucf13 +gb.yourAssignedTickets = \ub098\uc5d0\uac8c \ud560\ub2f9\ub41c +gb.newMilestone = \uc0c8 \ub9c8\uc77c\uc2a4\ud1a4 +gb.editMilestone = \ub9c8\uc77c\uc2a4\ud1a4 \uc218\uc815 +gb.deleteMilestone = \ub9c8\uc77c\uc2a4\ud1a4 \"{0}\"\uc744(\ub97c) \uc0ad\uc81c\ud560\uae4c\uc694? +gb.milestoneDeleteFailed = \ub9c8\uc77c\uc2a4\ud1a4 ''{0}'' \uc0ad\uc81c \uc2e4\ud328! +gb.notifyChangedOpenTickets = \uc5f0 \ud2f0\ucf13\uc758 \ubcc0\uacbd \uc54c\ub9bc \uc804\uc1a1 +gb.overdue = \uc9c0\uc5f0 +gb.openMilestones = \ub9c8\uc77c\uc2a4\ud1a4 \uc5f4\uae30 +gb.closedMilestones = \ub2eb\ud78c \ub9c8\uc77c\uc2a4\ud1a4 +gb.administration = \uad00\ub9ac +gb.plugins = \ud50c\ub7ec\uadf8\uc778 +gb.extensions = \ud655\uc7a5\uae30\ub2a5 +gb.pleaseSelectProject = \ud504\ub85c\uc81d\ud2b8\ub97c \uc120\ud0dd\ud574 \uc8fc\uc138\uc694! +gb.accessPolicy = \uc811\uadfc \uc815\ucc45 +gb.accessPolicyDescription = \uc800\uc7a5\uc18c \ubcf4\uae30\uc640 git \uad8c\ud55c\uc744 \uc81c\uc5b4\ud558\uae30 \uc704\ud574 \uc811\uadfc \uc815\ucc45\uc744 \uc120\ud0dd\ud558\uc138\uc694. +gb.anonymousPolicy = \uc775\uba85 \ubcf4\uae30, \ud074\ub860 \uadf8\ub9ac\uace0 \ud478\uc2dc +gb.anonymousPolicyDescription = \ub204\uad6c\ub098 \uc774 \uc800\uc7a5\uc18c\ub97c \ubcf4\uae30, \ud074\ub860, \uadf8\ub9ac\uace0 \ud478\uc2dc\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +gb.authenticatedPushPolicy = \uc81c\ud55c\ub41c \ud478\uc2dc (\uc778\uc99d\ub41c) +gb.authenticatedPushPolicyDescription = \ub204\uad6c\ub098 \uc774 \uc800\uc7a5\uc18c\ub97c \ubcf4\uac70\ub098 \ud074\ub860\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \ubaa8\ub4e0 \uc778\uc99d\ub41c \uc720\uc800\ub294 RW+ \ud478\uc2dc \uad8c\ud55c\uc744 \uac00\uc9d1\ub2c8\ub2e4. +gb.namedPushPolicy = \uc774\ub984\uc73c\ub85c \ud478\uc2dc \uc81c\ud55c +gb.namedPushPolicyDescription = \ub204\uad6c\ub098 \uc774 \uc800\uc7a5\uc18c\ub97c \ubcf4\uac70\ub098 \ud074\ub860\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc120\ud0dd\ud55c \uc720\uc800\ub9cc \ud478\uc2dc\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +gb.clonePolicy = \uc81c\ud55c\ub41c \ud074\ub860 & \ud478\uc2dc +gb.clonePolicyDescription = \ub204\uad6c\ub098 \uc774 \uc800\uc7a5\uc18c\ub97c \ubcfc \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc120\ud0dd\ud55c \uc720\uc800\ub9cc \ud074\ub860\uacfc \ud478\uc2dc\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +gb.viewPolicy = \uc81c\ud55c\ub41c \ubcf4\uae30, \ud074\ub860 & \ud478\uc2dc +gb.viewPolicyDescription = \uc120\ud0dd\ud55c \uc720\uc800\ub9cc \uc774 \uc800\uc7a5\uc18c\uc5d0 \ub300\ud574 \ubcf4\uae30, \ud074\ub860 \uadf8\ub9ac\uace0 \ud478\uc2dc \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +gb.initialCommit = \ucd5c\ucd08 \ucee4\ubc0b +gb.initialCommitDescription = \uc774 \uc800\uc7a5\uc18c\ub97c \uc989\uc2dc git clone \ud560 \uc218 \uc788\ub3c4\ub85d \ud569\ub2c8\ub2e4. \ub85c\uceec\uc5d0\uc11c git init \ud588\ub2e4\uba74 \uc774 \ub2e8\uacc4\ub97c \uac74\ub108\ub6f0\uc138\uc694. +gb.initWithReadme = README \ud3ec\ud568 +gb.initWithReadmeDescription = \uc800\uc7a5\uc18c\uc758 \uac04\ub2e8\ud55c README \ubb38\uc11c\ub97c \uc0dd\uc131\ud569\ub2c8\ub2e4. +gb.initWithGitignore = .gitignore \ud30c\uc77c \ud3ec\ud568 +gb.initWithGitignoreDescription = Git \ud074\ub77c\uc774\uc5b8\ud2b8\uac00 \uc815\uc758\ub41c \ud328\ud134\uc5d0 \ub530\ub77c \ud30c\uc77c\uc774\ub098 \ub514\ub809\ud1a0\ub9ac\ub97c \ubb34\uc2dc\ud558\ub3c4\ub85d \uc9c0\uc815\ud55c \uc124\uc815\ud30c\uc77c\uc744 \ucd94\uac00\ud569\ub2c8\ub2e4. +gb.pleaseSelectGitIgnore = .gitignore \ud30c\uc77c\uc744 \uc120\ud0dd\ud558\uc138\uc694. +gb.receive = \uc218\uc2e0 +gb.permissions = \uad8c\ud55c +gb.ownersDescription = \uc18c\uc720\uc790\ub294 \uc800\uc7a5\uc18c\uc758 \ubaa8\ub4e0 \uc124\uc815\uc744 \uad00\ub9ac\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uadf8\ub7ec\ub098, \uac1c\uc778 \uc800\uc7a5\uc18c\ub97c \uc81c\uc678\ud558\uace0\ub294 \uc800\uc7a5\uc18c \uc774\ub984\uc744 \ubcc0\uacbd\ud560 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4. +gb.userPermissionsDescription = \uac1c\ubcc4 \uc0ac\uc6a9\uc790 \uad8c\ud55c\uc744 \uc9c0\uc815\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc774 \uc124\uc815\uc740 \ud300\uc774\ub098 \uc815\uaddc\uc2dd \uad8c\ud55c\uc744 \ubb34\uc2dc\ud569\ub2c8\ub2e4. +gb.teamPermissionsDescription = \uac1c\ubcc4 \ud300 \uad8c\ud55c\uc744 \uc9c0\uc815\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc774 \uc124\uc815\uc740 \uc815\uaddc\uc2dd \uad8c\ud55c\uc744 \ubb34\uc2dc\ud569\ub2c8\ub2e4. +gb.ticketSettings = \ud2f0\ucf13 \uc124\uc815 +gb.receiveSettings = \uc218\uc2e0 \uc124\uc815 +gb.receiveSettingsDescription = \uc218\uc2e0 \uc124\uc815\uc740 \uc800\uc7a5\uc18c\uc5d0 \ud478\uc2dc\ud558\ub294 \uac83\uc744 \uc81c\uc5b4\ud569\ub2c8\ub2e4. +gb.preReceiveDescription = Pre-receive \ud6c5\uc740 \ucee4\ubc0b\uc744 \uc218\uc2e0\ud588\uc9c0\ub9cc, refs \uac00 \uc5c5\ub370\uc774\ud2b8 \ub418\uae30 \uc804 \uc5d0 \uc2e4\ud589\ub429\ub2c8\ub2e4.

    \uc774\uac83\uc740 \ud478\uc2dc\ub97c \uac70\ubd80\ud558\uae30\uc5d0 \uc801\uc808\ud55c \ud6c5 \uc785\ub2c8\ub2e4.

    +gb.postReceiveDescription = Post-receive \ud639\uc740 \ucee4\ubc0b\uc744 \uc218\uc2e0\ud558\uace0, refs \uac00 \uc5c5\ub370\uc774\ud2b8 \ub41c \ud6c4 \uc5d0 \uc2e4\ud589\ub429\ub2c8\ub2e4.

    \uc774\uac83\uc740 \uc54c\ub9bc, \ube4c\ub4dc \ud2b8\ub9ac\uac70 \ub4f1\uc744 \ud558\uae30\uc5d0 \uc801\uc808\ud55c \ud6c5 \uc785\ub2c8\ub2e4.

    +gb.federationStrategyDescription = \ub2e4\ub978 Gitblit \uacfc \ud398\ub354\ub808\uc774\uc158 \ud558\ub294 \ubc29\ubc95\uc744 \uc81c\uc5b4\ud569\ub2c8\ub2e4. +gb.federationSetsDescription = \uc774 \uc800\uc7a5\uc18c\ub294 \uc120\ud0dd\ub41c \ud398\ub354\ub808\uc774\uc158 \uc14b\uc5d0 \ud3ec\ud568\ub429\ub2c8\ub2e4. +gb.miscellaneous = \uae30\ud0c0 +gb.originDescription = \uc774 \uc800\uc7a5\uc18c\uac00 \ud074\ub860\ub41c \uacf3\uc758 url +gb.gc = GC +gb.garbageCollection = \uac00\ube44\uc9c0 \uceec\ub809\uc158 +gb.garbageCollectionDescription = \uac00\ube44\uc9c0 \uceec\ub809\ud130\ub294 \ud074\ub77c\uc774\uc5b8\ud2b8\uc5d0\uc11c \ud478\uc2dc\ud55c \ub290\uc2a8\ud55c \uc624\ube0c\uc81d\ud2b8\ub97c \ud328\ud0b9\ud558\uace0, \uc800\uc7a5\uc18c\uc5d0\uc11c \ucc38\uc870\ud558\uc9c0 \uc54a\ub294 \uc624\ube0c\uc81d\ud2b8\ub97c \uc0ad\uc81c\ud569\ub2c8\ub2e4. +gb.commitMessageRendererDescription = \ucee4\ubc0b \uba54\uc2dc\uc9c0\ub294 \ud3c9\ubb38 \ub610\ub294 \ub9c8\ud06c\uc5c5\uc73c\ub85c \ub80c\ub354\ub9c1\ud558\uc5ec \ud45c\uc2dc\ub420 \uc218 \uc788\uc2b5\ub2c8\ub2e4. +gb.preferences = \uc124\uc815 +gb.accountPreferences = \uacc4\uc815 \uc124\uc815 +gb.accountPreferencesDescription = \uacc4\uc815 \uc124\uc815\uc744 \uc9c0\uc815\ud569\ub2c8\ub2e4. +gb.languagePreference = \uc5b8\uc5b4 \uc124\uc815 +gb.languagePreferenceDescription = \uc120\ud638\ud558\ub294 \uc5b8\uc5b4\ub97c \uc120\ud0dd\ud558\uc138\uc694. +gb.emailMeOnMyTicketChanges = \ub0b4 \ud2f0\ucf13\uc774 \ubcc0\uacbd\ub418\uba74 \uc774\uba54\uc77c\ub85c \uc54c\ub9bc +gb.emailMeOnMyTicketChangesDescription = \ub0b4\uac00 \ub9cc\ub4e0 \ud2f0\ucf13\uc758 \ubcc0\uacbd\ub418\uba74 \ubcc0\uacbd\uc0ac\ud56d\uc744 \ub098\uc758 \uc774\uba54\uc77c\ub85c \uc54c\ub824\uc90c +gb.displayNameDescription = \ud45c\uc2dc\ub420 \uc774\ub984 +gb.emailAddressDescription = \uc54c\ub9bc\uc744 \ubc1b\uae30\uc704\ud55c \uc8fc \uc774\uba54\uc77c +gb.sshKeys = SSH \ud0a4 +gb.sshKeysDescription = SSH \uacf5\uac1c\ud0a4 \uc778\uc99d\uc740 \ud328\uc2a4\uc6cc\ub4dc \uc778\uc99d\uc744 \ub300\uccb4\ud558\ub294 \uc548\uc804\ud55c \ub300\uc548\uc785\ub2c8\ub2e4. +gb.addSshKey = SSH \ud0a4 \ucd94\uac00 +gb.key = \ud0a4 +gb.comment = \uc124\uba85 +gb.sshKeyCommentDescription = \uc0ac\uc6a9\uc790 \uc120\ud0dd\uc778 \uc124\uba85\uc744 \ucd94\uac00\ud558\uc138\uc694. \ube44\uc6cc \ub450\uba74 \ud0a4 \ub370\uc774\ud130\uc5d0\uc11c \ucd94\ucd9c\ud558\uc5ec \ucc44\uc6cc\uc9d1\ub2c8\ub2e4. +gb.permission = \uad8c\ud55c +gb.sshKeyPermissionDescription = SSH \ud0a4\uc758 \uc811\uc18d \uad8c\ud55c\uc744 \uc9c0\uc815\ud558\uc138\uc694. +gb.transportPreference = \uc804\uc1a1 \uc124\uc815 +gb.transportPreferenceDescription = \ud074\ub860\uc2dc \uc0ac\uc6a9\ud560 \uc124\uc815\uc744 \uc9c0\uc815\ud558\uc138\uc694. diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html index 7fbcee13..0ecb54d5 100644 --- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_ko.html @@ -14,41 +14,41 @@
    [repository] 저장소는 비어 있어서 Gitblit ì—서 ë³¼ 수 없습니다.

    - ì´ Git url ì— ì»¤ë°‹í•´ 주세요. + ì´ Git url ì— ì»¤ë°‹ì„ í‘¸ì‹œí•˜ì„¸ìš”.
    - After you have pushed commits you may refresh this page to view your repository. + ì»¤ë°‹ì„ í‘¸ì‹œí•œ 후 ì´ íŽ˜ì´ì§€ë¥¼ 새로고침하면 저장소가 보여질 것입니다.
    -

    Create a new repository on the command-line

    +

    커맨드ë¼ì¸ì—서 새 저장소 ìƒì„±í•˜ê¸°

    
     
    -	

    Push an existing repository from the command-line

    +

    커맨드ë¼ì¸ì—서 ê¸°ì¡´ì˜ ì €ìž¥ì†Œë¥¼ 푸시하기

    
     
     	

    Git 배우기

    만약 ì‚¬ìš©ë²•ì— ìžì‹ ì´ 없다면, Git ì‚¬ìš©ë²•ì„ ë” ìž˜ ì´í•´í•˜ê¸° 위해 - Git Community Book ë˜ëŠ” ì„ ë³¼ ê²ƒì„ ê³ ë ¤í•´ 보세요.

    + Git Community Book ì„ ë³¼ ê²ƒì„ ê³ ë ¤í•´ 보세요.

    -

    오픈소스 Git í´ë¼ì´ì–¸íЏ

    +

    오픈 소스 Git í´ë¼ì´ì–¸íЏ

    - - + +
    Git명령어 기반 ê³µì‹ Git
    TortoiseGit윈ë„ì˜ íŒŒì¼ íƒìƒ‰ê¸°ì— í†µí•©ëœ UI í´ë¼ì´ì–¸íЏ (명령어 기반 ê³µì‹ Git í•„ìš”)
    Eclipse/EGitì´í´ë¦½ìФ IDE í”ŒëŸ¬ê·¸ì¸ (Gitblit ê³¼ ê°™ì€ JGit 기반)
    Git ExtensionsC# frontend for Git that features Windows Explorer and Visual Studio integration
    GitX-deva Mac OS X Git client
    Git Extensionsìœˆë„ íƒìƒ‰ê¸°ì™€ 비주얼스튜디어를 위한 C#으로 ê°œë°œëœ ê¸°ëŠ¥
    GitX-devë§¥ OS X ìš© Git í´ë¼ì´ì–¸íЏ
    -

    유료 Git í´ë¼ì´ì–¸íЏ

    +

    유료/í´ë¡œì¦ˆë“œ 소스 Git í´ë¼ì´ì–¸íЏ

    - - + +
    SmartGit/Hgìžë°” 어플리케ì´ì…˜ (명령어 기반 ê³µì‹ Git í•„ìš”)
    SourceTreeA free Git and Mercurial client for Windows & Mac
    Towera Mac OS X Git client
    SourceTree윈ë„와 ë§¥ì—서 가능한 Git ê³¼ Mercurialìš© 무료 í´ë¼ì´ì–¸íЏ
    Towerë§¥ OS X ìš© Git í´ë¼ì´ì–¸íЏ
    -- cgit v1.2.3 From 2c92d5e415f95e8e9c43df88f93c14aced677e30 Mon Sep 17 00:00:00 2001 From: James Moger Date: Sat, 14 Jun 2014 09:44:48 -0400 Subject: Documentation --- src/site/plugins_overview.mkd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/site/plugins_overview.mkd b/src/site/plugins_overview.mkd index f7872fdb..14192f17 100644 --- a/src/site/plugins_overview.mkd +++ b/src/site/plugins_overview.mkd @@ -53,7 +53,7 @@ Gitblit provides a simple default registry of plugins. The registry is a JSON fi plugins.registry = http://plugins.gitblit.com/plugins.json -The [registry](http://plugins.gitblit.com/plugins.json) is currently hosted in a [Git repository on Github](https://github.com/gitblit/gitblit-registry). This git repository is also a [Maven-compatible repository](http://plugins.gitblit.com), which hosts some plugin binaries. +The [default plugins registry](http://plugins.gitblit.com) is currently hosted in a [Git repository on Github](https://github.com/gitblit/gitblit-registry). You can view the default registry file [here](http://plugins.gitblit.com/plugins.json). The default plugin registry is also a Maven-2 compatible repository. ### Contributing Plugins to the Default Registry -- cgit v1.2.3 From 9ddd993118d06a4bf0cc5057e3f604de9af7b511 Mon Sep 17 00:00:00 2001 From: Jeroen Baten Date: Sat, 14 Jun 2014 20:54:10 +0200 Subject: Dutch translated strings --- .../com/gitblit/wicket/GitBlitWebApp_nl.properties | 90 +++++++++++++++++++--- 1 file changed, 81 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties index c669f3ff..317716a1 100644 --- a/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_nl.properties @@ -221,8 +221,8 @@ gb.query = query gb.queryHelp = Standaard query syntax wordt ondersteund.

    Zie aub Lucene Query Parser Syntax voor informatie. gb.queryResults = resultaten {0} - {1} ({2} hits) gb.noHits = geen hits -gb.authored = authored -gb.committed = committed +gb.authored = geschreven +gb.committed = gecommit gb.indexedBranches = geïndexeerde branches gb.indexedBranchesDescription = kies de branches voor opname in uw Lucene index gb.noIndexedRepositoriesWarning = geen van uw repositories is geconfigureerd voor Lucene indexering @@ -517,7 +517,7 @@ gb.createdThisTicket = maakte deze ticket gb.proposedThisChange = stelde deze wijziging voor gb.uploadedPatchsetN = uploade patchset {0} gb.uploadedPatchsetNRevisionN = uploade patchset {0} revisie {1} -gb.mergedPatchset = merged patchset +gb.mergedPatchset = gemergede patchset gb.commented = becommentarieerde gb.noDescriptionGiven = geen omschrijving gegeven gb.toBranch = naar {0} @@ -534,10 +534,10 @@ gb.compareToMergeBase = vergelijk met merge base gb.compareToN = vergelijk met {0} gb.open = open gb.closed = gesloten -gb.merged = merged +gb.merged = gemerged gb.ticketPatchset = ticket {0}, patchset {1} gb.patchsetMergeable = Deze patchset kan automatisch gemerged worden naar {0}. -gb.patchsetMergeableMore = Deze patchset mag ook gemerged worden naar {0} vanaf de command line. +gb.patchsetMergeableMore = Deze patchset mag ook gemerged worden naar {0} vanaf de commandline. gb.patchsetAlreadyMerged = Deze patchset is gemerged naar {0}. gb.patchsetNotMergeable = Deze patchset kan niet automatisch gemerged worden naar {0}. gb.patchsetNotMergeableMore = Deze patchset moet gerebased of handmatig gemerged worden naar {0} om conflicten op te lossen. @@ -546,7 +546,7 @@ gb.patchsetNotApprovedMore = Een reviewer moet deze patchset goedkeuren. gb.patchsetVetoedMore = Een reviewer heeft een veto uitgesproken over deze patchset. gb.write = write gb.comment = commentaar -gb.preview = preview +gb.preview = voorbeeld gb.leaveComment = plaats een opmerking... gb.showHideDetails = toon/verberg details gb.acceptNewPatchsets = accepteer patchsets @@ -605,12 +605,12 @@ gb.patchset = patchset gb.all = alle gb.mergeBase = merge base gb.checkout = checkout -gb.checkoutViaCommandLine = Checkout via command line +gb.checkoutViaCommandLine = Checkout via commandline gb.checkoutViaCommandLineNote = U kunt deze wijzigingen uitchecken en lokaal testen vanuit uw eigen kopie van deze repositorie. gb.checkoutStep1 = Dowbload the actuele patchset \u2014 run deze vanuit uw eigen projectdirectorie gb.checkoutStep2 = Check de patchset uit naar een nieuwe branch en review hem -gb.mergingViaCommandLine = Mergen via command line -gb.mergingViaCommandLineNote = Als u de merge knop niet wilt gebruiken of een automatische merge niet kan worden uitgevoerd kunt u een handmatige merge op de command line uitvoeren. +gb.mergingViaCommandLine = Mergen via commandline +gb.mergingViaCommandLineNote = Als u de merge knop niet wilt gebruiken of een automatische merge niet kan worden uitgevoerd kunt u een handmatige merge op de commandline uitvoeren. gb.mergeStep1 = Check out een nieuwe branch voor het reviewen van wijzigingen \u2014 run deze vanuit uw eigen projectdirectorie gb.mergeStep2 = Breng de voorgestelde wijzigingen in en review ze gb.mergeStep3 = Merge de voorgestelde wijzigingen en update de server @@ -670,3 +670,75 @@ gb.repositoryDoesNotAcceptPatchsets = Deze repositorie accepteert geen patchsets gb.serverDoesNotAcceptPatchsets = Deze server accepteert geen patchsets. gb.ticketIsClosed = Deze ticket is gesloten. gb.mergeToDescription = default integratie branch voor het mergen van ticket patchsets +gb.anonymousCanNotPropose = Anonieme gebruikers kunnen geen patchsets voorstellen. +gb.youDoNotHaveClonePermission = U heeft geen rechten voor het clonen van deze repositorie. +ggb.myTickets = mijn tickets +gb.yourAssignedTickets = toegewezen aan mij +gb.newMilestone = nieuwe milestone +gb.editMilestone = wijzig milestone +gb.deleteMilestone = Verwijder milestone \"{0}\"? +gb.milestoneDeleteFailed = Milestone verwijdering ''{0}'' niet gelukt! +gb.notifyChangedOpenTickets = verstuur notificatie voor wijziging open tickets +gb.overdue = te laat +gb.openMilestones = open milestones +gb.closedMilestones = gesloten milestones +gb.administration = administratie +gb.plugins = plugins +gb.extensions = extensies +gb.pleaseSelectProject = Kies aub het project! +gb.accessPolicy = Toegangspolicy +gb.accessPolicyDescription = Kies een toegangspolicy voor het managen van de zichtbaarheid van de repositorie en de git toegangsrechten. +gb.anonymousPolicy = Anoniem View, Clone, & Push +gb.anonymousPolicyDescription = Iedereen mag deze repositorie zien, clonen, en er naartoe pushen. +gb.authenticatedPushPolicy = Beperk Push (Geauthenticeerd) +gb.authenticatedPushPolicyDescription = Iedereen kan deze repositorie zien en clonen. Alle geauthenticeerde gebruikers hebben RW+ push permissie. +gb.namedPushPolicy = Beperk Push (Gebruiker bekend) +gb.namedPushPolicyDescription = Iedereen kan deze repositorie zien en clonen. U bepaalt wie er mag pushen. +gb.clonePolicy = Beperk Clone & Push +gb.clonePolicyDescription = Iedereen kan deze repositorie zien. U bepaalt wie er mag clonen en pushen. +gb.viewPolicy = Beperk Zien, Clonen en Push +gb.viewPolicyDescription = U bepaalt wie deze repositorie mag zien, clonen en er naar toe pushen. +gb.initialCommit = Initiele Commit +gb.initialCommitDescription = Dit maakt het u mogelijk om meteen git clone deze repositorie. Sla deze stap over als u al git init lokaal heeft uitgevoerd. +gb.initWithReadme = Voeg een README toe +gb.initWithReadmeDescription = Dit zal een eenvoudige README document toevoegen aan uw repositorie. +gb.initWithGitignore = Voeg een .gitignore bestand toe +gb.initWithGitignoreDescription = Dit zal een configuratiebestand toevoegen dat uw Git programma zal instrueren om bepaalde bestanden of directories die aan bepaalde selectiepatronen voldoen te negeren. +gb.pleaseSelectGitIgnore = Kies aub een .gitignore bestand +gb.receive = ontvang +gb.permissions = permissies +gb.ownersDescription = Eigenaren kunnen alle repositoriesettings managen maar het is niet toegestaan een repositorie te hernoemen tenzij het hun persoonlijke repositorie is. +gb.userPermissionsDescription = U kunt afzonderlijke gebruikerspermissies specificeren. Deze instellingen zullen team- of regexpermisies overrulen. +gb.teamPermissionsDescription = U kunt afzonderlijke teamspermissies specificeren. Deze instellingen zullen regexpermisies overrulen. +gb.ticketSettings = Ticket Instellingen +gb.receiveSettings = Ontvangstinstellingen +gb.receiveSettingsDescription = De Ontvangstinstellingen managen pushes naar de repositorie. +gb.preReceiveDescription = Pre-receive hooks worden uitgevoerd na commits zijn ontvangen maar VOORDAT de refs worden geupdated.

    Dit is de juiste hook voor het afwijzen van een push.

    +gb.postReceiveDescription = Post-receive hooks worden uitgevoerd na commits zijn ontvangen maar NADAT de refs zijn geupdated.

    Dit is de juiste hook voor notificaties, build triggers, etc.

    +gb.federationStrategyDescription = Bepaal of en hoe deze repositorie te federeren met een andere Gitblit. +gb.federationSetsDescription = Deze repository zal worden opgenomen in de geselecteerde federatie sets. +gb.miscellaneous = diversen +gb.originDescription = De url vanaf welke deze repositorie was gecloned. +gb.gc = GC +gb.garbageCollection = Garbage Collection +gb.garbageCollectionDescription = De garbage collector zal losse objecten die gepushed zijn van clients samenvoegen en zal ongereferentieerde objecten uit de repository verwijderen. +gb.commitMessageRendererDescription = Commit meldingen kunnen worden getoond als platte tekst of als gerenderde markup. +gb.preferences = voorkeuren +gb.accountPreferences = Accountvoorkeuren +gb.accountPreferencesDescription = Specificeer uw accountvoorkeuren +gb.languagePreference = Taalvoorkeuren +gb.languagePreferenceDescription = Selecteer uw voorkeursvertaling van voor Gitblit +gb.emailMeOnMyTicketChanges = Email bij ticketwijziging +gb.emailMeOnMyTicketChangesDescription = Stuur me een emailnotificatie voor wijzigingen die ik aanbreng aan een ticket +gb.displayNameDescription = De gewenste naam om te tonen +gb.emailAddressDescription = Het primaire emailadres voor het ontvangen van notificaties +gb.sshKeys = SSH Sleutels +gb.sshKeysDescription = SSH publiekesleutelauthenticatie is een veilig alternatief voor wachtwoordauthenticatie +gb.addSshKey = Voeg SSH Sleutel toe +gb.key = Sleutel +gb.comment = Opmerking +gb.sshKeyCommentDescription = Voeg een optionele opmerking toe. Indien leeg zal de opmerking uit de sleutelgegevens worden gehaald. +gb.permission = Permissie +gb.sshKeyPermissionDescription = Specificeer de toegangsrechten voor de SSH sleutel +gb.transportPreference = Transportvoorkeuren +gb.transportPreferenceDescription = Stel de transportmethode in die u wenst voor het clonen -- cgit v1.2.3 From 88051ff6225abc668759fe385c4f6d692b1b6fd6 Mon Sep 17 00:00:00 2001 From: Jeroen Baten Date: Sun, 15 Jun 2014 12:37:54 +0200 Subject: changed empty repo page --- .../java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html index 84373d20..ab207d1e 100644 --- a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_nl.html @@ -19,11 +19,11 @@ Nadat u een commits gepushed heeft, kunt u deze pagina verversen om uw repository te bekijken.
    -

    Create a new repository on the command-line

    +

    Maak een nieuwe repositorie via de command-line

    
     
    -	

    Push an existing repository from the command-line

    +

    Push een bestaande repositorie vanaf de command-line

    
     
    @@ -31,18 +31,18 @@
     		

    Leer Git

    Als u niet goed weet wat u met deze informatie aan moet, raden we u aan om het Git Community Book te bestuderen voor een beter begrip over hoe u Git kunt gebruiken.

    -

    Open Source Git Clients

    +

    Open Source Git Programma's

    - +
    Gitde officiele, command-line Git
    TortoiseGitWindows bestandsverkenner ingetratie (officiele command-line Git is wel nodig)
    TortoiseGitWindows bestandsverkenner integratie (officiele command-line Git is wel nodig)
    Eclipse/EGitGit voor de Eclipse IDE (gebaseerd op JGit, zoals Gitblit)
    Git ExtensionsC# frontend voor Git met Windows Explorer en Visual Studio integratie
    GitX-deveen Mac OS X Git client
    -

    Commercial/Closed-Source Git Clients

    +

    Commerciele/Closed-Source Git Programma's

    -- cgit v1.2.3 From 4d67e5710ab67160c14d86fb5bddcdd3fd38ef53 Mon Sep 17 00:00:00 2001 From: GianMaria Romanato Date: Sun, 15 Jun 2014 20:58:31 +0200 Subject: Italian translation. When it comes to IT terminology, the Italian language borrows a lot of terms from English, and it is often difficult to decide what is to be translated and what is to be kept in English. I tried to follow the same approach adopted by the translators of the pro-git book, so for example "clone", "push" are not translated, while "branch" is translated (the noun, not the git command). I did my best to try to provide the best possible translation, but I had not enough time to test all translations on screen. Finally I noted that there are some duplicate keys e.g. gb.comment which appears one with a capital C and once with a lowercase C. --- .../com/gitblit/wicket/GitBlitWebApp_it.properties | 745 +++++++++++++++++++++ .../wicket/pages/EmptyRepositoryPage_it.html | 60 ++ src/main/java/login_it.mkd | 4 + src/main/java/welcome_it.mkd | 3 + 4 files changed, 812 insertions(+) create mode 100644 src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties create mode 100644 src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_it.html create mode 100644 src/main/java/login_it.mkd create mode 100644 src/main/java/welcome_it.mkd diff --git a/src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties b/src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties new file mode 100644 index 00000000..7230ec83 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/GitBlitWebApp_it.properties @@ -0,0 +1,745 @@ +gb.repository = repository +gb.owner = proprietario +gb.description = descrizione +gb.lastChange = ultima modifica +gb.refs = refs +gb.tag = tag +gb.tags = tags +gb.author = autore +gb.committer = committer +gb.commit = commit +gb.age = età +gb.tree = albero +gb.parent = padre +gb.url = URL +gb.history = cronologia +gb.raw = originale +gb.object = oggetto +gb.ticketId = id del ticket +gb.ticketAssigned = assegnato +gb.ticketOpenDate = data di apertura +gb.ticketStatus = stato +gb.ticketComments = commenti +gb.view = vista +gb.local = locale +gb.remote = remoto +gb.branches = rami +gb.patch = patch +gb.diff = differenze +gb.log = log +gb.moreLogs = ulteriori commits... +gb.allTags = tutte le tags... +gb.allBranches = tutti i rami... +gb.summary = riassunto +gb.ticket = ticket +gb.newRepository = nuovo repository +gb.newUser = nuovo utente +gb.commitdiff = differenze di commit +gb.tickets = elenco ticket +gb.pageFirst = prima +gb.pagePrevious = prec +gb.pageNext = succ +gb.head = HEAD +gb.blame = annotazioni +gb.login = login +gb.logout = logout +gb.username = nome utente +gb.password = password +gb.tagger = autore della tag +gb.moreHistory = ulteriore cronoligia... +gb.difftocurrent = differenze con il corrente +gb.search = ricerca +gb.searchForAuthor = Ricerca commit per autore +gb.searchForCommitter = Ricerca commit per committer +gb.addition = aggiunta +gb.modification = modifica +gb.deletion = cancellazione +gb.rename = rinomina +gb.metrics = metriche +gb.stats = statistiche +gb.markdown = markdown +gb.changedFiles = file modificati +gb.filesAdded = {0} file aggiunti +gb.filesModified = {0} file modificati +gb.filesDeleted = {0} file cancellati +gb.filesCopied = {0} file copiati +gb.filesRenamed = {0} file rinominati +gb.missingUsername = Nome Utente Mancante +gb.edit = modifica +gb.searchTypeTooltip = Seleziona tipo di ricerca +gb.searchTooltip = Ricerca {0} +gb.delete = cancella +gb.docs = documentazione +gb.accessRestriction = restrizioni di accesso +gb.name = nome +gb.enableTickets = abilita supporto ticket +gb.enableDocs = abilita documentazione +gb.save = salva +gb.showRemoteBranches = mostra i rami remoti +gb.editUsers = modifica utenti +gb.confirmPassword = conferma password +gb.restrictedRepositories = repository con restrizioni di accesso +gb.canAdmin = controllo completo +gb.notRestricted = visualizzazione, clone e push anonimi +gb.pushRestricted = push previa autenticazione +gb.cloneRestricted = clone e push previa autenticazione +gb.viewRestricted = visualizzazione, clone e push previa autenticazione +gb.useTicketsDescription = segnalazioni Ticgit distribuite (sola lettura) +gb.useDocsDescription = elenca la documentazione Markdown nel repository +gb.showRemoteBranchesDescription = mostra rami remoti +gb.canAdminDescription = può amministrare il server Gitblit +gb.permittedUsers = utenti autorizzati +gb.isFrozen = sola lettura +gb.isFrozenDescription = operazioni di push vietate +gb.zip = zip +gb.showReadme = mostra readme +gb.showReadmeDescription = mostra un file \"readme\" in formato Markdown nella pagina riassuntiva +gb.nameDescription = utilizza '/' per raggruppare i repository. p.e. libraries/mycoollib.git +gb.ownerDescription = il proprietario può modificare le impostazioni del repository +gb.blob = blob +gb.commitActivityTrend = tendenza dell'attività di commit +gb.commitActivityDOW = commit per giorno della settimana +gb.commitActivityAuthors = autori principali sulla base dei commit +gb.feed = feed +gb.cancel = annulla +gb.changePassword = cambia password +gb.isFederated = federato +gb.federateThis = attiva federazione su questo repository +gb.federateOrigin = attiva federazione su origin +gb.excludeFromFederation = escludi dalla federazione +gb.excludeFromFederationDescription = impedisci a istanze federate di Gitblit di effettuare il pull su questo utente +gb.tokens = gettoni di federazione +gb.tokenAllDescription = tutti i repository, utenti e impostazioni +gb.tokenUnrDescription = tutti i repository e gli utenti +gb.tokenJurDescription = tutti i repository +gb.federatedRepositoryDefinitions = definizione dei repository +gb.federatedUserDefinitions = definizione degli utenti +gb.federatedSettingDefinitions = definizione delle impostazioni +gb.proposals = proposta di federazione +gb.received = ricevuta +gb.type = tipo +gb.token = gettone +gb.repositories = repository +gb.proposal = proposta +gb.frequency = frequenza +gb.folder = cartella +gb.lastPull = ultimo pull +gb.nextPull = prossimo pull +gb.inclusions = inclusioni +gb.exclusions = esclusioni +gb.registration = registrazione +gb.registrations = registrationi di federazione +gb.sendProposal = proponi +gb.status = stato +gb.origin = origin +gb.headRef = ramo predefinito (HEAD) +gb.headRefDescription = Il ramo predefinito soggetto a clone e visualizzato nella pagina riassuntiva +gb.federationStrategy = strategia di federazione +gb.federationRegistration = registrazione di federazione +gb.federationResults = risultati di pull federato +gb.federationSets = insiemi di federazione +gb.message = messaggio +gb.myUrlDescription = URL pubblico alla tua istanza Gitblit +gb.destinationUrl = invia a +gb.destinationUrlDescription = URL dell'istanza Gitblit a cui inviare la proposta +gb.users = utenti +gb.federation = federazione +gb.error = errore +gb.refresh = aggiorna +gb.browse = sfoglia +gb.clone = clona +gb.filter = filtra +gb.create = crea +gb.servers = server +gb.recent = recenti +gb.available = disponibile +gb.selected = selezionato +gb.size = dimensione +gb.downloading = download in corso +gb.loading = caricamento +gb.starting = avvio +gb.general = generale +gb.settings = impostazioni +gb.manage = gestisci +gb.lastLogin = ultimo login +gb.skipSizeCalculation = non computare le dimensioni +gb.skipSizeCalculationDescription = disabilita la computazione delle dimensioni del repository (velocizza caricamento pagine) +gb.skipSummaryMetrics = ometti il riassunto delle metriche +gb.skipSummaryMetricsDescription = non calcolare le metriche nella pagina riassuntiva (velocizza caricamento pagine) +gb.accessLevel = livello di access +gb.default = predefinito +gb.setDefault = imposta predefinito +gb.since = da +gb.status = stato +gb.bootDate = data di avvio del server +gb.servletContainer = servlet container +gb.heapMaximum = memoria massima +gb.heapAllocated = memoria allocata +gb.heapUsed = memoria utilizzata +gb.free = libero +gb.version = versione +gb.releaseDate = data di rilascio +gb.date = data +gb.activity = attività +gb.subscribe = sottoscrivi +gb.branch = ramo +gb.maxHits = max hits +gb.recentActivity = attività recenti +gb.recentActivityStats = ultimi {0} giorni / {1} commit da {2} autori +gb.recentActivityNone = ultimi {0} giorni / nessuno +gb.dailyActivity = attività giornaliera +gb.activeRepositories = repository attivi +gb.activeAuthors = autori attivi +gb.commits = commit +gb.teams = gruppi +gb.teamName = nome del gruppo +gb.teamMembers = membry del gruppo +gb.teamMemberships = appartenenza al gruppo +gb.newTeam = nuovo gruppo +gb.permittedTeams = gruppi autorizzati +gb.emptyRepository = repository vuoto +gb.repositoryUrl = repository URL +gb.mailingLists = liste di corrispondenza +gb.preReceiveScripts = script eseguiti su pre-receive +gb.postReceiveScripts = script eseguiti su post-receive +gb.hookScripts = script eseguiti su hook di git +gb.customFields = campi peronalizzati +gb.customFieldsDescription = campi personalizzati accessibili a hook scritti in Groovy +gb.accessPermissions = permessi di accesso +gb.filters = filtri +gb.generalDescription = impostazioni comuni +gb.accessPermissionsDescription = riduci l'accesso in base a utenti e gruppi +gb.accessPermissionsForUserDescription = imposta appartenenza a un gruppo o abilita accesso a repository soggetti a restrizioni +gb.accessPermissionsForTeamDescription = imposta i membri di un gruppo e abilita accesso a repository soggetti a restrizioni +gb.federationRepositoryDescription = condividi questo repository con altre istanze Gitblit +gb.hookScriptsDescription = esegue script Groovy quando viene effettuato un push su questo server +gb.reset = reimposta +gb.pages = pagine +gb.workingCopy = copia di lavoro +gb.workingCopyWarning = questo repository è una copia di lavoro a non ammette push +gb.query = interrogazione +gb.queryHelp = La sintassi standard è supportata.

    Si vedi Lucene Query Parser Syntax per ulteriori dettagli. +gb.queryResults = risultati {0} - {1} ({2} corrispondenze) +gb.noHits = nessuna corrispondenza +gb.authored = creato da +gb.committed = commit di +gb.indexedBranches = Rami Indicizzati +gb.indexedBranchesDescription = Seleziona i rami che devono essere indicizzati tramite Lucene +gb.noIndexedRepositoriesWarning = nessun repository è soggetto a indicizzazione Lucene +gb.undefinedQueryWarning = interrogazione non specificata! +gb.noSelectedRepositoriesWarning = per favore specifica uno o più repository! +gb.luceneDisabled = Indicizzazione tramite Lucene disabilitata +gb.failedtoRead = Errore di lettura +gb.isNotValidFile = non è un file valido +gb.failedToReadMessage = Errore nella lettura del messaggio da {0}! +gb.passwordsDoNotMatch = La password non corissponde! +gb.passwordTooShort = La password è troppo corta. La lunghezza minima è {0} caratteri. +gb.passwordChanged = Password modificata con successo. +gb.passwordChangeAborted = Modifica della password annullata. +gb.pleaseSetRepositoryName = Specificare il nome del repository! +gb.illegalLeadingSlash = Riferiementi alla cartella principale (/) non sono ammessi. +gb.illegalRelativeSlash = Riferimenti relativi a cartelle (../) non sono ammessi. +gb.illegalCharacterRepositoryName = Carattere non consetito ''{0}'' nel nome del repository! +gb.selectAccessRestriction = Restrizioni di accesso non specificate! +gb.selectFederationStrategy = Strategia di federazione non selezionata! +gb.pleaseSetTeamName = Nome del gruppo non specificato! +gb.teamNameUnavailable = Il nome di gruppo ''{0}'' non è disponibile. +gb.teamMustSpecifyRepository = Un gruppo deve specificare almeno un repository. +gb.teamCreated = Nuovo gruppo ''{0}'' creato con successo. +gb.pleaseSetUsername = Nome utente non specificato! +gb.usernameUnavailable = Il nome utente ''{0}'' non è disponibile. +gb.combinedMd5Rename = Gitblit è configurato per effettuare un hashing delle password di tipo combinato-md5. E' quindi necessario specificare una nuova password quando si rinomina un utenza. +gb.userCreated = Nuovo utente ''{0}'' creato con successo. +gb.couldNotFindFederationRegistration = Impossibile trovare la registrazione di federazione! +gb.failedToFindGravatarProfile = Profilo Gravatar per {0} non reperito! +gb.branchStats = {2} contiene {0} commit e {1} tag +gb.repositoryNotSpecified = Repository non specificato! +gb.repositoryNotSpecifiedFor = Repository non specificato per {0}! +gb.canNotLoadRepository = Impossibile leggere il repository +gb.commitIsNull = Commit nullo +gb.unauthorizedAccessForRepository = Accesso al repository non autorizzato +gb.failedToFindCommit = Cmmit \"{0}\" non trovato in {1}! +gb.couldNotFindFederationProposal = Impossibile trovare la proposta di federazione! +gb.invalidUsernameOrPassword = Nome utente o password non validi! +gb.OneProposalToReview = 1 proposta di federazione è in attesa di valutazione. +gb.nFederationProposalsToReview = Ci sono {0} proposte di federazione in attesa di valutazione +gb.couldNotFindTag = Tag non trovata {0} +gb.couldNotCreateFederationProposal = Impossibile creare proposta di federazione! +gb.pleaseSetGitblitUrl = Gitblit URL non specificato! +gb.pleaseSetDestinationUrl = URL di destinazione non specificato! +gb.proposalReceived = Proposta ricevuta da {0} con successo. +gb.noGitblitFound = {0} non ha potuto trovare una istanza di Gitblit presso {1}. +gb.noProposals = {0} al momento non accetta proposte. +gb.noFederation = {0} non è configurato per creare una federazione con altre istanze Gitblit. +gb.proposalFailed = {0} non ha ricevuto alcuna proposta di federazione! +gb.proposalError = {0} segnala un errore inatteso! +gb.failedToSendProposal = Invio proposta fallito! +gb.userServiceDoesNotPermitAddUser = {0} non consete di aggiungere nuovi utenti! +gb.userServiceDoesNotPermitPasswordChanges = {0} non consente di cambiare la password! +gb.displayName = nome pubblico +gb.emailAddress = indirizzo email +gb.errorAdminLoginRequired = Effettuare l'accesso per utilizzare le funzioni amministrative +gb.errorOnlyAdminMayCreateRepository = Solo un utente amministratore può creare repository +gb.errorOnlyAdminOrOwnerMayEditRepository = Solo un utente amministratore e il proprietario possono modificare un repository +gb.errorAdministrationDisabled = Funzioni amministrative disabilitate +gb.lastNDays = Ultimi {0} giorni +gb.completeGravatarProfile = Completa il profilo su Gravatar.com +gb.none = nessuno +gb.line = linea +gb.content = contenuto +gb.empty = vuoto +gb.inherited = ereditato +gb.deleteRepository = Cancellare il repository \"{0}\"? +gb.repositoryDeleted = Repository ''{0}'' cancellato. +gb.repositoryDeleteFailed = Impossible cancellare il repository ''{0}''! +gb.deleteUser = Cancellare l'utente \"{0}\"? +gb.userDeleted = Utente ''{0}'' cancellato. +gb.userDeleteFailed = Impossibile cancellare l'utente ''{0}''! +gb.time.justNow = in questo istante +gb.time.today = oggi +gb.time.yesterday = ieri +gb.time.minsAgo = {0} minuti fa +gb.time.hoursAgo = {0} ore fa +gb.time.daysAgo = {0} giorni fa +gb.time.weeksAgo = {0} settimane fa +gb.time.monthsAgo = {0} mese fa +gb.time.oneYearAgo = 1 anno fa +gb.time.yearsAgo = {0} anni fa +gb.duration.oneDay = 1 giorno +gb.duration.days = {0} giorni +gb.duration.oneMonth = 1 mese +gb.duration.months = {0} mesi +gb.duration.oneYear = 1 anno +gb.duration.years = {0} anni +gb.authorizationControl = Controlli di autorizzazine +gb.allowAuthenticatedDescription = Consenti lettura/scrittura a tutti gli utenti registrati +gb.allowNamedDescription = Configura permessi specifici per utenti e gruppi +gb.markdownFailure = Impossibile leggere contenuto Markdown! +gb.clearCache = pulisci la cache +gb.projects = progetti +gb.project = progetto +gb.allProjects = tutti i progetti +gb.copyToClipboard = copia negli appunti +gb.fork = ramificazione +gb.forks = ramificazioni +gb.forkRepository = crea una ramificazione {0}? +gb.repositoryForked = ramificazione creata per {0} +gb.repositoryForkFailed= ramificazione fallita +gb.personalRepositories = repository personali +gb.allowForks = consenti ramificazioni +gb.allowForksDescription = consenti agli utenti autorizzati di creare ramificazioni di questo repository +gb.forkedFrom = ramificazione di +gb.canFork = creare ramificazioni +gb.canForkDescription = può creare una ramificazione personale a partire da un repository cui ha accesso +gb.myFork = vedere le mie ramificazioni +gb.forksProhibited = ramificazioni vietate +gb.forksProhibitedWarning = questo repository non ammette ramificazioni +gb.noForks = {0} non ha ramificazioni +gb.forkNotAuthorized = non sei autorizzato a crare una ramificazione di {0} +gb.forkInProgress = ramificazione in corso +gb.preparingFork = ramificazione in preparazione... +gb.isFork = è una ramificazione +gb.canCreate = può creare +gb.canCreateDescription = può creare repository personali +gb.illegalPersonalRepositoryLocation = i tuoi repository personali devono trovarsi \"{0}\" +gb.verifyCommitter = verifica committer +gb.verifyCommitterDescription = controlla che l'identità del committer corrisponda all'utente Gitblit di push +gb.verifyCommitterNote = tutti i merge richiedono "--no-ff" per verificare l'identità del committer +gb.repositoryPermissions = permessi di repository +gb.userPermissions = permessi di utente +gb.teamPermissions = permessi di gruppo +gb.add = aggiungi +gb.noPermission = CANCELLA QUESTO PERMESSO +gb.excludePermission = {0} (esclude) +gb.viewPermission = {0} (visualizza) +gb.clonePermission = {0} (clone) +gb.pushPermission = {0} (push) +gb.createPermission = {0} (push, crea refs) +gb.deletePermission = {0} (push, crea e cancella refs) +gb.rewindPermission = {0} (push, crea cancella e riavvolge ref) +gb.permission = permesso +gb.regexPermission = questo permesso è assegnato tramite espressione regolare \"{0}\" +gb.accessDenied = accesso negato +gb.busyCollectingGarbage = Gitblit sta eseguendo manutenzione su {0} +gb.gcPeriod = Intervallo di GC +gb.gcPeriodDescription = Intervallo di tempo tra un GC e il successivo +gb.gcThreshold = soglia di GC +gb.gcThresholdDescription = soglia minima di oggetti eliminabili che innesca un GC (garbage collection) anticipato +gb.ownerPermission = proprietario del repository +gb.administrator = amministratore +gb.administratorPermission = amministratore di Gitblit +gb.team = gruppo +gb.teamPermission = permesso ottenuto attraverso l'appartenenza al gruppo \"{0}\" +gb.missing = mancante! +gb.missingPermission = il repository per questo permesso è mancante! +gb.mutable = mutabile +gb.specified = specificato +gb.effective = effettivo +gb.organizationalUnit = unità organizzativa +gb.organization = organizzazione +gb.locality = località +gb.stateProvince = stato o provincia +gb.countryCode = codice nazione +gb.properties = proprietà +gb.issued = segnalato +gb.expires = scade +gb.expired = scaduto +gb.expiring = in scadenza +gb.revoked = revocato +gb.serialNumber = numero di serie +gb.certificates = certificati +gb.newCertificate = nuovo certificato +gb.revokeCertificate = revoca certificato +gb.sendEmail = spedisci email +gb.passwordHint = domanda di sicurezza +gb.ok = ok +gb.invalidExpirationDate = data di scadenza invalida! +gb.passwordHintRequired = la domanda di sicurezza è obbligatoria! +gb.viewCertificate = vedi certificato +gb.subject = soggetto +gb.issuer = emesso da +gb.validFrom = valid dal +gb.validUntil = valido fino al +gb.publicKey = chiave pubblica +gb.signatureAlgorithm = algoritml di firma +gb.sha1FingerPrint = firma SHA-1 +gb.md5FingerPrint = firma MD5 +gb.reason = motivazione +gb.revokeCertificateReason = Per favore selezionare una motivazione per la revoca del certificato +gb.unspecified = non specificata +gb.keyCompromise = chiave compromessa +gb.caCompromise = CA compromessa +gb.affiliationChanged = cambio di affiliazione +gb.superseded = obsoleto +gb.cessationOfOperation = cessata attività +gb.privilegeWithdrawn = privilegio rimosso +gb.time.inMinutes = in {0} minuti +gb.time.inHours = in {0} ore +gb.time.inDays = in {0} giorni +gb.hostname = nome host +gb.hostnameRequired = Per favore specificare un nome host +gb.newSSLCertificate = nuovo certificato SSL per il server +gb.newCertificateDefaults = nuovi valori predefiniti del certificato +gb.duration = durata +gb.certificateRevoked = Il certificato {0,number,0} è stato revocato +gb.clientCertificateGenerated = Nuovo certificato client generato con successo per {0} +gb.sslCertificateGenerated = Nuovo certificato SSL server generato con successo per {0} +gb.newClientCertificateMessage = NOTA:\nLa 'password' non è la password dell'utente, bensì la password per il portachiavi (keystore). Questa password non è salvata, perciò è necessario specificare una domanda di sicurezza che sarà inclusa nelle istruzioni per l'utente (README) +gb.certificate = certificato +gb.emailCertificateBundle = invia in email il pacchetto del certificato +gb.pleaseGenerateClientCertificate = Per favore generare un certificato client per {0} +gb.clientCertificateBundleSent = Il pacchetto contente il certificato client per {0} è stato spedito +gb.enterKeystorePassword = Per favore digita la password per il portachiavi di Gitblit (keystore) +gb.warning = attenzione +gb.jceWarning = Il runtime Java in use non contiene i files \"JCE Unlimited Strength Jurisdiction Policy\".\nQuesto limita la lunghezza della password del portachiavi a 7 caratteri.\nI file mancanti possono essere scaricati dal sito Oracle.\n\nVuoi continuare e generare il certificato comunque?\n\nSe rispondi No il tuo browser verrà redirezionato alla pagina di download di Oracle. +gb.maxActivityCommits = numero di commit nella pagina attività +gb.maxActivityCommitsDescription = numero massimo di commit da visualizzare nella pagina attività +gb.noMaximum = nessun limite +gb.attributes = attributi +gb.serveCertificate = utilizza questo certificato per HTTPS +gb.sslCertificateGeneratedRestart = Certificato SSL server generato con successo per {0}.\nE' necessario riavviare Gitblit per utilizzare il nuovo certificato.\n\nSe l'applicazione à avviata con il parametro '--alias', sarà necesario impostare tale parametro a ''--alias {0}''. +gb.validity = validità +gb.siteName = nome del sito +gb.siteNameDescription = nome breve del server +gb.excludeFromActivity = escludi dalla pagina riassuntiva delle attività +gb.isSparkleshared = il repository si trova una cartella Sparkleshare +gb.owners = proprietari +gb.sessionEnded = La sessione è terminata +gb.closeBrowser = Chiudere il browser per terminare correttamente la sessione. +gb.doesNotExistInTree = {0} non esiste nell'albero {1} +gb.enableIncrementalPushTags = abilita push incrementale di tag +gb.useIncrementalPushTagsDescription = A seguito di un push, crea automaticamente una etichetta in cima ad ogni ramificazione utilizzando un numero incrementale +gb.incrementalPushTagMessage = Nuova auto-etichetta su ramificazione [{0}] a seguito di push +gb.externalPermissions = {0} i permessi di accesso sono gestiti su un sistema esterno +gb.viewAccess = Non hai accesso in lettura o scrittura su Gitblit +gb.overview = riassunto +gb.dashboard = cruscotto +gb.monthlyActivity = attività mensile +gb.myProfile = il mio profilo +gb.compare = confronta +gb.manual = manuale +gb.from = da +gb.to = a +gb.at = al +gb.of = di +gb.in = in +gb.moreChanges = tutti i cambiamenti... +gb.pushedNCommitsTo = ha effettuato il push di {0} nuovi commit +gb.pushedOneCommitTo = ha effettuato il push di 1 nuovo commit +gb.commitsTo = {0} crea commits su +gb.oneCommitTo = 1 commit su +gb.byNAuthors = da {0} authori +gb.byOneAuthor = da {0} +gb.viewComparison = confronta qeusti {0} commit \u00bb +gb.nMoreCommits = {0} altri commit \u00bb +gb.oneMoreCommit = 1 altro commit \u00bb +gb.pushedNewTag = ha effettuato il push di una nuova tag +gb.createdNewTag = ha creato una nuova tag +gb.deletedTag = ha cancellato una tag +gb.pushedNewBranch = ha effettuato il push di una ramificazione +gb.createdNewBranch = ha creato una nuova ramificazione +gb.deletedBranch = ha cancellato una ramificazione +gb.createdNewPullRequest = ha creato una richiesta di pull +gb.mergedPullRequest = ha eseguito il merge di una richiesta di pull +gb.rewind = RIAVVOLGERE +gb.star = aggiungi stella +gb.unstar = togli stella +gb.stargazers = astronomi +gb.starredRepositories = repository stellati +gb.failedToUpdateUser = Aggiornamento utente fallito! +gb.myRepositories = I miei repository +gb.noActivity = nessuna attività negli ultimi {0} giorni +gb.findSomeRepositories = trova repository +gb.metricAuthorExclusions = Esclusione autori dalle metriche +gb.myDashboard = il mio cruscotto +gb.failedToFindAccount = utente non trovato ''{0}'' +gb.reflog = reflog +gb.active = attivo +gb.starred = stellato +gb.owned = posseduto +gb.starredAndOwned = stellato e posseduto +gb.reviewPatchset = revisione di {0} insiemi di patch {1} +gb.todaysActivityStats = oggi / {1} commit da {2} autori +gb.todaysActivityNone = oggi / nessuno +gb.noActivityToday = nessuna attività oggi +gb.anonymousUser= anonimo +gb.commitMessageRenderer = visualizzatore messaggio di commit +gb.diffStat = {0} aggiunte & {1} cancellazioni +gb.home = home +gb.isMirror = questo repository è uno specchio +gb.mirrorOf = specchio di {0} +gb.mirrorWarning = questo repository è uno specchio e non ammette push +gb.docsWelcome1 = Puoi usare file per documentare il tuo repository +gb.docsWelcome2 = Crea un file README.md o HOME.md per cominciare. +gb.createReadme = crea un README +gb.responsible = responsabile +gb.createdThisTicket = ha creato questo ticket +gb.proposedThisChange = ha proposto questo cambiamento +gb.uploadedPatchsetN = ha fatto l'upload di una patch {0} +gb.uploadedPatchsetNRevisionN = ha aggiornato la patch {0} alla revisione {1} +gb.mergedPatchset = ha effettuato il merge di una patch +gb.commented = ha commentato +gb.noDescriptionGiven = nessuna descrizione +gb.toBranch = a {0} +gb.createdBy = creato da +gb.oneParticipant = {0} partecipante +gb.nParticipants = {0} partecipanti +gb.noComments = nessun comment +gb.oneComment = {0} commento +gb.nComments = {0} commenti +gb.oneAttachment = {0} allegato +gb.nAttachments = {0} allegati +gb.milestone = milestone +gb.compareToMergeBase = confronta con la base di merge +gb.compareToN = confronta con {0} +gb.open = aperto +gb.closed = chiuso +gb.merged = merge effettuato +gb.ticketPatchset = ticket {0}, patch {1} +gb.patchsetMergeable = Questa patch può essere sottoposta a merge automatico con {0}. +gb.patchsetMergeableMore = Questa patch può anche sottoposta a merge con {0} dalla riga di comando. +gb.patchsetAlreadyMerged = Questa patch è stata sottoposta a merge con {0}. +gb.patchsetNotMergeable = Non è possibile effettuare il merge automatico di questa patch con {0}. +gb.patchsetNotMergeableMore = Questa patch necessita di rebase o merge manuale con {0} per risolvere i conflitti. +gb.patchsetNotApproved = La revisione di questa patch non à stata approvata per il merge con {0}. +gb.patchsetNotApprovedMore = Questa patch richiede approvazione da parte di un revisore. +gb.patchsetVetoedMore = Un revisore ha rifiutato questa patch. +gb.write = scrittura +gb.comment = commento +gb.preview = anteprima +gb.leaveComment = lascia un commento... +gb.showHideDetails = mostra/nascondi dettagli +gb.acceptNewPatchsets = accetta patch +gb.acceptNewPatchsetsDescription = accetta patch per questo repository +gb.acceptNewTickets = consenti nuovi ticket +gb.acceptNewTicketsDescription = consente la creazione di ticket per difetti, migliorie, attività, etc +gb.requireApproval = approvazione richiesta +gb.requireApprovalDescription = le patch devono essere approvate affinchè il bottone merge venga abilitato +gb.topic = argomento +gb.proposalTickets = cambiamenti proposti +gb.bugTickets = difetti +gb.enhancementTickets = migliorie +gb.taskTickets = attività +gb.questionTickets = domande +gb.requestTickets = migliorie e attività +gb.yourCreatedTickets = create da te +gb.yourWatchedTickets = osservate da te +gb.mentionsMeTickets = in cui sei menzionato +gb.updatedBy = aggiornate da +gb.sort = ordina +gb.sortNewest = più nuovi +gb.sortOldest = più vecchi +gb.sortMostRecentlyUpdated = aggiornati più di recente +gb.sortLeastRecentlyUpdated = aggiornati meno di recente +gb.sortMostComments = più commenti +gb.sortLeastComments = meno commenti +gb.sortMostPatchsetRevisions = patch con più revisioni +gb.sortLeastPatchsetRevisions = patch con meno revisioni +gb.sortMostVotes = più votati +gb.sortLeastVotes = meno votati +gb.topicsAndLabels = argomenti ed etichette +gb.milestones = milestone +gb.noMilestoneSelected = nessuna milestone selezionata +gb.notSpecified = non specificato +gb.due = entro +gb.queries = interrogazioni +gb.searchTicketsTooltip = ricerca {0} ticket +gb.searchTickets = ricerca ticket +gb.new = nuovo +gb.newTicket = nuovo ticket +gb.editTicket = modifica ticket +gb.ticketsWelcome = Puoi usare i ticket per creare una lista di cose da fare, discutere i difetti o collaborare su patch. +gb.createFirstTicket = Crea il tuo primo ticket +gb.title = Titolo +gb.changedStatus = ha cambibato lo stato +gb.discussion = discussione +gb.updated = aggiornato +gb.proposePatchset = proponi una patch +gb.proposePatchsetNote = Sei il benvenuto nel proporre una patch per questo ticket. +gb.proposeInstructions = Per iniziare, crea una patch e fanne l'upload con Git. Gitblit collegerà la tua patch a questo ticket per id. +gb.proposeWith = Proponi una patch con {0} +gb.revisionHistory = cronologia revisioni +gb.merge = merge +gb.action = azione +gb.patchset = patch +gb.all = all +gb.mergeBase = base di merge +gb.checkout = checkout +gb.checkoutViaCommandLine = Checkout da riga di comando +gb.checkoutViaCommandLineNote = Puoi effettuare il checkout e testare questi cambiamenti localmente tramite il tuo clone di questo repository. +gb.checkoutStep1 = Esegui il fetch della patch corrente \u2014 esegui questo dalla tua cartella di progetto +gb.checkoutStep2 = Esegui il checkout della patch in una nuova ramificazione e revisione +gb.mergingViaCommandLine = Esecuzione del merge via command line +gb.mergingViaCommandLineNote = Se non vuoi utilizzare il bottone di merge, oppure il merge automatico non è possibile, puoi eseguire il merge manuale da riga di comando. +gb.mergeStep1 = Esegui il checkout di un nuovo branch per esaminare i cambiamenti \u2014 esegui questo dalla tua cartella di progetto +gb.mergeStep2 = Apporta i cambiamenti proposti ed esegui la revisione +gb.mergeStep3 = Effettua il merge dei cambiamenti proposti e poi aggiorna il server +gb.download = download +gb.ptDescription = strumento di Gitblit per le patch +gb.ptCheckout = Esegui il fetch e il checkout della patch corrente in una nuova ramificazione per la revisione +gb.ptMerge = Esegui il fetch e il checkout della patch corrente in una tua ramificazione locale +gb.ptDescription1 = Barnum è un accessorio a riga di comando per Git che semplifica la sintassi per lavorare con i ticket Gitblit e le patch +gb.ptSimplifiedCollaboration = sintassi semplificata di collaborazione +gb.ptSimplifiedMerge = sintassi semplificata di merge +gb.ptDescription2 = Barnum richiede Python 3 e il client Git nativo. Funziona su Windows, Linux, and Mac OS X. +gb.stepN = Passo {0} +gb.watchers = osservatori +gb.votes = voti +gb.vote = vota per questo {0} +gb.watch = osserva questo {0} +gb.removeVote = annulla voto +gb.stopWatching = non osservare più +gb.watching = osservati +gb.comments = commenti +gb.addComment = aggiungi un commento +gb.export = esporta +gb.oneCommit = un commit +gb.nCommits = {0} commit +gb.addedOneCommit = aggiunto 1 commit +gb.addedNCommits = aggiunti {0} commit +gb.commitsInPatchsetN = commit nella pactch {0} +gb.patchsetN = patch {0} +gb.reviewedPatchsetRev = patch analizzata {0} revisione {1}: {2} +gb.review = revisione +gb.reviews = revisioni +gb.veto = veto +gb.needsImprovement = da migliorare +gb.looksGood = sembra buona +gb.approve = approvata +gb.hasNotReviewed = non analizzata +gb.about = a proposito di +gb.ticketN = ticket #{0} +gb.disableUser = disabilita utente +gb.disableUserDescription = blocca l'utente impedendone l'autenticazione +gb.any = qualsiasi +gb.milestoneProgress = {0} aperti, {1} chiusi +gb.nOpenTickets = {0} aperti +gb.nClosedTickets = {0} chiusi +gb.nTotalTickets = {0} totali +gb.body = corpo +gb.mergeSha = SHA del merge +gb.mergeTo = merge con +gb.labels = etichette +gb.reviewers = revisori +gb.voters = votanti +gb.mentions = menzioni +gb.canNotProposePatchset = patch non accettate +gb.repositoryIsMirror = Questo repository è uno specchio di sola lettura. +gb.repositoryIsFrozen = Questo repository è congelato. +gb.repositoryDoesNotAcceptPatchsets = Questo repository non ammette patch. +gb.serverDoesNotAcceptPatchsets = Questo server non ammette patch. +gb.ticketIsClosed = Questo ticket è chiuso. +gb.mergeToDescription = ramificazione di integrazione per il merge di patch per ticket +gb.anonymousCanNotPropose = Utenti anonimi non possono proporre patch. +gb.youDoNotHaveClonePermission = Non hai i diritti per effettuare il clone di questo repository. +gb.myTickets = i miei ticket +gb.yourAssignedTickets = assegnati a te +gb.newMilestone = nuova milestone +gb.editMilestone = modifica milestone +gb.deleteMilestone = Cancella milestone \"{0}\"? +gb.milestoneDeleteFailed = Cancellazione di milestone fallita ''{0}''! +gb.notifyChangedOpenTickets = invia notifiche per cambiamenti su ticket aperti +gb.overdue = oltre il termine +gb.openMilestones = milestone aperte +gb.closedMilestones = milestone chiuse +gb.administration = amministrazione +gb.plugins = plugins +gb.extensions = estensioni +gb.pleaseSelectProject = Per favore seleziona il progetto! +gb.accessPolicy = Politica di accesso +gb.accessPolicyDescription = Scegli una politica di accesso per controllare la visibilità del repository e i permessi git. +gb.anonymousPolicy = Visualizzazione, Clone & Push anonimi +gb.anonymousPolicyDescription = Chiunque può visualizzare, clonare ed fare push su questo repository. +gb.authenticatedPushPolicy = Push ristretto (utenti autenticati) +gb.authenticatedPushPolicyDescription = Chiunque può visualizzare e clonare questo repository. Tutti gli utenti autenticati hanno diritto a push. +gb.namedPushPolicy = Push ristretto (utenti specifici) +gb.namedPushPolicyDescription = Chiunque può visualizzare e clonare questo repository. Solo gli utenti selezioni hanno diritto al push. +gb.clonePolicy = Clone & Push ristretti +gb.clonePolicyDescription = Chiunque può visualizzare questo repository. I permessi di clone e push vanno definiti. +gb.viewPolicy = Visualizzazione, Clone, & Push ristretti +gb.viewPolicyDescription = Vanno definiti i permessi per stabilire chi può visualizzare, clonare ed effettuare il push su questo repository. +gb.initialCommit = Primo commit +gb.initialCommitDescription = Questa funzionalità ti consente di clonare questo repository immediatamente. Salta questo passo se hai già un repository locale inizializzato. +gb.initWithReadme = Includi un README +gb.initWithReadmeDescription = Questa funzionalità genera semplice README per il tuo repository +gb.initWithGitignore = Includi un file .gitignore +gb.initWithGitignoreDescription = Questa funzionalità aggiunge un file di configurazione che istruisce i client Git ad ignorare file o cartelle che corrispondono a determinati criteri di selezione. +gb.pleaseSelectGitIgnore = Scegli un file .gitignore +gb.receive = ricevi +gb.permissions = permessi +gb.ownersDescription = Tutti i proprietari possono gestire tutti le impostazioni del repository ma non è concessa la rinomina del repository tranne nel caso di repository personale. +gb.userPermissionsDescription = E' possibile configurare permessi individuali. Queste impostazioni sovrascrivono quelle ereditate dal gruppo o da associazione tramite espresisone regolare. +gb.teamPermissionsDescription = E' possibile specificare permessi di gruppo. Queste impostazioni sovrascrivono quelle ereditate da associazione tramite espressione regolare. +gb.ticketSettings = Impostazioni Ticket +gb.receiveSettings = Ricezione ticket +gb.receiveSettingsDescription = Le impostazioni di ricezione governano i push al repository +gb.preReceiveDescription = Gli hook di pre-receive sono eseguiti dopo aver ricevuto i commit ma PRIMA che i ref vengano aggiornati.

    Questo è l'hook da usare per rigettare un push

    +gb.postReceiveDescription = Gli hook di post-receive sono eseguiti dopo aver ricevuto i commit e DOPO che i ref sono stati aggiornati.

    Questo è l'hook da usare per inviare notifiche, attivare un sistema di build ecc.

    +gb.federationStrategyDescription = Stabilisce se e come federare questo repository con un altra istanza Gitblit. +gb.federationSetsDescription = Questo repository sarà incluso nelle federazioni selezionate. +gb.miscellaneous = miscellanea +gb.originDescription = URL da cui questo repository è stato clonato +gb.gc = GC +gb.garbageCollection = Garbage Collection +gb.garbageCollectionDescription = Lo spazzino (GC) comprimerà gli oggetti inviati da client Git and rimuoverà dal repository oggetti non più referenziati. +gb.commitMessageRendererDescription = I messaggi di commit possono essere visualizzati come testo semplice o decorati come markdown +gb.preferences = impostazioni +gb.accountPreferences = Impostazione Utente +gb.accountPreferencesDescription = Imposta le preferenze del tuo utente +gb.languagePreference = Impostazioni di lingua +gb.languagePreferenceDescription = Scegli la tua lingua di traduzione preferita per Gitblit +gb.emailMeOnMyTicketChanges = Inviami una email quando uno dei miei ticket è modificato +gb.emailMeOnMyTicketChangesDescription = Inviami una email quando io stesso modifico un ticket +gb.displayNameDescription = Nome visualizzato +gb.emailAddressDescription = Indirizzo email principale per la ricezione delle notifiche +gb.sshKeys = Chiavi SSH +gb.sshKeysDescription = Autenticazione tramite chiave pubblica SSH è una alternativa sicura all'autenticazione tramite password +gb.addSshKey = Aggiungi una chiave SSH +gb.key = Chiave +gb.comment = Commento +gb.sshKeyCommentDescription = Aggiungi opzionalmente un commento. Se vuoto, il commento sarà estratto dalla chiave stessa. +gb.permission = Permesso +gb.sshKeyPermissionDescription = Definisci il il livello di accesso per la chiave SSH +gb.transportPreference = Preferenze di trasporto +gb.transportPreferenceDescription = Specifica il protocollo di trasporto che preferisci usare per le operazioni di clone + diff --git a/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_it.html b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_it.html new file mode 100644 index 00000000..365f4135 --- /dev/null +++ b/src/main/java/com/gitblit/wicket/pages/EmptyRepositoryPage_it.html @@ -0,0 +1,60 @@ + + + + + +
    +
    +
    +
    +

    Repository vuoto

    +
    + [repository] è vuoto e non può essere visualizzato con Gitblit. +

    + Per favore effettua il push di alcuni commit su +
    + Dopo il push ricarica questa pagina per vedere il contenuto del repository. +
    + +

    Crea un nuovo repository da riga di comando

    + +
    
    +
    +	

    Effettua il push da riga di comando

    + +
    
    +	
    +	
    +

    Impara a usare Git

    +

    Se non sei sicuro di quello che stai facendo, prova a leggere Git Community Book in italiano per una miglior comprensione dell'utilizzo di Git.

    + +

    Applicazioni client Git open source

    +
    SmartGit/HgEen Java Git, Mercurial, en SVN client applicatie (officiele command-line Git is wel nodig)
    + + + + + + + +
    Gitla versione ufficiale di Git, da riga di comando
    TortoiseGitIntegrazione per Windows Explorer (richiede la versione ufficiale di Git da riga di comando)
    Eclipse/EGitGit per ambienti di sviluppo basati su Eclipse (basato su JGit, come Gitblit)
    Git Extensionsapplicazione C# che integra Git in Windows Explorer e Visual Studio
    GitX-devun client Git per Mac OS X
    + +

    Applicazioni client commerciali/non open source

    + + + + + + +
    SmartGit/HgUn client Git e Mercurial scritto in Java per Windows, Mac, and Linux
    SourceTreeUn client Git e Mercurial gratuito per Windows & Mac
    TowerUn client Git per Mac OS X
    +
    +
    + + + +
    + + diff --git a/src/main/java/login_it.mkd b/src/main/java/login_it.mkd new file mode 100644 index 00000000..17058e34 --- /dev/null +++ b/src/main/java/login_it.mkd @@ -0,0 +1,4 @@ +## Login richiesto + +Per favore fornisci le tue credenziali per accedere a questo sito Gitblit. + diff --git a/src/main/java/welcome_it.mkd b/src/main/java/welcome_it.mkd new file mode 100644 index 00000000..54e681af --- /dev/null +++ b/src/main/java/welcome_it.mkd @@ -0,0 +1,3 @@ +## Benvenuto su Gitblit + +Un modo facile e veloce per ospitare o visualizzare i tuoi repository [Git](http://www.git-scm.com). -- cgit v1.2.3 From 5441436f507a8b1b0dbd24b523e4a27bd30840e6 Mon Sep 17 00:00:00 2001 From: David Ostrovsky Date: Mon, 16 Jun 2014 14:56:29 +0200 Subject: Remove unnecessary import --- src/site/plugins_extensions.mkd | 1 - 1 file changed, 1 deletion(-) diff --git a/src/site/plugins_extensions.mkd b/src/site/plugins_extensions.mkd index 0e066438..9e0d1705 100644 --- a/src/site/plugins_extensions.mkd +++ b/src/site/plugins_extensions.mkd @@ -96,7 +96,6 @@ import ro.fortsoft.pf4j.Extension; import org.kohsuke.args4j.Option; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.gitblit.models.UserModel; import com.gitblit.transport.ssh.commands.CommandMetaData; import com.gitblit.transport.ssh.commands.DispatchCommand; import com.gitblit.transport.ssh.commands.UsageExample; -- cgit v1.2.3 From 5881c4f334a5842f3c5fe63e3e499fd13aa41277 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 16 Jun 2014 10:01:53 -0400 Subject: Expose an Italiano language option in user preferences --- releases.moxie | 2 ++ src/main/java/com/gitblit/wicket/pages/UserPage.java | 1 + 2 files changed, 3 insertions(+) diff --git a/releases.moxie b/releases.moxie index 64039bc0..daf0a788 100644 --- a/releases.moxie +++ b/releases.moxie @@ -70,6 +70,7 @@ r24: { - Add setting to control default thread pool size for miscellaneous background tasks (ticket-92) - Add Norwegian transation (pr-186) - Add German translation (pr-192) + - Add Italian translation (pr-196) dependencyChanges: - Update to javax.mail 1.5.1 (issue-417, ticket-58) contributors: @@ -91,6 +92,7 @@ r24: { - Dongsu Kim - Karanbir Singh - Tamás Papp + - GianMaria Romanato settings: - { name: 'web.allowDeletingNonEmptyRepositories', defaultValue: 'true' } - { name: 'web.includePersonalRepositories', defaultValue: 'false' } diff --git a/src/main/java/com/gitblit/wicket/pages/UserPage.java b/src/main/java/com/gitblit/wicket/pages/UserPage.java index 7c6b7b0e..8931d5e3 100644 --- a/src/main/java/com/gitblit/wicket/pages/UserPage.java +++ b/src/main/java/com/gitblit/wicket/pages/UserPage.java @@ -176,6 +176,7 @@ public class UserPage extends RootPage { new Language("English","en"), new Language("Español", "es"), new Language("Français", "fr"), + new Language("Italiano", "it"), new Language("日本語", "ja"), new Language("한국ë§", "ko"), new Language("Nederlands", "nl"), -- cgit v1.2.3 From 74029cbbe0d3466167985d90d2ae6aa3ed4dadcd Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 16 Jun 2014 10:02:03 -0400 Subject: Documentation --- README.markdown | 38 ++++++++++++++++++++++++++++++++++---- src/site/features.mkd | 21 +++++++++++---------- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/README.markdown b/README.markdown index 76c15fce..e720bf5a 100644 --- a/README.markdown +++ b/README.markdown @@ -1,7 +1,8 @@ Gitblit ================= -Gitblit is an open source, pure Java Git solution for managing, viewing, and serving [Git](http://git-scm.com) repositories. +Gitblit is an open source, pure Java Git solution for managing, viewing, and serving [Git](http://git-scm.com) repositories. It can serve repositories over the GIT, HTTP, and SSH transports; it can authenticate against multiple providers; and it allows you to get up-and-running with an attractive, capable Git server in less than 5 minutes. + More information about Gitblit can be found [here](http://gitblit.com). @@ -15,7 +16,27 @@ The text of the license is included in the file LICENSE in the root of the proje Contributing ------------ -GitHub pull requests are preferred. Any contributions must be distributed under the terms of the [Apache Software Foundation license, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). +GitHub pull requests or Gitblit Tickets are preferred. Any contributions must be distributed under the terms of the [Apache Software Foundation license, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +**Workflow** + +Gitblit practices the [git-flow][1] branching model. + +- **master** is the current stable release + fixes accumulated since release. +- **develop** is the integration branch for the next major release. +- **ticket/N** are feature or hotfix branches to be merged to **master** or **develop**, as appropriate. + +**Feature Development** + +Development of new features is mostly done using [Gitblit Tickets][2] hosted at [dev.gitblit.com][3]. This allows continuous dogfooding and improvement of Gitbit's own issue-tracker and pull-request mechanism. + +**Release Planning** + +Release planning is mostly done using Gitblit Milestones and Gitblit Tickets hosted at [dev.gitblit.com][3]. + +**Releasing** + +When Gitblit is preparing for a release, a **release-{milestone}** branch will be created, tested, & fixed until it is ready to be merged to **master** and tagged as the next major release. After the release is tagged, the **release-{milestone}** branch will also be merged back into **develop** and then the release branch will be removed. Java Runtime Requirement ------------------------------------ @@ -25,8 +46,13 @@ Gitblit requires at Java 7 Runtime Environment (JRE) or a Java 7 Development Kit Getting help ------------ -Read the online documentation available at the [Gitblit website](http://gitblit.com) -Issues, binaries, & sources @ [Google Code](http://code.google.com/p/gitblit) +| Source | Location | +| ------------- |--------------------------------------------------------| +| Documentation | [Gitblit website](http://gitblit.com) | +| Issues | [Google Code](http://code.google.com/p/gitblit) | +| Forums | [Google Groups](https://groups.google.com/forum/#!forum/gitblit) | +| Twitter | @gitblit or @jamesmoger | +| Google+ | +gitblit or +jamesmoger | Building Gitblit ---------------- @@ -49,3 +75,7 @@ Building Tips & Tricks ---------------------- 1. If you are running Ant from an ANSI-capable console, consider setting the `MX_COLOR` environment variable before executing Ant.
    set MX_COLOR=true
    2. The build script will honor your Maven proxy settings. If you need to fine-tune this, please review the [settings.moxie](http://gitblit.github.io/moxie/settings.html) documentation. + +[1]: http://nvie.com/posts/a-successful-git-branching-model +[2]: http://gitblit.com/tickets_overview.html +[3]: https://dev.gitblit.com diff --git a/src/site/features.mkd b/src/site/features.mkd index 9aa81962..d9ceba71 100644 --- a/src/site/features.mkd +++ b/src/site/features.mkd @@ -60,17 +60,18 @@ - Customizable regular expression substitution for commit messages (i.e. bug or code review link integration) - Single text file for users configuration - Translations - - English - - Japanese - - Spanish - - Polish - - Korean - - Brazilian Portuguese - - Dutch + - German (de) + - English (en) + - Spanish (es) + - French (fr) + - Italian (it) + - Japanese (ja) + - Korean (ko) + - Dutch (nl) + - Norwegian (no) + - Polish (pl) + - Brazilian Portuguese (pt_BR) - Simplified Chinese (zh_CN) - - French - - German - - Norwegian ## Gitblit GO Features - Out-of-the-box integrated stack requiring minimal configuration -- cgit v1.2.3 From 14353c12bfc35f82441993ddeff0ecd36bcfee86 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 16 Jun 2014 11:02:57 -0400 Subject: Documentation --- src/main/java/com/gitblit/tickets/commands.md | 2 +- src/site/tickets_using.mkd | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/gitblit/tickets/commands.md b/src/main/java/com/gitblit/tickets/commands.md index 87fe515c..84d9ccc8 100644 --- a/src/main/java/com/gitblit/tickets/commands.md +++ b/src/main/java/com/gitblit/tickets/commands.md @@ -6,6 +6,6 @@ To review an updated patchset To review a rewritten patchset - git fetch origin && git checkout ${ticketBranch} && git reset --hard origin/${ticketBranch} + git fetch origin && git checkout -B ${ticketBranch} diff --git a/src/site/tickets_using.mkd b/src/site/tickets_using.mkd index 3cda7314..57128457 100644 --- a/src/site/tickets_using.mkd +++ b/src/site/tickets_using.mkd @@ -59,6 +59,14 @@ Any authenticated user who can clone your repository. ...add one or more commits... git push +### Checking-Out a Named Branch for an Existing Ticket with a Patchset + +If you prefer to name your local ticket branches rather than using the default integer ids, you can do this with a little more syntax. + + git checkout -b my_fix --track origin/ticket/{id} + +This will create a local branch named *my_fix* which tracks the upstream ticket branch. + ### Rewriting a Patchset (amend, rebase, squash) *Who can rewrite a patchset?* @@ -76,22 +84,19 @@ OR if you have RW+ permissions, then you can push using *-f* flag. ### Updating your copy of a rewritten Patchset -If a patchset has been rewritten you can no longer simply *pull* to update. Let's assume your checkout **does not** have any unshared commits - i.e. it represents the previous patchset. The simplest way to update your branch to the current patchset is to reset it. +If a patchset has been rewritten you can no longer simply *pull* to update. Let's assume your checkout **does not** have any unshared commits - i.e. it represents the previous patchset. The simplest way to update your branch to the current patchset is to reset it using the `-B` checkout flag. - git fetch && git checkout ticket/{id} - git reset --hard origin/ticket/{id} + git fetch && git checkout -B ticket/{id} If you **do** have unshared commits then you'll could make a new temporary branch and then cherry-pick your changes onto the rewritten patchset. git branch oldticket ticket/{id} - git fetch && git checkout ticket/{id} - git reset --hard origin/ticket/{id} + git fetch && git checkout -B ticket/{id} git cherry-pick git branch -D oldticket Git is a very flexible tool, there are no doubt several other strategies you could use to resolve this situation. The above solution is just one way. - ### Ticket RefSpecs Gitblit supports two primary push ref specs: the magic ref and the patchset ref. -- cgit v1.2.3 From 1f15c8e463b92ecd73c3f42bfeea7a6a5b2bb8d0 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 16 Jun 2014 11:58:13 -0400 Subject: Updated README --- README.markdown | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.markdown b/README.markdown index e720bf5a..a2260497 100644 --- a/README.markdown +++ b/README.markdown @@ -13,6 +13,22 @@ License Gitblit is distributed under the terms of the [Apache Software Foundation license, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). The text of the license is included in the file LICENSE in the root of the project. +Java Runtime Requirement +------------------------------------ + +Gitblit requires at Java 7 Runtime Environment (JRE) or a Java 7 Development Kit (JDK). + +Getting help +------------ + +| Source | Location | +| ------------- |--------------------------------------------------------| +| Documentation | [Gitblit website](http://gitblit.com) | +| Issues | [Google Code](http://code.google.com/p/gitblit) | +| Forums | [Google Groups](https://groups.google.com/forum/#!forum/gitblit) | +| Twitter | @gitblit or @jamesmoger | +| Google+ | +gitblit or +jamesmoger | + Contributing ------------ @@ -38,22 +54,6 @@ Release planning is mostly done using Gitblit Milestones and Gitblit Tickets hos When Gitblit is preparing for a release, a **release-{milestone}** branch will be created, tested, & fixed until it is ready to be merged to **master** and tagged as the next major release. After the release is tagged, the **release-{milestone}** branch will also be merged back into **develop** and then the release branch will be removed. -Java Runtime Requirement ------------------------------------- - -Gitblit requires at Java 7 Runtime Environment (JRE) or a Java 7 Development Kit (JDK). - -Getting help ------------- - -| Source | Location | -| ------------- |--------------------------------------------------------| -| Documentation | [Gitblit website](http://gitblit.com) | -| Issues | [Google Code](http://code.google.com/p/gitblit) | -| Forums | [Google Groups](https://groups.google.com/forum/#!forum/gitblit) | -| Twitter | @gitblit or @jamesmoger | -| Google+ | +gitblit or +jamesmoger | - Building Gitblit ---------------- -- cgit v1.2.3 From de1b355f49a4fd5bd775ae9b407d45942c0979e0 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 16 Jun 2014 17:06:56 -0400 Subject: Update build script for git-flow releases --- build.xml | 24 +++++++- release.template | 180 +++++++++++++++++++++++++++++-------------------------- 2 files changed, 119 insertions(+), 85 deletions(-) diff --git a/build.xml b/build.xml index 39fdb2e7..59dc6cb0 100644 --- a/build.xml +++ b/build.xml @@ -780,16 +780,38 @@ + + + + - Reset build identifiers for next development cycle + Reset build identifiers for next point release cycle + + + + + Reset build identifiers for next minor release cycle + + + + +