From f6b200be4c8b90c26886c6cdd5809abac8c4ac15 Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 27 Mar 2013 12:46:05 -0400 Subject: Reorganized to Apache Standard Directory Layout & integrated Moxie This is a massive commit which reorganizes the entire project structure (although it is still monolithic), removes the Build classes, and switches to Moxie, a smarter Ant build tookit based on the original Gitblit Build classes. The Ant build script will likely require additional fine-tuning, but this is big step forward. --- src/main/java/com/gitblit/models/Activity.java | 129 +++++ .../java/com/gitblit/models/AnnotatedLine.java | 47 ++ .../java/com/gitblit/models/FederationModel.java | 206 +++++++ .../com/gitblit/models/FederationProposal.java | 82 +++ .../java/com/gitblit/models/FederationSet.java | 58 ++ .../java/com/gitblit/models/FeedEntryModel.java | 61 ++ src/main/java/com/gitblit/models/FeedModel.java | 91 +++ src/main/java/com/gitblit/models/ForkModel.java | 77 +++ src/main/java/com/gitblit/models/GitNote.java | 39 ++ .../java/com/gitblit/models/GravatarProfile.java | 83 +++ src/main/java/com/gitblit/models/IssueModel.java | 532 ++++++++++++++++++ src/main/java/com/gitblit/models/Metric.java | 50 ++ src/main/java/com/gitblit/models/PathModel.java | 127 +++++ src/main/java/com/gitblit/models/ProjectModel.java | 101 ++++ src/main/java/com/gitblit/models/PushLogEntry.java | 208 +++++++ src/main/java/com/gitblit/models/RefModel.java | 148 +++++ .../gitblit/models/RegistrantAccessPermission.java | 149 +++++ .../java/com/gitblit/models/RepositoryCommit.java | 112 ++++ .../java/com/gitblit/models/RepositoryModel.java | 243 ++++++++ src/main/java/com/gitblit/models/SearchResult.java | 70 +++ .../java/com/gitblit/models/ServerSettings.java | 69 +++ src/main/java/com/gitblit/models/ServerStatus.java | 83 +++ src/main/java/com/gitblit/models/SettingModel.java | 162 ++++++ .../java/com/gitblit/models/SubmoduleModel.java | 47 ++ src/main/java/com/gitblit/models/TeamModel.java | 310 +++++++++++ src/main/java/com/gitblit/models/TicketModel.java | 119 ++++ src/main/java/com/gitblit/models/UserModel.java | 613 +++++++++++++++++++++ 27 files changed, 4016 insertions(+) create mode 100644 src/main/java/com/gitblit/models/Activity.java create mode 100644 src/main/java/com/gitblit/models/AnnotatedLine.java create mode 100644 src/main/java/com/gitblit/models/FederationModel.java create mode 100644 src/main/java/com/gitblit/models/FederationProposal.java create mode 100644 src/main/java/com/gitblit/models/FederationSet.java create mode 100644 src/main/java/com/gitblit/models/FeedEntryModel.java create mode 100644 src/main/java/com/gitblit/models/FeedModel.java create mode 100644 src/main/java/com/gitblit/models/ForkModel.java create mode 100644 src/main/java/com/gitblit/models/GitNote.java create mode 100644 src/main/java/com/gitblit/models/GravatarProfile.java create mode 100644 src/main/java/com/gitblit/models/IssueModel.java create mode 100644 src/main/java/com/gitblit/models/Metric.java create mode 100644 src/main/java/com/gitblit/models/PathModel.java create mode 100644 src/main/java/com/gitblit/models/ProjectModel.java create mode 100644 src/main/java/com/gitblit/models/PushLogEntry.java create mode 100644 src/main/java/com/gitblit/models/RefModel.java create mode 100644 src/main/java/com/gitblit/models/RegistrantAccessPermission.java create mode 100644 src/main/java/com/gitblit/models/RepositoryCommit.java create mode 100644 src/main/java/com/gitblit/models/RepositoryModel.java create mode 100644 src/main/java/com/gitblit/models/SearchResult.java create mode 100644 src/main/java/com/gitblit/models/ServerSettings.java create mode 100644 src/main/java/com/gitblit/models/ServerStatus.java create mode 100644 src/main/java/com/gitblit/models/SettingModel.java create mode 100644 src/main/java/com/gitblit/models/SubmoduleModel.java create mode 100644 src/main/java/com/gitblit/models/TeamModel.java create mode 100644 src/main/java/com/gitblit/models/TicketModel.java create mode 100644 src/main/java/com/gitblit/models/UserModel.java (limited to 'src/main/java/com/gitblit/models') diff --git a/src/main/java/com/gitblit/models/Activity.java b/src/main/java/com/gitblit/models/Activity.java new file mode 100644 index 00000000..59405c7f --- /dev/null +++ b/src/main/java/com/gitblit/models/Activity.java @@ -0,0 +1,129 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jgit.revwalk.RevCommit; + +import com.gitblit.utils.StringUtils; +import com.gitblit.utils.TimeUtils; + +/** + * Model class to represent the commit activity across many repositories. This + * class is used by the Activity page. + * + * @author James Moger + */ +public class Activity implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public final Date startDate; + + public final Date endDate; + + private final Set commits; + + private final Map authorMetrics; + + private final Map repositoryMetrics; + + /** + * Constructor for one day of activity. + * + * @param date + */ + public Activity(Date date) { + this(date, TimeUtils.ONEDAY - 1); + } + + /** + * Constructor for specified duration of activity from start date. + * + * @param date + * the start date of the activity + * @param duration + * the duration of the period in milliseconds + */ + public Activity(Date date, long duration) { + startDate = date; + endDate = new Date(date.getTime() + duration); + commits = new LinkedHashSet(); + authorMetrics = new HashMap(); + repositoryMetrics = new HashMap(); + } + + /** + * Adds a commit to the activity object as long as the commit is not a + * duplicate. + * + * @param repository + * @param branch + * @param commit + * @return a RepositoryCommit, if one was added. Null if this is duplicate + * commit + */ + public RepositoryCommit addCommit(String repository, String branch, RevCommit commit) { + RepositoryCommit commitModel = new RepositoryCommit(repository, branch, commit); + if (commits.add(commitModel)) { + if (!repositoryMetrics.containsKey(repository)) { + repositoryMetrics.put(repository, new Metric(repository)); + } + repositoryMetrics.get(repository).count++; + + String author = StringUtils.removeNewlines(commit.getAuthorIdent().getEmailAddress()).toLowerCase(); + if (!authorMetrics.containsKey(author)) { + authorMetrics.put(author, new Metric(author)); + } + authorMetrics.get(author).count++; + return commitModel; + } + return null; + } + + public int getCommitCount() { + return commits.size(); + } + + public List getCommits() { + List list = new ArrayList(commits); + Collections.sort(list); + return list; + } + + public Map getAuthorMetrics() { + return authorMetrics; + } + + public Map getRepositoryMetrics() { + return repositoryMetrics; + } + + @Override + public int compareTo(Activity o) { + // reverse chronological order + return o.startDate.compareTo(startDate); + } +} diff --git a/src/main/java/com/gitblit/models/AnnotatedLine.java b/src/main/java/com/gitblit/models/AnnotatedLine.java new file mode 100644 index 00000000..69b55bcd --- /dev/null +++ b/src/main/java/com/gitblit/models/AnnotatedLine.java @@ -0,0 +1,47 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.Date; + +import org.eclipse.jgit.revwalk.RevCommit; + +/** + * AnnotatedLine is a serializable model class that represents a the most recent + * author, date, and commit id of a line in a source file. + * + * @author James Moger + * + */ +public class AnnotatedLine implements Serializable { + + private static final long serialVersionUID = 1L; + + public final String commitId; + public final String author; + public final Date when; + public final int lineNumber; + public final String data; + + public AnnotatedLine(RevCommit commit, int lineNumber, String data) { + this.commitId = commit.getName(); + this.author = commit.getAuthorIdent().getName(); + this.when = commit.getAuthorIdent().getWhen(); + this.lineNumber = lineNumber; + this.data = data; + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/models/FederationModel.java b/src/main/java/com/gitblit/models/FederationModel.java new file mode 100644 index 00000000..1d211ce9 --- /dev/null +++ b/src/main/java/com/gitblit/models/FederationModel.java @@ -0,0 +1,206 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import com.gitblit.Constants.FederationPullStatus; +import com.gitblit.utils.StringUtils; + +/** + * Represents a federated server registration. Gitblit federation allows one + * Gitblit instance to pull the repositories and configuration from another + * Gitblit instance. This is a backup operation and can be considered something + * like svn-sync. + * + */ +public class FederationModel implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public String name; + + public String url; + + public String token; + + public String frequency; + + public String folder; + + public boolean bare; + + public boolean mirror; + + public boolean mergeAccounts; + + public boolean sendStatus; + + public boolean notifyOnError; + + public List exclusions = new ArrayList(); + + public List inclusions = new ArrayList(); + + public Date lastPull; + + public Date nextPull; + + private Map results = new ConcurrentHashMap(); + + /** + * The constructor for a remote server configuration. + * + * @param serverName + */ + public FederationModel(String serverName) { + this.name = serverName; + bare = true; + mirror = true; + this.lastPull = new Date(0); + this.nextPull = new Date(0); + } + + public boolean isIncluded(RepositoryModel repository) { + // if exclusions has the all wildcard, then check for specific + // inclusions + if (exclusions.contains("*")) { + for (String name : inclusions) { + if (StringUtils.fuzzyMatch(repository.name, name)) { + results.put(repository.name, FederationPullStatus.PENDING); + return true; + } + } + results.put(repository.name, FederationPullStatus.EXCLUDED); + return false; + } + + // named exclusions + for (String name : exclusions) { + if (StringUtils.fuzzyMatch(repository.name, name)) { + results.put(repository.name, FederationPullStatus.EXCLUDED); + return false; + } + } + + // included by default + results.put(repository.name, FederationPullStatus.PENDING); + return true; + } + + /** + * Updates the pull status of a particular repository in this federation + * registration. + * + * @param repository + * @param status + */ + public void updateStatus(RepositoryModel repository, FederationPullStatus status) { + if (!results.containsKey(repository.name)) { + results.put(repository.name, FederationPullStatus.PENDING); + } + if (status != null) { + results.put(repository.name, status); + } + } + + public List getStatusList() { + List list = new ArrayList(); + for (Map.Entry entry : results.entrySet()) { + list.add(new RepositoryStatus(entry.getKey(), entry.getValue())); + } + return list; + } + + /** + * Iterates over the current pull results and returns the lowest pull + * status. + * + * @return the lowest pull status of the registration + */ + public FederationPullStatus getLowestStatus() { + if (results.size() == 0) { + return FederationPullStatus.PENDING; + } + FederationPullStatus status = FederationPullStatus.MIRRORED; + for (FederationPullStatus result : results.values()) { + if (result.ordinal() < status.ordinal()) { + status = result; + } + } + return status; + } + + /** + * Returns true if this registration represents the result data sent by a + * pulling Gitblit instance. + * + * @return true, if this is result data + */ + public boolean isResultData() { + return !url.toLowerCase().startsWith("http://") && !url.toLowerCase().startsWith("https://"); + } + + @Override + public String toString() { + return "Federated " + name + " (" + url + ")"; + } + + @Override + public int compareTo(FederationModel o) { + boolean r1 = isResultData(); + boolean r2 = o.isResultData(); + if ((r1 && r2) || (!r1 && !r2)) { + // sort registrations and results by name + return name.compareTo(o.name); + } + // sort registrations first + if (r1) { + return 1; + } + return -1; + } + + /** + * Class that encapsulates a point-in-time pull result. + * + */ + public static class RepositoryStatus implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public final String name; + public final FederationPullStatus status; + + RepositoryStatus(String name, FederationPullStatus status) { + this.name = name; + this.status = status; + } + + @Override + public int compareTo(RepositoryStatus o) { + if (status.equals(o.status)) { + return StringUtils.compareRepositoryNames(name, o.name); + } + return status.compareTo(o.status); + } + } +} diff --git a/src/main/java/com/gitblit/models/FederationProposal.java b/src/main/java/com/gitblit/models/FederationProposal.java new file mode 100644 index 00000000..5cf9182c --- /dev/null +++ b/src/main/java/com/gitblit/models/FederationProposal.java @@ -0,0 +1,82 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.Map; + +import com.gitblit.Constants.FederationToken; + +/** + * Represents a proposal from a Gitblit instance to pull its repositories. + */ +public class FederationProposal implements Serializable { + + private static final long serialVersionUID = 1L; + + public Date received; + + public String name; + + public String url; + + public FederationToken tokenType; + + public String token; + + public String message; + + public Map repositories; + + /** + * The constructor for a federation proposal. + * + * @param url + * the url of the source Gitblit instance + * @param tokenType + * the type of token from the source Gitblit instance + * @param token + * the federation token from the source Gitblit instance + * @param repositories + * the map of repositories to be pulled from the source Gitblit + * instance keyed by the repository clone url + */ + public FederationProposal(String url, FederationToken tokenType, String token, + Map repositories) { + this.received = new Date(); + this.url = url; + this.tokenType = tokenType; + this.token = token; + this.message = ""; + this.repositories = repositories; + try { + // determine server name and set that as the proposal name + name = url.substring(url.indexOf("//") + 2); + if (name.contains("/")) { + name = name.substring(0, name.indexOf('/')); + } + name = name.replace(".", "").replace(";", "").replace(":", "").replace("-", ""); + } catch (Exception e) { + name = Long.toHexString(System.currentTimeMillis()); + } + } + + @Override + public String toString() { + return "Federation Proposal (" + url + ")"; + } +} diff --git a/src/main/java/com/gitblit/models/FederationSet.java b/src/main/java/com/gitblit/models/FederationSet.java new file mode 100644 index 00000000..357689c9 --- /dev/null +++ b/src/main/java/com/gitblit/models/FederationSet.java @@ -0,0 +1,58 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.Map; + +import com.gitblit.Constants.FederationToken; + +/** + * Represents a group of repositories. + */ +public class FederationSet implements Serializable { + + private static final long serialVersionUID = 1L; + + public String name; + + public String token; + + public FederationToken tokenType; + + public Map repositories; + + /** + * The constructor for a federation set. + * + * @param name + * the name of this federation set + * @param tokenType + * the type of token of this federation set + * @param token + * the federation token + */ + public FederationSet(String name, FederationToken tokenType, String token) { + this.name = name; + this.tokenType = tokenType; + this.token = token; + } + + @Override + public String toString() { + return "Federation Set (" + name + ")"; + } +} diff --git a/src/main/java/com/gitblit/models/FeedEntryModel.java b/src/main/java/com/gitblit/models/FeedEntryModel.java new file mode 100644 index 00000000..e1c00c38 --- /dev/null +++ b/src/main/java/com/gitblit/models/FeedEntryModel.java @@ -0,0 +1,61 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +/** + * FeedEntryModel represents an entry in a syndication (RSS) feed. + * + * @author James Moger + */ +public class FeedEntryModel implements Serializable, Comparable { + + public String repository; + public String branch; + public String title; + public String author; + public Date published; + public String link; + public String content; + public String contentType; + public List tags; + + private static final long serialVersionUID = 1L; + + public FeedEntryModel() { + } + + @Override + public int compareTo(FeedEntryModel o) { + return o.published.compareTo(published); + } + + @Override + public int hashCode() { + return link.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof FeedEntryModel) { + return hashCode() == o.hashCode(); + } + return false; + } +} diff --git a/src/main/java/com/gitblit/models/FeedModel.java b/src/main/java/com/gitblit/models/FeedModel.java new file mode 100644 index 00000000..08f9e48e --- /dev/null +++ b/src/main/java/com/gitblit/models/FeedModel.java @@ -0,0 +1,91 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.Date; + +import com.gitblit.utils.StringUtils; + +/** + * FeedModel represents a syndication (RSS) feed. + * + * @author James Moger + */ +public class FeedModel implements Serializable, Comparable { + + public String repository; + public String branch; + public Date lastRefreshDate; + public Date currentRefreshDate; + + public boolean subscribed; + + private static final long serialVersionUID = 1L; + + public FeedModel() { + this(""); + subscribed = false; + } + + public FeedModel(String definition) { + subscribed = true; + lastRefreshDate = new Date(0); + currentRefreshDate = new Date(0); + + String[] fields = definition.split(":"); + repository = fields[0]; + if (fields.length > 1) { + branch = fields[1]; + } + } + + @Override + public String toString() { + if (StringUtils.isEmpty(branch)) { + return repository; + } + return repository + ":" + branch; + } + + @Override + public int compareTo(FeedModel o) { + int repositoryCompare = StringUtils.compareRepositoryNames(repository, o.repository); + if (repositoryCompare == 0) { + // same repository + if (StringUtils.isEmpty(branch)) { + return 1; + } else if (StringUtils.isEmpty(o.branch)) { + return -1; + } + return branch.compareTo(o.branch); + } + return repositoryCompare; + } + + @Override + public int hashCode() { + return toString().toLowerCase().hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof FeedModel) { + return hashCode() == o.hashCode(); + } + return false; + } +} diff --git a/src/main/java/com/gitblit/models/ForkModel.java b/src/main/java/com/gitblit/models/ForkModel.java new file mode 100644 index 00000000..849986c1 --- /dev/null +++ b/src/main/java/com/gitblit/models/ForkModel.java @@ -0,0 +1,77 @@ +/* + * Copyright 2012 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.models; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import com.gitblit.utils.ArrayUtils; +import com.gitblit.utils.StringUtils; + +/** + * A ForkModel represents a repository, its direct descendants, and its origin. + * + * @author James Moger + * + */ +public class ForkModel implements Serializable { + + private static final long serialVersionUID = 1L; + + public final RepositoryModel repository; + + public final List forks; + + public ForkModel(RepositoryModel repository) { + this.repository = repository; + this.forks = new ArrayList(); + } + + public boolean isRoot() { + return StringUtils.isEmpty(repository.originRepository); + } + + public boolean isNode() { + return !ArrayUtils.isEmpty(forks); + } + + public boolean isLeaf() { + return ArrayUtils.isEmpty(forks); + } + + public boolean isPersonalRepository() { + return repository.isPersonalRepository(); + } + + @Override + public int hashCode() { + return repository.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof ForkModel) { + return repository.equals(((ForkModel) o).repository); + } + return false; + } + + @Override + public String toString() { + return repository.toString(); + } +} diff --git a/src/main/java/com/gitblit/models/GitNote.java b/src/main/java/com/gitblit/models/GitNote.java new file mode 100644 index 00000000..c333a881 --- /dev/null +++ b/src/main/java/com/gitblit/models/GitNote.java @@ -0,0 +1,39 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; + +/** + * GitNote is a serializable model class that represents a git note. This class + * retains an instance of the RefModel which contains the commit in which this + * git note was created. + * + * @author James Moger + * + */ +public class GitNote implements Serializable { + + private static final long serialVersionUID = 1L; + + public final String content; + public final RefModel notesRef; + + public GitNote(RefModel notesRef, String text) { + this.notesRef = notesRef; + this.content = text; + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/models/GravatarProfile.java b/src/main/java/com/gitblit/models/GravatarProfile.java new file mode 100644 index 00000000..aa128ce0 --- /dev/null +++ b/src/main/java/com/gitblit/models/GravatarProfile.java @@ -0,0 +1,83 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.List; + +/** + * Represents a Gravatar profile. + * + * @author James Moger + * + */ +public class GravatarProfile implements Serializable { + + private static final long serialVersionUID = 1L; + + public String id; + public String hash; + public String requestHash; + public String displayName; + public String preferredUsername; + public String currentLocation; + public String aboutMe; + + public String profileUrl; + public String thumbnailUrl; + public List photos; +// public Map profileBackground; +// public Map name; + + public List phoneNumbers; + public List emails; + public List ims; + public List accounts; + public List urls; + + public static class ProfileObject implements Serializable { + + private static final long serialVersionUID = 1L; + + public String title; + public String type; + public String value; + public boolean primary; + + @Override + public String toString() { + return value; + } + } + + public static class Account implements Serializable { + + private static final long serialVersionUID = 1L; + + public String domain; + public String display; + public String url; + public String username; + public String userid; + public boolean verified; + public String shortname; + + @Override + public String toString() { + return display; + } + } +} diff --git a/src/main/java/com/gitblit/models/IssueModel.java b/src/main/java/com/gitblit/models/IssueModel.java new file mode 100644 index 00000000..c9038913 --- /dev/null +++ b/src/main/java/com/gitblit/models/IssueModel.java @@ -0,0 +1,532 @@ +/* + * Copyright 2012 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.models; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import com.gitblit.utils.ArrayUtils; +import com.gitblit.utils.StringUtils; +import com.gitblit.utils.TimeUtils; + +/** + * The Gitblit Issue model, its component classes, and enums. + * + * @author James Moger + * + */ +public class IssueModel implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public String id; + + public Type type; + + public Status status; + + public Priority priority; + + public Date created; + + public String summary; + + public String description; + + public String reporter; + + public String owner; + + public String milestone; + + public List changes; + + public IssueModel() { + // the first applied change set the date appropriately + created = new Date(0); + + type = Type.Defect; + status = Status.New; + priority = Priority.Medium; + + changes = new ArrayList(); + } + + public String getStatus() { + String s = status.toString(); + if (!StringUtils.isEmpty(owner)) + s += " (" + owner + ")"; + return s; + } + + public boolean hasLabel(String label) { + return getLabels().contains(label); + } + + public List getLabels() { + List list = new ArrayList(); + String labels = null; + for (Change change : changes) { + if (change.hasField(Field.Labels)) { + labels = change.getString(Field.Labels); + } + } + if (!StringUtils.isEmpty(labels)) { + list.addAll(StringUtils.getStringsFromValue(labels, " ")); + } + return list; + } + + public Attachment getAttachment(String name) { + Attachment attachment = null; + for (Change change : changes) { + if (change.hasAttachments()) { + Attachment a = change.getAttachment(name); + if (a != null) { + attachment = a; + } + } + } + return attachment; + } + + public List getAttachments() { + List list = new ArrayList(); + for (Change change : changes) { + if (change.hasAttachments()) { + list.addAll(change.attachments); + } + } + return list; + } + + public void applyChange(Change change) { + if (changes.size() == 0) { + // first change created the issue + created = change.created; + } + changes.add(change); + + if (change.hasFieldChanges()) { + for (FieldChange fieldChange : change.fieldChanges) { + switch (fieldChange.field) { + case Id: + id = fieldChange.value.toString(); + break; + case Type: + type = IssueModel.Type.fromObject(fieldChange.value); + break; + case Status: + status = IssueModel.Status.fromObject(fieldChange.value); + break; + case Priority: + priority = IssueModel.Priority.fromObject(fieldChange.value); + break; + case Summary: + summary = fieldChange.value.toString(); + break; + case Description: + description = fieldChange.value.toString(); + break; + case Reporter: + reporter = fieldChange.value.toString(); + break; + case Owner: + owner = fieldChange.value.toString(); + break; + case Milestone: + milestone = fieldChange.value.toString(); + break; + } + } + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("issue "); + sb.append(id.substring(0, 8)); + sb.append(" (" + summary + ")\n"); + for (Change change : changes) { + sb.append(change); + sb.append('\n'); + } + return sb.toString(); + } + + @Override + public int compareTo(IssueModel o) { + return o.created.compareTo(created); + } + + @Override + public boolean equals(Object o) { + if (o instanceof IssueModel) + return id.equals(((IssueModel) o).id); + return super.equals(o); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + public static class Change implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public final Date created; + + public final String author; + + public String id; + + public char code; + + public Comment comment; + + public Set fieldChanges; + + public Set attachments; + + public Change(String author) { + this.created = new Date((System.currentTimeMillis() / 1000) * 1000); + this.author = author; + this.id = StringUtils.getSHA1(created.toString() + author); + } + + public boolean hasComment() { + return comment != null && !comment.deleted; + } + + public void comment(String text) { + comment = new Comment(text); + comment.id = StringUtils.getSHA1(created.toString() + author + text); + } + + public boolean hasAttachments() { + return !ArrayUtils.isEmpty(attachments); + } + + public void addAttachment(Attachment attachment) { + if (attachments == null) { + attachments = new LinkedHashSet(); + } + attachments.add(attachment); + } + + public Attachment getAttachment(String name) { + for (Attachment attachment : attachments) { + if (attachment.name.equalsIgnoreCase(name)) { + return attachment; + } + } + return null; + } + + public boolean hasField(Field field) { + return !StringUtils.isEmpty(getString(field)); + } + + public boolean hasFieldChanges() { + return !ArrayUtils.isEmpty(fieldChanges); + } + + public Object getField(Field field) { + if (fieldChanges != null) { + for (FieldChange fieldChange : fieldChanges) { + if (fieldChange.field == field) { + return fieldChange.value; + } + } + } + return null; + } + + public void setField(Field field, Object value) { + FieldChange fieldChange = new FieldChange(field, value); + if (fieldChanges == null) { + fieldChanges = new LinkedHashSet(); + } + fieldChanges.add(fieldChange); + } + + public String getString(Field field) { + Object value = getField(field); + if (value == null) { + return null; + } + return value.toString(); + } + + @Override + public int compareTo(Change c) { + return created.compareTo(c.created); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof Change) { + return id.equals(((Change) o).id); + } + return false; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(new TimeUtils().timeAgo(created)); + switch (code) { + case '+': + sb.append(" created by "); + break; + default: + if (hasComment()) { + sb.append(" commented on by "); + } else { + sb.append(" changed by "); + } + } + sb.append(author).append(" - "); + if (hasComment()) { + if (comment.deleted) { + sb.append("(deleted) "); + } + sb.append(comment.text).append(" "); + } + if (hasFieldChanges()) { + switch (code) { + case '+': + break; + default: + for (FieldChange fieldChange : fieldChanges) { + sb.append("\n "); + sb.append(fieldChange); + } + break; + } + } + return sb.toString(); + } + } + + public static class Comment implements Serializable { + + private static final long serialVersionUID = 1L; + + public String text; + + public String id; + + public boolean deleted; + + Comment(String text) { + this.text = text; + } + + @Override + public String toString() { + return text; + } + } + + public static class FieldChange implements Serializable { + + private static final long serialVersionUID = 1L; + + public final Field field; + + public final Object value; + + FieldChange(Field field, Object value) { + this.field = field; + this.value = value; + } + + @Override + public int hashCode() { + return field.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof FieldChange) { + return field.equals(((FieldChange) o).field); + } + return false; + } + + @Override + public String toString() { + return field + ": " + value; + } + } + + public static class Attachment implements Serializable { + + private static final long serialVersionUID = 1L; + + public final String name; + public String id; + public long size; + public byte[] content; + public boolean deleted; + + public Attachment(String name) { + this.name = name; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof Attachment) { + return name.equalsIgnoreCase(((Attachment) o).name); + } + return false; + } + + @Override + public String toString() { + return name; + } + } + + public static enum Field { + Id, Summary, Description, Reporter, Owner, Type, Status, Priority, Milestone, Component, Labels; + } + + public static enum Type { + Defect, Enhancement, Task, Review, Other; + + public static Type fromObject(Object o) { + if (o instanceof Type) { + // cast and return + return (Type) o; + } else if (o instanceof String) { + // find by name + for (Type type : values()) { + String str = o.toString(); + if (type.toString().equalsIgnoreCase(str)) { + return type; + } + } + } else if (o instanceof Number) { + // by ordinal + int id = ((Number) o).intValue(); + if (id >= 0 && id < values().length) { + return values()[id]; + } + } + return null; + } + } + + public static enum Priority { + Low, Medium, High, Critical; + + public static Priority fromObject(Object o) { + if (o instanceof Priority) { + // cast and return + return (Priority) o; + } else if (o instanceof String) { + // find by name + for (Priority priority : values()) { + String str = o.toString(); + if (priority.toString().equalsIgnoreCase(str)) { + return priority; + } + } + } else if (o instanceof Number) { + // by ordinal + int id = ((Number) o).intValue(); + if (id >= 0 && id < values().length) { + return values()[id]; + } + } + return null; + } + } + + public static enum Status { + New, Accepted, Started, Review, Queued, Testing, Done, Fixed, WontFix, Duplicate, Invalid; + + public static Status fromObject(Object o) { + if (o instanceof Status) { + // cast and return + return (Status) o; + } else if (o instanceof String) { + // find by name + for (Status status : values()) { + String str = o.toString(); + if (status.toString().equalsIgnoreCase(str)) { + return status; + } + } + } else if (o instanceof Number) { + // by ordinal + int id = ((Number) o).intValue(); + if (id >= 0 && id < values().length) { + return values()[id]; + } + } + return null; + } + + public boolean atLeast(Status status) { + return ordinal() >= status.ordinal(); + } + + public boolean exceeds(Status status) { + return ordinal() > status.ordinal(); + } + + public boolean isClosed() { + return ordinal() >= Done.ordinal(); + } + + public Status next() { + switch (this) { + case New: + return Started; + case Accepted: + return Started; + case Started: + return Testing; + case Review: + return Testing; + case Queued: + return Testing; + case Testing: + return Done; + } + return Accepted; + } + } +} diff --git a/src/main/java/com/gitblit/models/Metric.java b/src/main/java/com/gitblit/models/Metric.java new file mode 100644 index 00000000..2845c527 --- /dev/null +++ b/src/main/java/com/gitblit/models/Metric.java @@ -0,0 +1,50 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; + +/** + * Metric is a serializable model class that encapsulates metrics for some given + * type. + * + * @author James Moger + * + */ +public class Metric implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public final String name; + public double count; + public double tag; + public int duration; + + public Metric(String name) { + this.name = name; + } + + @Override + public int compareTo(Metric o) { + if (count > o.count) { + return -1; + } + if (count < o.count) { + return 1; + } + return 0; + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/models/PathModel.java b/src/main/java/com/gitblit/models/PathModel.java new file mode 100644 index 00000000..84571cbb --- /dev/null +++ b/src/main/java/com/gitblit/models/PathModel.java @@ -0,0 +1,127 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; + +import org.eclipse.jgit.diff.DiffEntry.ChangeType; +import org.eclipse.jgit.lib.FileMode; + +/** + * PathModel is a serializable model class that represents a file or a folder, + * including all its metadata and associated commit id. + * + * @author James Moger + * + */ +public class PathModel implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public final String name; + public final String path; + public final long size; + public final int mode; + public final String objectId; + public final String commitId; + public boolean isParentPath; + + public PathModel(String name, String path, long size, int mode, String objectId, String commitId) { + this.name = name; + this.path = path; + this.size = size; + this.mode = mode; + this.objectId = objectId; + this.commitId = commitId; + } + + public boolean isSymlink() { + return FileMode.SYMLINK.equals(mode); + } + + public boolean isSubmodule() { + return FileMode.GITLINK.equals(mode); + } + + public boolean isTree() { + return FileMode.TREE.equals(mode); + } + + @Override + public int hashCode() { + return commitId.hashCode() + path.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof PathModel) { + PathModel other = (PathModel) o; + return this.path.equals(other.path); + } + return super.equals(o); + } + + @Override + public int compareTo(PathModel o) { + boolean isTree = isTree(); + boolean otherTree = o.isTree(); + if (isTree && otherTree) { + return path.compareTo(o.path); + } else if (!isTree && !otherTree) { + if (isSubmodule() && o.isSubmodule()) { + return path.compareTo(o.path); + } else if (isSubmodule()) { + return -1; + } else if (o.isSubmodule()) { + return 1; + } + return path.compareTo(o.path); + } else if (isTree && !otherTree) { + return -1; + } + return 1; + } + + /** + * PathChangeModel is a serializable class that represents a file changed in + * a commit. + * + * @author James Moger + * + */ + public static class PathChangeModel extends PathModel { + + private static final long serialVersionUID = 1L; + + public final ChangeType changeType; + + public PathChangeModel(String name, String path, long size, int mode, String objectId, + String commitId, ChangeType type) { + super(name, path, size, mode, objectId, commitId); + this.changeType = type; + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object o) { + return super.equals(o); + } + } +} diff --git a/src/main/java/com/gitblit/models/ProjectModel.java b/src/main/java/com/gitblit/models/ProjectModel.java new file mode 100644 index 00000000..9e5d5233 --- /dev/null +++ b/src/main/java/com/gitblit/models/ProjectModel.java @@ -0,0 +1,101 @@ +/* + * Copyright 2012 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.models; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; + +import com.gitblit.utils.StringUtils; + +/** + * ProjectModel is a serializable model class. + * + * @author James Moger + * + */ +public class ProjectModel implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + // field names are reflectively mapped in EditProject page + public final String name; + public String title; + public String description; + public final Set repositories = new HashSet(); + + public String projectMarkdown; + public String repositoriesMarkdown; + public Date lastChange; + public final boolean isRoot; + + public ProjectModel(String name) { + this(name, false); + } + + public ProjectModel(String name, boolean isRoot) { + this.name = name; + this.isRoot = isRoot; + this.lastChange = new Date(0); + this.title = ""; + this.description = ""; + } + + public boolean isUserProject() { + return name.charAt(0) == '~'; + } + + public boolean hasRepository(String name) { + return repositories.contains(name.toLowerCase()); + } + + public void addRepository(String name) { + repositories.add(name.toLowerCase()); + } + + public void addRepository(RepositoryModel model) { + repositories.add(model.name.toLowerCase()); + if (lastChange.before(model.lastChange)) { + lastChange = model.lastChange; + } + } + + public void addRepositories(Collection names) { + for (String name:names) { + repositories.add(name.toLowerCase()); + } + } + + public void removeRepository(String name) { + repositories.remove(name.toLowerCase()); + } + + public String getDisplayName() { + return StringUtils.isEmpty(title) ? name : title; + } + + @Override + public String toString() { + return name; + } + + @Override + public int compareTo(ProjectModel o) { + return name.compareTo(o.name); + } +} diff --git a/src/main/java/com/gitblit/models/PushLogEntry.java b/src/main/java/com/gitblit/models/PushLogEntry.java new file mode 100644 index 00000000..f625c2a3 --- /dev/null +++ b/src/main/java/com/gitblit/models/PushLogEntry.java @@ -0,0 +1,208 @@ +/* + * Copyright 2013 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.models; + +import java.io.Serializable; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.transport.ReceiveCommand; + +/** + * Model class to represent a push into a repository. + * + * @author James Moger + */ +public class PushLogEntry implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public final String repository; + + public final Date date; + + public final UserModel user; + + private final Set commits; + + private final Map refUpdates; + + /** + * Constructor for specified duration of push from start date. + * + * @param repository + * the repository that received the push + * @param date + * the date of the push + * @param user + * the user who pushed + */ + public PushLogEntry(String repository, Date date, UserModel user) { + this.repository = repository; + this.date = date; + this.user = user; + this.commits = new LinkedHashSet(); + this.refUpdates = new HashMap(); + } + + /** + * Tracks the change type for the specified ref. + * + * @param ref + * @param type + */ + public void updateRef(String ref, ReceiveCommand.Type type) { + if (!refUpdates.containsKey(ref)) { + refUpdates.put(ref, type); + } + } + + /** + * Adds a commit to the push entry object as long as the commit is not a + * duplicate. + * + * @param branch + * @param commit + * @return a RepositoryCommit, if one was added. Null if this is duplicate + * commit + */ + public RepositoryCommit addCommit(String branch, RevCommit commit) { + RepositoryCommit commitModel = new RepositoryCommit(repository, branch, commit); + if (commits.add(commitModel)) { + return commitModel; + } + return null; + } + + /** + * Returns true if this push contains a non-fastforward ref update. + * + * @return true if this is a non-fastforward push + */ + public boolean isNonFastForward() { + for (Map.Entry entry : refUpdates.entrySet()) { + if (ReceiveCommand.Type.UPDATE_NONFASTFORWARD.equals(entry.getValue())) { + return true; + } + } + return false; + } + + /** + * Returns the list of branches changed by the push. + * + * @return a list of branches + */ + public List getChangedBranches() { + return getChangedRefs(Constants.R_HEADS); + } + + /** + * Returns the list of tags changed by the push. + * + * @return a list of tags + */ + public List getChangedTags() { + return getChangedRefs(Constants.R_TAGS); + } + + /** + * Gets the changed refs in the push. + * + * @param baseRef + * @return the changed refs + */ + protected List getChangedRefs(String baseRef) { + Set refs = new HashSet(); + for (String ref : refUpdates.keySet()) { + if (baseRef == null || ref.startsWith(baseRef)) { + refs.add(ref); + } + } + List list = new ArrayList(refs); + Collections.sort(list); + return list; + } + + /** + * The total number of commits in the push. + * + * @return the number of commits in the push + */ + public int getCommitCount() { + return commits.size(); + } + + /** + * Returns all commits in the push. + * + * @return a list of commits + */ + public List getCommits() { + List list = new ArrayList(commits); + Collections.sort(list); + return list; + } + + /** + * Returns all commits that belong to a particular ref + * + * @param ref + * @return a list of commits + */ + public List getCommits(String ref) { + List list = new ArrayList(); + for (RepositoryCommit commit : commits) { + if (commit.branch.equals(ref)) { + list.add(commit); + } + } + Collections.sort(list); + return list; + } + + @Override + public int compareTo(PushLogEntry o) { + // reverse chronological order + return o.date.compareTo(date); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(MessageFormat.format("{0,date,yyyy-MM-dd HH:mm}: {1} pushed {2,number,0} commit{3} to {4} ", + date, user.getDisplayName(), commits.size(), commits.size() == 1 ? "":"s", repository)); + for (Map.Entry entry : refUpdates.entrySet()) { + String ref = entry.getKey(); + ReceiveCommand.Type type = entry.getValue(); + sb.append("\n ").append(ref).append(' ').append(type.name()).append('\n'); + for (RepositoryCommit commit : getCommits(ref)) { + sb.append(" ").append(commit.toString()).append('\n'); + } + } + return sb.toString(); + } +} diff --git a/src/main/java/com/gitblit/models/RefModel.java b/src/main/java/com/gitblit/models/RefModel.java new file mode 100644 index 00000000..8489c817 --- /dev/null +++ b/src/main/java/com/gitblit/models/RefModel.java @@ -0,0 +1,148 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.Date; + +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevObject; +import org.eclipse.jgit.revwalk.RevTag; + +/** + * RefModel is a serializable model class that represents a tag or branch and + * includes the referenced object. + * + * @author James Moger + * + */ +public class RefModel implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + public final String displayName; + public final RevObject referencedObject; + public transient Ref reference; + + public RefModel(String displayName, Ref ref, RevObject refObject) { + this.displayName = displayName; + this.reference = ref; + this.referencedObject = refObject; + } + + public Date getDate() { + Date date = new Date(0); + if (referencedObject != null) { + if (referencedObject instanceof RevTag) { + RevTag tag = (RevTag) referencedObject; + if (tag.getTaggerIdent() != null) { + date = tag.getTaggerIdent().getWhen(); + } + } else if (referencedObject instanceof RevCommit) { + date = ((RevCommit) referencedObject).getCommitterIdent().getWhen(); + } + } + return date; + } + + public String getName() { + if (reference == null) { + return displayName; + } + return reference.getName(); + } + + public int getReferencedObjectType() { + int type = referencedObject.getType(); + if (referencedObject instanceof RevTag) { + type = ((RevTag) referencedObject).getObject().getType(); + } + return type; + } + + public ObjectId getReferencedObjectId() { + if (referencedObject instanceof RevTag) { + return ((RevTag) referencedObject).getObject().getId(); + } + return referencedObject.getId(); + } + + public String getShortMessage() { + String message = ""; + if (referencedObject instanceof RevTag) { + message = ((RevTag) referencedObject).getShortMessage(); + } else if (referencedObject instanceof RevCommit) { + message = ((RevCommit) referencedObject).getShortMessage(); + } + return message; + } + + public String getFullMessage() { + String message = ""; + if (referencedObject instanceof RevTag) { + message = ((RevTag) referencedObject).getFullMessage(); + } else if (referencedObject instanceof RevCommit) { + message = ((RevCommit) referencedObject).getFullMessage(); + } + return message; + } + + public PersonIdent getAuthorIdent() { + if (referencedObject instanceof RevTag) { + return ((RevTag) referencedObject).getTaggerIdent(); + } else if (referencedObject instanceof RevCommit) { + return ((RevCommit) referencedObject).getAuthorIdent(); + } + return null; + } + + public ObjectId getObjectId() { + return reference.getObjectId(); + } + + public boolean isAnnotatedTag() { + if (referencedObject instanceof RevTag) { + return !getReferencedObjectId().equals(getObjectId()); + } + return reference.getPeeledObjectId() != null; + } + + @Override + public int hashCode() { + return getReferencedObjectId().hashCode() + getName().hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof RefModel) { + RefModel other = (RefModel) o; + return getName().equals(other.getName()); + } + return super.equals(o); + } + + @Override + public int compareTo(RefModel o) { + return getDate().compareTo(o.getDate()); + } + + @Override + public String toString() { + return displayName; + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/models/RegistrantAccessPermission.java b/src/main/java/com/gitblit/models/RegistrantAccessPermission.java new file mode 100644 index 00000000..8f4049a8 --- /dev/null +++ b/src/main/java/com/gitblit/models/RegistrantAccessPermission.java @@ -0,0 +1,149 @@ +/* + * Copyright 2012 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.models; + +import java.io.Serializable; + +import com.gitblit.Constants.AccessPermission; +import com.gitblit.Constants.PermissionType; +import com.gitblit.Constants.RegistrantType; +import com.gitblit.utils.StringUtils; + +/** + * Represents a Registrant-AccessPermission tuple. + * + * @author James Moger + */ +public class RegistrantAccessPermission implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public String registrant; + public AccessPermission permission; + public RegistrantType registrantType; + public PermissionType permissionType; + public boolean mutable; + public String source; + + public RegistrantAccessPermission() { + } + + public RegistrantAccessPermission(RegistrantType registrantType) { + this.registrantType = registrantType; + this.permissionType = PermissionType.EXPLICIT; + this.mutable = true; + } + + public RegistrantAccessPermission(String registrant, AccessPermission permission, PermissionType permissionType, RegistrantType registrantType, String source, boolean mutable) { + this.registrant = registrant; + this.permission = permission; + this.permissionType = permissionType; + this.registrantType = registrantType; + this.source = source; + this.mutable = mutable; + } + + public boolean isAdmin() { + return PermissionType.ADMINISTRATOR.equals(permissionType); + } + + public boolean isOwner() { + return PermissionType.OWNER.equals(permissionType); + } + + public boolean isExplicit() { + return PermissionType.EXPLICIT.equals(permissionType); + } + + public boolean isRegex() { + return PermissionType.REGEX.equals(permissionType); + } + + public boolean isTeam() { + return PermissionType.TEAM.equals(permissionType); + } + + public boolean isMissing() { + return PermissionType.MISSING.equals(permissionType); + } + + public int getScore() { + switch (registrantType) { + case REPOSITORY: + if (isAdmin()) { + return 0; + } + if (isOwner()) { + return 1; + } + if (isExplicit()) { + return 2; + } + if (isRegex()) { + return 3; + } + if (isTeam()) { + return 4; + } + default: + return 0; + } + } + + @Override + public int compareTo(RegistrantAccessPermission p) { + switch (registrantType) { + case REPOSITORY: + // repository permissions are sorted in score order + // to convey the order in which permissions are tested + int score1 = getScore(); + int score2 = p.getScore(); + if (score1 <= 2 && score2 <= 2) { + // group admin, owner, and explicit together + return StringUtils.compareRepositoryNames(registrant, p.registrant); + } + if (score1 < score2) { + return -1; + } else if (score2 < score1) { + return 1; + } + return StringUtils.compareRepositoryNames(registrant, p.registrant); + default: + // user and team permissions are string sorted + return registrant.toLowerCase().compareTo(p.registrant.toLowerCase()); + } + } + + @Override + public int hashCode() { + return registrant.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof RegistrantAccessPermission) { + RegistrantAccessPermission p = (RegistrantAccessPermission) o; + return registrant.equals(p.registrant); + } + + return false; + } + + @Override + public String toString() { + return permission.asRole(registrant); + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/models/RepositoryCommit.java b/src/main/java/com/gitblit/models/RepositoryCommit.java new file mode 100644 index 00000000..e68e8613 --- /dev/null +++ b/src/main/java/com/gitblit/models/RepositoryCommit.java @@ -0,0 +1,112 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.text.MessageFormat; +import java.util.List; + +import org.eclipse.jgit.lib.PersonIdent; +import org.eclipse.jgit.revwalk.RevCommit; + +/** + * Model class to represent a RevCommit, it's source repository, and the branch. + * This class is used by the activity page. + * + * @author James Moger + */ +public class RepositoryCommit implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public final String repository; + + public final String branch; + + private final RevCommit commit; + + private List refs; + + public RepositoryCommit(String repository, String branch, RevCommit commit) { + this.repository = repository; + this.branch = branch; + this.commit = commit; + } + + public void setRefs(List refs) { + this.refs = refs; + } + + public List getRefs() { + return refs; + } + + public String getName() { + return commit.getName(); + } + + public String getShortName() { + return commit.getName().substring(0, 8); + } + + public String getShortMessage() { + return commit.getShortMessage(); + } + + public int getParentCount() { + return commit.getParentCount(); + } + + public PersonIdent getAuthorIdent() { + return commit.getAuthorIdent(); + } + + public PersonIdent getCommitterIdent() { + return commit.getCommitterIdent(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof RepositoryCommit) { + RepositoryCommit commit = (RepositoryCommit) o; + return repository.equals(commit.repository) && getName().equals(commit.getName()); + } + return false; + } + + @Override + public int hashCode() { + return (repository + commit).hashCode(); + } + + @Override + public int compareTo(RepositoryCommit o) { + // reverse-chronological order + if (commit.getCommitTime() > o.commit.getCommitTime()) { + return -1; + } else if (commit.getCommitTime() < o.commit.getCommitTime()) { + return 1; + } + return 0; + } + + @Override + public String toString() { + return MessageFormat.format("{0} {1} {2,date,yyyy-MM-dd HH:mm} {3} {4}", + getShortName(), branch, getCommitterIdent().getWhen(), getAuthorIdent().getName(), + getShortMessage()); + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/models/RepositoryModel.java b/src/main/java/com/gitblit/models/RepositoryModel.java new file mode 100644 index 00000000..a2dab3c5 --- /dev/null +++ b/src/main/java/com/gitblit/models/RepositoryModel.java @@ -0,0 +1,243 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Constants.FederationStrategy; +import com.gitblit.utils.ArrayUtils; +import com.gitblit.utils.StringUtils; + +/** + * RepositoryModel is a serializable model class that represents a Gitblit + * repository including its configuration settings and access restriction. + * + * @author James Moger + * + */ +public class RepositoryModel implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + // field names are reflectively mapped in EditRepository page + public String name; + public String description; + public List owners; + public Date lastChange; + public boolean hasCommits; + public boolean showRemoteBranches; + public boolean useTickets; + public boolean useDocs; + public AccessRestrictionType accessRestriction; + public AuthorizationControl authorizationControl; + public boolean allowAuthenticated; + public boolean isFrozen; + public boolean showReadme; + public FederationStrategy federationStrategy; + public List federationSets; + public boolean isFederated; + public boolean skipSizeCalculation; + public boolean skipSummaryMetrics; + public String frequency; + public boolean isBare; + public String origin; + public String HEAD; + public List availableRefs; + public List indexedBranches; + public String size; + public List preReceiveScripts; + public List postReceiveScripts; + public List mailingLists; + public Map customFields; + public String projectPath; + private String displayName; + public boolean allowForks; + public Set forks; + public String originRepository; + public boolean verifyCommitter; + public String gcThreshold; + public int gcPeriod; + public int maxActivityCommits; + + public transient boolean isCollectingGarbage; + public Date lastGC; + public String sparkleshareId; + + public RepositoryModel() { + this("", "", "", new Date(0)); + } + + public RepositoryModel(String name, String description, String owner, Date lastchange) { + this.name = name; + this.description = description; + this.lastChange = lastchange; + this.accessRestriction = AccessRestrictionType.NONE; + this.authorizationControl = AuthorizationControl.NAMED; + this.federationSets = new ArrayList(); + this.federationStrategy = FederationStrategy.FEDERATE_THIS; + this.projectPath = StringUtils.getFirstPathElement(name); + this.owners = new ArrayList(); + + addOwner(owner); + } + + public List getLocalBranches() { + if (ArrayUtils.isEmpty(availableRefs)) { + return new ArrayList(); + } + List localBranches = new ArrayList(); + for (String ref : availableRefs) { + if (ref.startsWith("refs/heads")) { + localBranches.add(ref); + } + } + return localBranches; + } + + public void addFork(String repository) { + if (forks == null) { + forks = new TreeSet(); + } + forks.add(repository); + } + + public void removeFork(String repository) { + if (forks == null) { + return; + } + forks.remove(repository); + } + + public void resetDisplayName() { + displayName = null; + } + + @Override + public int hashCode() { + return name.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof RepositoryModel) { + return name.equals(((RepositoryModel) o).name); + } + return false; + } + + @Override + public String toString() { + if (displayName == null) { + displayName = StringUtils.stripDotGit(name); + } + return displayName; + } + + @Override + public int compareTo(RepositoryModel o) { + return StringUtils.compareRepositoryNames(name, o.name); + } + + public boolean isFork() { + return !StringUtils.isEmpty(originRepository); + } + + public boolean isOwner(String username) { + if (StringUtils.isEmpty(username) || ArrayUtils.isEmpty(owners)) { + return false; + } + return owners.contains(username.toLowerCase()); + } + + public boolean isPersonalRepository() { + return !StringUtils.isEmpty(projectPath) && projectPath.charAt(0) == '~'; + } + + public boolean isUsersPersonalRepository(String username) { + return !StringUtils.isEmpty(projectPath) && projectPath.equalsIgnoreCase("~" + username); + } + + public boolean allowAnonymousView() { + return !accessRestriction.atLeast(AccessRestrictionType.VIEW); + } + + public boolean isSparkleshared() { + return !StringUtils.isEmpty(sparkleshareId); + } + + public RepositoryModel cloneAs(String cloneName) { + RepositoryModel clone = new RepositoryModel(); + clone.originRepository = name; + clone.name = cloneName; + clone.projectPath = StringUtils.getFirstPathElement(cloneName); + clone.isBare = true; + clone.description = description; + clone.accessRestriction = AccessRestrictionType.PUSH; + clone.authorizationControl = AuthorizationControl.NAMED; + clone.federationStrategy = federationStrategy; + clone.showReadme = showReadme; + clone.showRemoteBranches = false; + clone.allowForks = false; + clone.useDocs = useDocs; + clone.useTickets = useTickets; + clone.skipSizeCalculation = skipSizeCalculation; + clone.skipSummaryMetrics = skipSummaryMetrics; + clone.sparkleshareId = sparkleshareId; + return clone; + } + + public void addOwner(String username) { + if (!StringUtils.isEmpty(username)) { + String name = username.toLowerCase(); + // a set would be more efficient, but this complicates JSON + // deserialization so we enforce uniqueness with an arraylist + if (!owners.contains(name)) { + owners.add(name); + } + } + } + + public void removeOwner(String username) { + if (!StringUtils.isEmpty(username)) { + owners.remove(username.toLowerCase()); + } + } + + public void addOwners(Collection usernames) { + if (!ArrayUtils.isEmpty(usernames)) { + for (String username : usernames) { + addOwner(username); + } + } + } + + public void removeOwners(Collection usernames) { + if (!ArrayUtils.isEmpty(owners)) { + for (String username : usernames) { + removeOwner(username); + } + } + } +} diff --git a/src/main/java/com/gitblit/models/SearchResult.java b/src/main/java/com/gitblit/models/SearchResult.java new file mode 100644 index 00000000..efd1b075 --- /dev/null +++ b/src/main/java/com/gitblit/models/SearchResult.java @@ -0,0 +1,70 @@ +package com.gitblit.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import com.gitblit.Constants.SearchObjectType; + +/** + * Model class that represents a search result. + * + * @author James Moger + * + */ +public class SearchResult implements Serializable { + + private static final long serialVersionUID = 1L; + + public int hitId; + + public int totalHits; + + public float score; + + public Date date; + + public String author; + + public String committer; + + public String summary; + + public String fragment; + + public String repository; + + public String branch; + + public String commitId; + + public String path; + + public String issueId; + + public List tags; + + public List labels; + + public SearchObjectType type; + + public SearchResult() { + } + + public String getId() { + switch (type) { + case blob: + return path; + case commit: + return commitId; + case issue: + return issueId; + } + return commitId; + } + + @Override + public String toString() { + return score + " : " + type.name() + " : " + repository + " : " + getId() + " (" + branch + ")"; + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/models/ServerSettings.java b/src/main/java/com/gitblit/models/ServerSettings.java new file mode 100644 index 00000000..27199b41 --- /dev/null +++ b/src/main/java/com/gitblit/models/ServerSettings.java @@ -0,0 +1,69 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * Server settings represents the settings of the Gitblit server including all + * setting metadata such as name, current value, default value, description, and + * directives. It is a model class for serialization and presentation, but not + * for persistence. + * + * @author James Moger + */ +public class ServerSettings implements Serializable { + + private final Map settings; + + private static final long serialVersionUID = 1L; + + public List pushScripts; + + public boolean supportsCredentialChanges; + + public boolean supportsDisplayNameChanges; + + public boolean supportsEmailAddressChanges; + + public boolean supportsTeamMembershipChanges; + + public ServerSettings() { + settings = new TreeMap(); + } + + public List getKeys() { + return new ArrayList(settings.keySet()); + } + + public void add(SettingModel setting) { + if (setting != null) { + settings.put(setting.name, setting); + } + } + + public SettingModel get(String key) { + return settings.get(key); + } + + public boolean hasKey(String key) { + return settings.containsKey(key); + } +} diff --git a/src/main/java/com/gitblit/models/ServerStatus.java b/src/main/java/com/gitblit/models/ServerStatus.java new file mode 100644 index 00000000..3a1e0306 --- /dev/null +++ b/src/main/java/com/gitblit/models/ServerStatus.java @@ -0,0 +1,83 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.Date; +import java.util.Map; +import java.util.TreeMap; + +import com.gitblit.Constants; + +/** + * ServerStatus encapsulates runtime status information about the server + * including some information about the system environment. + * + * @author James Moger + * + */ +public class ServerStatus implements Serializable { + + private static final long serialVersionUID = 1L; + + public final Date bootDate; + + public final String version; + + public final String releaseDate; + + public final boolean isGO; + + public final Map systemProperties; + + public final long heapMaximum; + + public volatile long heapAllocated; + + public volatile long heapFree; + + public String servletContainer; + + public ServerStatus(boolean isGO) { + this.bootDate = new Date(); + this.version = Constants.getVersion(); + this.releaseDate = Constants.getBuildDate(); + this.isGO = isGO; + + this.heapMaximum = Runtime.getRuntime().maxMemory(); + + this.systemProperties = new TreeMap(); + put("file.encoding"); + put("java.home"); + put("java.awt.headless"); + put("java.io.tmpdir"); + put("java.runtime.name"); + put("java.runtime.version"); + put("java.vendor"); + put("java.version"); + put("java.vm.info"); + put("java.vm.name"); + put("java.vm.vendor"); + put("java.vm.version"); + put("os.arch"); + put("os.name"); + put("os.version"); + } + + private void put(String key) { + systemProperties.put(key, System.getProperty(key)); + } +} diff --git a/src/main/java/com/gitblit/models/SettingModel.java b/src/main/java/com/gitblit/models/SettingModel.java new file mode 100644 index 00000000..a04126e1 --- /dev/null +++ b/src/main/java/com/gitblit/models/SettingModel.java @@ -0,0 +1,162 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import com.gitblit.utils.StringUtils; + +/** + * SettingModel represents a setting and all its metadata: name, current value, + * default value, description, and directives. + * + * @author James Moger + */ +public class SettingModel implements Serializable { + + public static final String SPACE_DELIMITED = "SPACE-DELIMITED"; + + public static final String CASE_SENSITIVE = "CASE-SENSITIVE"; + + public static final String RESTART_REQUIRED = "RESTART REQUIRED"; + + public static final String SINCE = "SINCE"; + + public String name; + public volatile String currentValue; + public String defaultValue; + public String description; + public String since; + public boolean caseSensitive; + public boolean restartRequired; + public boolean spaceDelimited; + + private static final long serialVersionUID = 1L; + + public SettingModel() { + } + + /** + * Returns true if the current value is the default value. + * + * @return true if current value is the default value + */ + public boolean isDefaultValue() { + return (currentValue != null && currentValue.equals(defaultValue)) + || currentValue.trim().length() == 0; + } + + /** + * Returns the boolean value for the currentValue. If the currentValue can + * not be interpreted as a boolean, the defaultValue is returned. + * + * @param defaultValue + * @return key value or defaultValue + */ + public boolean getBoolean(boolean defaultValue) { + if (!StringUtils.isEmpty(currentValue)) { + return Boolean.parseBoolean(currentValue.trim()); + } + return defaultValue; + } + + /** + * Returns the integer value for the currentValue. If the currentValue can + * not be interpreted as an integer, the defaultValue is returned. + * + * @param defaultValue + * @return key value or defaultValue + */ + public int getInteger(int defaultValue) { + try { + if (!StringUtils.isEmpty(currentValue)) { + return Integer.parseInt(currentValue.trim()); + } + } catch (NumberFormatException e) { + } + return defaultValue; + } + + /** + * Returns the char value for currentValue. If the currentValue can not be + * interpreted as a char, the defaultValue is returned. + * + * @param defaultValue + * @return key value or defaultValue + */ + public char getChar(char defaultValue) { + if (!StringUtils.isEmpty(currentValue)) { + return currentValue.trim().charAt(0); + } + return defaultValue; + } + + /** + * Returns the string value for currentValue. If the currentValue is null, + * the defaultValue is returned. + * + * @param defaultValue + * @return key value or defaultValue + */ + public String getString(String defaultValue) { + if (currentValue != null) { + return currentValue.trim(); + } + return defaultValue; + } + + /** + * Returns a list of space-separated strings from the specified key. + * + * @return list of strings + */ + public List getStrings() { + return getStrings(" "); + } + + /** + * Returns a list of strings from the currentValue using the specified + * string separator. + * + * @param separator + * @return list of strings + */ + public List getStrings(String separator) { + List strings = new ArrayList(); + strings = StringUtils.getStringsFromValue(currentValue, separator); + return strings; + } + + /** + * Returns a map of strings from the current value. + * + * @return map of string, string + */ + public Map getMap() { + Map map = new LinkedHashMap(); + for (String string : getStrings()) { + String[] kvp = string.split("=", 2); + String key = kvp[0]; + String value = kvp[1]; + map.put(key, value); + } + return map; + } +} diff --git a/src/main/java/com/gitblit/models/SubmoduleModel.java b/src/main/java/com/gitblit/models/SubmoduleModel.java new file mode 100644 index 00000000..47f84b95 --- /dev/null +++ b/src/main/java/com/gitblit/models/SubmoduleModel.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012 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.models; + +import java.io.Serializable; + +/** + * SubmoduleModel is a serializable model class that represents a git submodule + * definition. + * + * @author James Moger + * + */ +public class SubmoduleModel implements Serializable { + + private static final long serialVersionUID = 1L; + + public final String name; + public final String path; + public final String url; + + public boolean hasSubmodule; + public String gitblitPath; + + public SubmoduleModel(String name, String path, String url) { + this.name = name; + this.path = path; + this.url = url; + } + + public String toString() { + return path + "=" + url; + } +} \ No newline at end of file diff --git a/src/main/java/com/gitblit/models/TeamModel.java b/src/main/java/com/gitblit/models/TeamModel.java new file mode 100644 index 00000000..9587ca7a --- /dev/null +++ b/src/main/java/com/gitblit/models/TeamModel.java @@ -0,0 +1,310 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.gitblit.Constants.AccessPermission; +import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.PermissionType; +import com.gitblit.Constants.RegistrantType; +import com.gitblit.Constants.Unused; +import com.gitblit.utils.StringUtils; + +/** + * TeamModel is a serializable model class that represents a group of users and + * a list of accessible repositories. + * + * @author James Moger + * + */ +public class TeamModel implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + // field names are reflectively mapped in EditTeam page + public String name; + public boolean canAdmin; + public boolean canFork; + public boolean canCreate; + public final Set users = new HashSet(); + // retained for backwards-compatibility with RPC clients + @Deprecated + public final Set repositories = new HashSet(); + public final Map permissions = new LinkedHashMap(); + public final Set mailingLists = new HashSet(); + public final List preReceiveScripts = new ArrayList(); + public final List postReceiveScripts = new ArrayList(); + + public TeamModel(String name) { + this.name = name; + } + + /** + * @use hasRepositoryPermission + * @param name + * @return + */ + @Deprecated + @Unused + public boolean hasRepository(String name) { + return hasRepositoryPermission(name); + } + + @Deprecated + @Unused + public void addRepository(String name) { + addRepositoryPermission(name); + } + + @Deprecated + @Unused + public void addRepositories(Collection names) { + addRepositoryPermissions(names); + } + + @Deprecated + @Unused + public void removeRepository(String name) { + removeRepositoryPermission(name); + } + + + /** + * Returns a list of repository permissions for this team. + * + * @return the team's list of permissions + */ + public List getRepositoryPermissions() { + List list = new ArrayList(); + if (canAdmin) { + // team has REWIND access to all repositories + return list; + } + for (Map.Entry entry : permissions.entrySet()) { + String registrant = entry.getKey(); + String source = null; + boolean editable = true; + PermissionType pType = PermissionType.EXPLICIT; + if (StringUtils.findInvalidCharacter(registrant) != null) { + // a regex will have at least 1 invalid character + pType = PermissionType.REGEX; + source = registrant; + } + list.add(new RegistrantAccessPermission(registrant, entry.getValue(), pType, RegistrantType.REPOSITORY, source, editable)); + } + Collections.sort(list); + return list; + } + + /** + * Returns true if the team has any type of specified access permission for + * this repository. + * + * @param name + * @return true if team has a specified access permission for the repository + */ + public boolean hasRepositoryPermission(String name) { + String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); + if (permissions.containsKey(repository)) { + // exact repository permission specified + return true; + } else { + // search for regex permission match + for (String key : permissions.keySet()) { + if (name.matches(key)) { + AccessPermission p = permissions.get(key); + if (p != null) { + return true; + } + } + } + } + return false; + } + + /** + * Returns true if the team has an explicitly specified access permission for + * this repository. + * + * @param name + * @return if the team has an explicitly specified access permission + */ + public boolean hasExplicitRepositoryPermission(String name) { + String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); + return permissions.containsKey(repository); + } + + /** + * Adds a repository permission to the team. + *

+ * Role may be formatted as: + *

    + *
  • myrepo.git (this is implicitly RW+) + *
  • RW+:myrepo.git + *
+ * @param role + */ + public void addRepositoryPermission(String role) { + AccessPermission permission = AccessPermission.permissionFromRole(role); + String repository = AccessPermission.repositoryFromRole(role).toLowerCase(); + repositories.add(repository); + permissions.put(repository, permission); + } + + public void addRepositoryPermissions(Collection roles) { + for (String role:roles) { + addRepositoryPermission(role); + } + } + + public AccessPermission removeRepositoryPermission(String name) { + String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); + repositories.remove(repository); + return permissions.remove(repository); + } + + public void setRepositoryPermission(String repository, AccessPermission permission) { + permissions.put(repository.toLowerCase(), permission); + repositories.add(repository.toLowerCase()); + } + + public RegistrantAccessPermission getRepositoryPermission(RepositoryModel repository) { + RegistrantAccessPermission ap = new RegistrantAccessPermission(); + ap.registrant = name; + ap.registrantType = RegistrantType.TEAM; + ap.permission = AccessPermission.NONE; + ap.mutable = false; + + if (canAdmin) { + ap.permissionType = PermissionType.ADMINISTRATOR; + ap.permission = AccessPermission.REWIND; + return ap; + } + + if (permissions.containsKey(repository.name.toLowerCase())) { + // exact repository permission specified + AccessPermission p = permissions.get(repository.name.toLowerCase()); + if (p != null) { + ap.permissionType = PermissionType.EXPLICIT; + ap.permission = p; + ap.mutable = true; + return ap; + } + } else { + // search for case-insensitive regex permission match + for (String key : permissions.keySet()) { + if (StringUtils.matchesIgnoreCase(repository.name, key)) { + AccessPermission p = permissions.get(key); + if (p != null) { + // take first match + ap.permissionType = PermissionType.REGEX; + ap.permission = p; + ap.source = key; + return ap; + } + } + } + } + return ap; + } + + protected boolean canAccess(RepositoryModel repository, AccessRestrictionType ifRestriction, AccessPermission requirePermission) { + if (repository.accessRestriction.atLeast(ifRestriction)) { + RegistrantAccessPermission ap = getRepositoryPermission(repository); + return ap.permission.atLeast(requirePermission); + } + return true; + } + + public boolean canView(RepositoryModel repository) { + return canAccess(repository, AccessRestrictionType.VIEW, AccessPermission.VIEW); + } + + public boolean canClone(RepositoryModel repository) { + return canAccess(repository, AccessRestrictionType.CLONE, AccessPermission.CLONE); + } + + public boolean canPush(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.PUSH); + } + + public boolean canCreateRef(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.CREATE); + } + + public boolean canDeleteRef(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.DELETE); + } + + public boolean canRewindRef(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.REWIND); + } + + public boolean hasUser(String name) { + return users.contains(name.toLowerCase()); + } + + public void addUser(String name) { + users.add(name.toLowerCase()); + } + + public void addUsers(Collection names) { + for (String name:names) { + users.add(name.toLowerCase()); + } + } + + public void removeUser(String name) { + users.remove(name.toLowerCase()); + } + + public void addMailingLists(Collection addresses) { + for (String address:addresses) { + mailingLists.add(address.toLowerCase()); + } + } + + @Override + public String toString() { + return name; + } + + @Override + public int compareTo(TeamModel o) { + return name.compareTo(o.name); + } +} diff --git a/src/main/java/com/gitblit/models/TicketModel.java b/src/main/java/com/gitblit/models/TicketModel.java new file mode 100644 index 00000000..b8043c6c --- /dev/null +++ b/src/main/java/com/gitblit/models/TicketModel.java @@ -0,0 +1,119 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * TicketModel is a serializable model class that represents a Ticgit ticket. + * + * @author James Moger + * + */ +public class TicketModel implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public String id; + public String name; + public String title; + public String state; + public Date date; + public String handler; + public String milestone; + public String email; + public String author; + public List comments; + public List tags; + + public TicketModel(String ticketName) throws ParseException { + state = ""; + name = ticketName; + comments = new ArrayList(); + tags = new ArrayList(); + + String[] chunks = name.split("_"); + if (chunks.length == 3) { + date = new Date(Long.parseLong(chunks[0]) * 1000L); + title = chunks[1].replace('-', ' '); + } + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof TicketModel) { + TicketModel other = (TicketModel) o; + return id.equals(other.id); + } + return super.equals(o); + } + + @Override + public int compareTo(TicketModel o) { + return date.compareTo(o.date); + } + + /** + * Comment is a serializable model class that represents a Ticgit ticket + * comment. + * + * @author James Moger + * + */ + public static class Comment implements Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public String text; + public String author; + public Date date; + + public Comment(String filename, String content) throws ParseException { + String[] chunks = filename.split("_", -1); + this.date = new Date(Long.parseLong(chunks[1]) * 1000L); + this.author = chunks[2]; + this.text = content; + } + + @Override + public int hashCode() { + return text.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof Comment) { + Comment other = (Comment) o; + return text.equals(other.text); + } + return super.equals(o); + } + + @Override + public int compareTo(Comment o) { + return date.compareTo(o.date); + } + } +} diff --git a/src/main/java/com/gitblit/models/UserModel.java b/src/main/java/com/gitblit/models/UserModel.java new file mode 100644 index 00000000..bec011d9 --- /dev/null +++ b/src/main/java/com/gitblit/models/UserModel.java @@ -0,0 +1,613 @@ +/* + * Copyright 2011 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.models; + +import java.io.Serializable; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import com.gitblit.Constants.AccessPermission; +import com.gitblit.Constants.AccessRestrictionType; +import com.gitblit.Constants.AccountType; +import com.gitblit.Constants.AuthorizationControl; +import com.gitblit.Constants.PermissionType; +import com.gitblit.Constants.RegistrantType; +import com.gitblit.Constants.Unused; +import com.gitblit.utils.ArrayUtils; +import com.gitblit.utils.StringUtils; + +/** + * UserModel is a serializable model class that represents a user and the user's + * restricted repository memberships. Instances of UserModels are also used as + * servlet user principals. + * + * @author James Moger + * + */ +public class UserModel implements Principal, Serializable, Comparable { + + private static final long serialVersionUID = 1L; + + public static final UserModel ANONYMOUS = new UserModel(); + + // field names are reflectively mapped in EditUser page + public String username; + public String password; + public String cookie; + public String displayName; + public String emailAddress; + public String organizationalUnit; + public String organization; + public String locality; + public String stateProvince; + public String countryCode; + public boolean canAdmin; + public boolean canFork; + public boolean canCreate; + public boolean excludeFromFederation; + // retained for backwards-compatibility with RPC clients + @Deprecated + public final Set repositories = new HashSet(); + public final Map permissions = new LinkedHashMap(); + public final Set teams = new TreeSet(); + + // non-persisted fields + public boolean isAuthenticated; + public AccountType accountType; + + public UserModel(String username) { + this.username = username; + this.isAuthenticated = true; + this.accountType = AccountType.LOCAL; + } + + private UserModel() { + this.username = "$anonymous"; + this.isAuthenticated = false; + this.accountType = AccountType.LOCAL; + } + + public boolean isLocalAccount() { + return accountType.isLocal(); + } + + /** + * This method does not take into consideration Ownership where the + * administrator has not explicitly granted access to the owner. + * + * @param repositoryName + * @return + */ + @Deprecated + public boolean canAccessRepository(String repositoryName) { + return canAdmin() || repositories.contains(repositoryName.toLowerCase()) + || hasTeamAccess(repositoryName); + } + + @Deprecated + @Unused + public boolean canAccessRepository(RepositoryModel repository) { + boolean isOwner = repository.isOwner(username); + boolean allowAuthenticated = isAuthenticated && AuthorizationControl.AUTHENTICATED.equals(repository.authorizationControl); + return canAdmin() || isOwner || repositories.contains(repository.name.toLowerCase()) + || hasTeamAccess(repository.name) || allowAuthenticated; + } + + @Deprecated + @Unused + public boolean hasTeamAccess(String repositoryName) { + for (TeamModel team : teams) { + if (team.hasRepositoryPermission(repositoryName)) { + return true; + } + } + return false; + } + + @Deprecated + @Unused + public boolean hasRepository(String name) { + return hasRepositoryPermission(name); + } + + @Deprecated + @Unused + public void addRepository(String name) { + addRepositoryPermission(name); + } + + @Deprecated + @Unused + public void removeRepository(String name) { + removeRepositoryPermission(name); + } + + /** + * Returns a list of repository permissions for this user exclusive of + * permissions inherited from team memberships. + * + * @return the user's list of permissions + */ + public List getRepositoryPermissions() { + List list = new ArrayList(); + if (canAdmin()) { + // user has REWIND access to all repositories + return list; + } + for (Map.Entry entry : permissions.entrySet()) { + String registrant = entry.getKey(); + AccessPermission ap = entry.getValue(); + String source = null; + boolean mutable = true; + PermissionType pType = PermissionType.EXPLICIT; + if (isMyPersonalRepository(registrant)) { + pType = PermissionType.OWNER; + ap = AccessPermission.REWIND; + mutable = false; + } else if (StringUtils.findInvalidCharacter(registrant) != null) { + // a regex will have at least 1 invalid character + pType = PermissionType.REGEX; + source = registrant; + } + list.add(new RegistrantAccessPermission(registrant, ap, pType, RegistrantType.REPOSITORY, source, mutable)); + } + Collections.sort(list); + + // include immutable team permissions, being careful to preserve order + Set set = new LinkedHashSet(list); + for (TeamModel team : teams) { + for (RegistrantAccessPermission teamPermission : team.getRepositoryPermissions()) { + // we can not change an inherited team permission, though we can override + teamPermission.registrantType = RegistrantType.REPOSITORY; + teamPermission.permissionType = PermissionType.TEAM; + teamPermission.source = team.name; + teamPermission.mutable = false; + set.add(teamPermission); + } + } + return new ArrayList(set); + } + + /** + * Returns true if the user has any type of specified access permission for + * this repository. + * + * @param name + * @return true if user has a specified access permission for the repository + */ + public boolean hasRepositoryPermission(String name) { + String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); + if (permissions.containsKey(repository)) { + // exact repository permission specified + return true; + } else { + // search for regex permission match + for (String key : permissions.keySet()) { + if (name.matches(key)) { + AccessPermission p = permissions.get(key); + if (p != null) { + return true; + } + } + } + } + return false; + } + + /** + * Returns true if the user has an explicitly specified access permission for + * this repository. + * + * @param name + * @return if the user has an explicitly specified access permission + */ + public boolean hasExplicitRepositoryPermission(String name) { + String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); + return permissions.containsKey(repository); + } + + /** + * Returns true if the user's team memberships specify an access permission for + * this repository. + * + * @param name + * @return if the user's team memberships specifi an access permission + */ + public boolean hasTeamRepositoryPermission(String name) { + if (teams != null) { + for (TeamModel team : teams) { + if (team.hasRepositoryPermission(name)) { + return true; + } + } + } + return false; + } + + /** + * Adds a repository permission to the team. + *

+ * Role may be formatted as: + *

    + *
  • myrepo.git (this is implicitly RW+) + *
  • RW+:myrepo.git + *
+ * @param role + */ + public void addRepositoryPermission(String role) { + AccessPermission permission = AccessPermission.permissionFromRole(role); + String repository = AccessPermission.repositoryFromRole(role).toLowerCase(); + repositories.add(repository); + permissions.put(repository, permission); + } + + public AccessPermission removeRepositoryPermission(String name) { + String repository = AccessPermission.repositoryFromRole(name).toLowerCase(); + repositories.remove(repository); + return permissions.remove(repository); + } + + public void setRepositoryPermission(String repository, AccessPermission permission) { + permissions.put(repository.toLowerCase(), permission); + } + + public RegistrantAccessPermission getRepositoryPermission(RepositoryModel repository) { + RegistrantAccessPermission ap = new RegistrantAccessPermission(); + ap.registrant = username; + ap.registrantType = RegistrantType.USER; + ap.permission = AccessPermission.NONE; + ap.mutable = false; + + if (AccessRestrictionType.NONE.equals(repository.accessRestriction)) { + // anonymous rewind + ap.permissionType = PermissionType.ADMINISTRATOR; + ap.permission = AccessPermission.REWIND; + return ap; + } + + // administrator + if (canAdmin()) { + ap.permissionType = PermissionType.ADMINISTRATOR; + ap.permission = AccessPermission.REWIND; + if (!canAdmin) { + // administator permission from team membership + for (TeamModel team : teams) { + if (team.canAdmin) { + ap.source = team.name; + break; + } + } + } + return ap; + } + + // repository owner - either specified owner or personal repository + if (repository.isOwner(username) || repository.isUsersPersonalRepository(username)) { + ap.permissionType = PermissionType.OWNER; + ap.permission = AccessPermission.REWIND; + return ap; + } + + if (AuthorizationControl.AUTHENTICATED.equals(repository.authorizationControl) && isAuthenticated) { + // AUTHENTICATED is a shortcut for authorizing all logged-in users RW+ access + ap.permission = AccessPermission.REWIND; + return ap; + } + + // explicit user permission OR user regex match is used + // if that fails, then the best team permission is used + if (permissions.containsKey(repository.name.toLowerCase())) { + // exact repository permission specified, use it + AccessPermission p = permissions.get(repository.name.toLowerCase()); + if (p != null) { + ap.permissionType = PermissionType.EXPLICIT; + ap.permission = p; + ap.mutable = true; + return ap; + } + } else { + // search for case-insensitive regex permission match + for (String key : permissions.keySet()) { + if (StringUtils.matchesIgnoreCase(repository.name, key)) { + AccessPermission p = permissions.get(key); + if (p != null) { + // take first match + ap.permissionType = PermissionType.REGEX; + ap.permission = p; + ap.source = key; + return ap; + } + } + } + } + + // try to find a team match + for (TeamModel team : teams) { + RegistrantAccessPermission p = team.getRepositoryPermission(repository); + if (p.permission.exceeds(ap.permission)) { + // use highest team permission + ap.permission = p.permission; + ap.source = team.name; + ap.permissionType = PermissionType.TEAM; + } + } + + return ap; + } + + protected boolean canAccess(RepositoryModel repository, AccessRestrictionType ifRestriction, AccessPermission requirePermission) { + if (repository.accessRestriction.atLeast(ifRestriction)) { + RegistrantAccessPermission ap = getRepositoryPermission(repository); + return ap.permission.atLeast(requirePermission); + } + return true; + } + + public boolean canView(RepositoryModel repository) { + return canAccess(repository, AccessRestrictionType.VIEW, AccessPermission.VIEW); + } + + public boolean canView(RepositoryModel repository, String ref) { + // Default UserModel doesn't implement ref-level security. + // Other Realms (i.e. Gerrit) may override this method. + return canView(repository); + } + + public boolean canClone(RepositoryModel repository) { + return canAccess(repository, AccessRestrictionType.CLONE, AccessPermission.CLONE); + } + + public boolean canPush(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.PUSH); + } + + public boolean canCreateRef(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.CREATE); + } + + public boolean canDeleteRef(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.DELETE); + } + + public boolean canRewindRef(RepositoryModel repository) { + if (repository.isFrozen) { + return false; + } + return canAccess(repository, AccessRestrictionType.PUSH, AccessPermission.REWIND); + } + + public boolean canFork(RepositoryModel repository) { + if (repository.isUsersPersonalRepository(username)) { + // can not fork your own repository + return false; + } + if (canAdmin() || repository.isOwner(username)) { + return true; + } + if (!repository.allowForks) { + return false; + } + if (!isAuthenticated || !canFork()) { + return false; + } + return canClone(repository); + } + + public boolean canDelete(RepositoryModel model) { + return canAdmin() || model.isUsersPersonalRepository(username); + } + + public boolean canEdit(RepositoryModel model) { + return canAdmin() || model.isUsersPersonalRepository(username) || model.isOwner(username); + } + + /** + * This returns true if the user has fork privileges or the user has fork + * privileges because of a team membership. + * + * @return true if the user can fork + */ + public boolean canFork() { + if (canFork) { + return true; + } + if (!ArrayUtils.isEmpty(teams)) { + for (TeamModel team : teams) { + if (team.canFork) { + return true; + } + } + } + return false; + } + + /** + * This returns true if the user has admin privileges or the user has admin + * privileges because of a team membership. + * + * @return true if the user can admin + */ + public boolean canAdmin() { + if (canAdmin) { + return true; + } + if (!ArrayUtils.isEmpty(teams)) { + for (TeamModel team : teams) { + if (team.canAdmin) { + return true; + } + } + } + return false; + } + + /** + * This returns true if the user has create privileges or the user has create + * privileges because of a team membership. + * + * @return true if the user can admin + */ + public boolean canCreate() { + if (canCreate) { + return true; + } + if (!ArrayUtils.isEmpty(teams)) { + for (TeamModel team : teams) { + if (team.canCreate) { + return true; + } + } + } + return false; + } + + /** + * Returns true if the user is allowed to create the specified repository. + * + * @param repository + * @return true if the user can create the repository + */ + public boolean canCreate(String repository) { + if (canAdmin()) { + // admins can create any repository + return true; + } + if (canCreate) { + String projectPath = StringUtils.getFirstPathElement(repository); + if (!StringUtils.isEmpty(projectPath) && projectPath.equalsIgnoreCase("~" + username)) { + // personal repository + return true; + } + } + return false; + } + + public boolean isTeamMember(String teamname) { + for (TeamModel team : teams) { + if (team.name.equalsIgnoreCase(teamname)) { + return true; + } + } + return false; + } + + public TeamModel getTeam(String teamname) { + if (teams == null) { + return null; + } + for (TeamModel team : teams) { + if (team.name.equalsIgnoreCase(teamname)) { + return team; + } + } + return null; + } + + @Override + public String getName() { + return username; + } + + public String getDisplayName() { + if (StringUtils.isEmpty(displayName)) { + return username; + } + return displayName; + } + + public String getPersonalPath() { + return "~" + username; + } + + @Override + public int hashCode() { + return username.hashCode(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof UserModel) { + return username.equals(((UserModel) o).username); + } + return false; + } + + @Override + public String toString() { + return username; + } + + @Override + public int compareTo(UserModel o) { + return username.compareTo(o.username); + } + + /** + * Returns true if the name/email pair match this user account. + * + * @param name + * @param email + * @return true, if the name and email address match this account + */ + public boolean is(String name, String email) { + // at a minimum a usename or display name must be supplied + if (StringUtils.isEmpty(name)) { + return false; + } + boolean nameVerified = name.equalsIgnoreCase(username) || name.equalsIgnoreCase(getDisplayName()); + boolean emailVerified = false; + if (StringUtils.isEmpty(emailAddress)) { + // user account has not specified an email address + // rely on username/displayname verification + emailVerified = true; + } else { + // user account has specified an email address + // require email address verification + if (!StringUtils.isEmpty(email)) { + emailVerified = email.equalsIgnoreCase(emailAddress); + } + } + return nameVerified && emailVerified; + } + + @Deprecated + public boolean hasBranchPermission(String repositoryName, String branch) { + // Default UserModel doesn't implement branch-level security. Other Realms (i.e. Gerrit) may override this method. + return hasRepositoryPermission(repositoryName) || hasTeamRepositoryPermission(repositoryName); + } + + public boolean isMyPersonalRepository(String repository) { + String projectPath = StringUtils.getFirstPathElement(repository); + return !StringUtils.isEmpty(projectPath) && projectPath.equalsIgnoreCase("~" + username); + } +} -- cgit v1.2.3