diff options
author | James Moger <james.moger@gitblit.com> | 2013-03-27 12:46:05 -0400 |
---|---|---|
committer | James Moger <james.moger@gitblit.com> | 2013-03-27 17:22:08 -0400 |
commit | f6b200be4c8b90c26886c6cdd5809abac8c4ac15 (patch) | |
tree | a948dbcf6f24bf884ad95a8d6830b4ec4e1706cf /src/main/java/com/gitblit/models | |
parent | b79ade104858ce6714a7329b7629b331564a2ea5 (diff) | |
download | gitblit-f6b200be4c8b90c26886c6cdd5809abac8c4ac15.tar.gz gitblit-f6b200be4c8b90c26886c6cdd5809abac8c4ac15.zip |
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.
Diffstat (limited to 'src/main/java/com/gitblit/models')
27 files changed, 4016 insertions, 0 deletions
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<Activity> {
+
+ private static final long serialVersionUID = 1L;
+
+ public final Date startDate;
+
+ public final Date endDate;
+
+ private final Set<RepositoryCommit> commits;
+
+ private final Map<String, Metric> authorMetrics;
+
+ private final Map<String, Metric> 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<RepositoryCommit>();
+ authorMetrics = new HashMap<String, Metric>();
+ repositoryMetrics = new HashMap<String, Metric>();
+ }
+
+ /**
+ * 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<RepositoryCommit> getCommits() {
+ List<RepositoryCommit> list = new ArrayList<RepositoryCommit>(commits);
+ Collections.sort(list);
+ return list;
+ }
+
+ public Map<String, Metric> getAuthorMetrics() {
+ return authorMetrics;
+ }
+
+ public Map<String, Metric> 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<FederationModel> {
+
+ 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<String> exclusions = new ArrayList<String>();
+
+ public List<String> inclusions = new ArrayList<String>();
+
+ public Date lastPull;
+
+ public Date nextPull;
+
+ private Map<String, FederationPullStatus> results = new ConcurrentHashMap<String, FederationPullStatus>();
+
+ /**
+ * 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<RepositoryStatus> getStatusList() {
+ List<RepositoryStatus> list = new ArrayList<RepositoryStatus>();
+ for (Map.Entry<String, FederationPullStatus> 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<RepositoryStatus> {
+
+ 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<String, RepositoryModel> 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<String, RepositoryModel> 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<String, RepositoryModel> 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<FeedEntryModel> {
+
+ 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<String> 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<FeedModel> {
+
+ 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<ForkModel> forks; + + public ForkModel(RepositoryModel repository) { + this.repository = repository; + this.forks = new ArrayList<ForkModel>(); + } + + 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<ProfileObject> photos;
+// public Map<String, String> profileBackground;
+// public Map<String, String> name;
+
+ public List<ProfileObject> phoneNumbers;
+ public List<ProfileObject> emails;
+ public List<ProfileObject> ims;
+ public List<Account> accounts;
+ public List<ProfileObject> 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<IssueModel> {
+
+ 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<Change> 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<Change>();
+ }
+
+ 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<String> getLabels() {
+ List<String> list = new ArrayList<String>();
+ 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<Attachment> getAttachments() {
+ List<Attachment> list = new ArrayList<Attachment>();
+ 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<Change> {
+
+ 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<FieldChange> fieldChanges;
+
+ public Set<Attachment> 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<Attachment>();
+ }
+ 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<FieldChange>();
+ }
+ 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<Metric> {
+
+ 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<PathModel> {
+
+ 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<ProjectModel> {
+
+ 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<String> repositories = new HashSet<String>();
+
+ 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<String> 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<PushLogEntry> {
+
+ private static final long serialVersionUID = 1L;
+
+ public final String repository;
+
+ public final Date date;
+
+ public final UserModel user;
+
+ private final Set<RepositoryCommit> commits;
+
+ private final Map<String, ReceiveCommand.Type> 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<RepositoryCommit>();
+ this.refUpdates = new HashMap<String, ReceiveCommand.Type>();
+ }
+
+ /**
+ * 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<String, ReceiveCommand.Type> 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<String> getChangedBranches() {
+ return getChangedRefs(Constants.R_HEADS);
+ }
+
+ /**
+ * Returns the list of tags changed by the push.
+ *
+ * @return a list of tags
+ */
+ public List<String> getChangedTags() {
+ return getChangedRefs(Constants.R_TAGS);
+ }
+
+ /**
+ * Gets the changed refs in the push.
+ *
+ * @param baseRef
+ * @return the changed refs
+ */
+ protected List<String> getChangedRefs(String baseRef) {
+ Set<String> refs = new HashSet<String>();
+ for (String ref : refUpdates.keySet()) {
+ if (baseRef == null || ref.startsWith(baseRef)) {
+ refs.add(ref);
+ }
+ }
+ List<String> list = new ArrayList<String>(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<RepositoryCommit> getCommits() {
+ List<RepositoryCommit> list = new ArrayList<RepositoryCommit>(commits);
+ Collections.sort(list);
+ return list;
+ }
+
+ /**
+ * Returns all commits that belong to a particular ref
+ *
+ * @param ref
+ * @return a list of commits
+ */
+ public List<RepositoryCommit> getCommits(String ref) {
+ List<RepositoryCommit> list = new ArrayList<RepositoryCommit>();
+ 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<String, ReceiveCommand.Type> 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<RefModel> {
+
+ 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<RegistrantAccessPermission> { + + 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<RepositoryCommit> { + + private static final long serialVersionUID = 1L; + + public final String repository; + + public final String branch; + + private final RevCommit commit; + + private List<RefModel> refs; + + public RepositoryCommit(String repository, String branch, RevCommit commit) { + this.repository = repository; + this.branch = branch; + this.commit = commit; + } + + public void setRefs(List<RefModel> refs) { + this.refs = refs; + } + + public List<RefModel> 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<RepositoryModel> {
+
+ private static final long serialVersionUID = 1L;
+
+ // field names are reflectively mapped in EditRepository page
+ public String name;
+ public String description;
+ public List<String> 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<String> federationSets;
+ public boolean isFederated;
+ public boolean skipSizeCalculation;
+ public boolean skipSummaryMetrics;
+ public String frequency;
+ public boolean isBare;
+ public String origin;
+ public String HEAD;
+ public List<String> availableRefs;
+ public List<String> indexedBranches;
+ public String size;
+ public List<String> preReceiveScripts;
+ public List<String> postReceiveScripts;
+ public List<String> mailingLists;
+ public Map<String, String> customFields;
+ public String projectPath;
+ private String displayName;
+ public boolean allowForks;
+ public Set<String> 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<String>();
+ this.federationStrategy = FederationStrategy.FEDERATE_THIS;
+ this.projectPath = StringUtils.getFirstPathElement(name);
+ this.owners = new ArrayList<String>();
+
+ addOwner(owner);
+ }
+
+ public List<String> getLocalBranches() {
+ if (ArrayUtils.isEmpty(availableRefs)) {
+ return new ArrayList<String>();
+ }
+ List<String> localBranches = new ArrayList<String>();
+ 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<String>();
+ }
+ 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<String> usernames) {
+ if (!ArrayUtils.isEmpty(usernames)) {
+ for (String username : usernames) {
+ addOwner(username);
+ }
+ }
+ }
+
+ public void removeOwners(Collection<String> 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<String> tags;
+
+ public List<String> 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<String, SettingModel> settings;
+
+ private static final long serialVersionUID = 1L;
+
+ public List<String> pushScripts;
+
+ public boolean supportsCredentialChanges;
+
+ public boolean supportsDisplayNameChanges;
+
+ public boolean supportsEmailAddressChanges;
+
+ public boolean supportsTeamMembershipChanges;
+
+ public ServerSettings() {
+ settings = new TreeMap<String, SettingModel>();
+ }
+
+ public List<String> getKeys() {
+ return new ArrayList<String>(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<String, String> 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<String, String>();
+ 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<String> getStrings() {
+ return getStrings(" ");
+ }
+
+ /**
+ * Returns a list of strings from the currentValue using the specified
+ * string separator.
+ *
+ * @param separator
+ * @return list of strings
+ */
+ public List<String> getStrings(String separator) {
+ List<String> strings = new ArrayList<String>();
+ strings = StringUtils.getStringsFromValue(currentValue, separator);
+ return strings;
+ }
+
+ /**
+ * Returns a map of strings from the current value.
+ *
+ * @return map of string, string
+ */
+ public Map<String, String> getMap() {
+ Map<String, String> map = new LinkedHashMap<String, String>();
+ 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<TeamModel> {
+
+ 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<String> users = new HashSet<String>();
+ // retained for backwards-compatibility with RPC clients
+ @Deprecated
+ public final Set<String> repositories = new HashSet<String>();
+ public final Map<String, AccessPermission> permissions = new LinkedHashMap<String, AccessPermission>();
+ public final Set<String> mailingLists = new HashSet<String>();
+ public final List<String> preReceiveScripts = new ArrayList<String>();
+ public final List<String> postReceiveScripts = new ArrayList<String>();
+
+ 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<String> 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<RegistrantAccessPermission> getRepositoryPermissions() {
+ List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>();
+ if (canAdmin) {
+ // team has REWIND access to all repositories
+ return list;
+ }
+ for (Map.Entry<String, AccessPermission> 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.
+ * <p>
+ * Role may be formatted as:
+ * <ul>
+ * <li> myrepo.git <i>(this is implicitly RW+)</i>
+ * <li> RW+:myrepo.git
+ * </ul>
+ * @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<String> 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<String> names) {
+ for (String name:names) {
+ users.add(name.toLowerCase());
+ }
+ }
+
+ public void removeUser(String name) {
+ users.remove(name.toLowerCase());
+ }
+
+ public void addMailingLists(Collection<String> 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<TicketModel> {
+
+ 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<Comment> comments;
+ public List<String> tags;
+
+ public TicketModel(String ticketName) throws ParseException {
+ state = "";
+ name = ticketName;
+ comments = new ArrayList<Comment>();
+ tags = new ArrayList<String>();
+
+ 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<Comment> {
+
+ 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<UserModel> {
+
+ 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<String> repositories = new HashSet<String>();
+ public final Map<String, AccessPermission> permissions = new LinkedHashMap<String, AccessPermission>();
+ public final Set<TeamModel> teams = new TreeSet<TeamModel>();
+
+ // 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<RegistrantAccessPermission> getRepositoryPermissions() {
+ List<RegistrantAccessPermission> list = new ArrayList<RegistrantAccessPermission>();
+ if (canAdmin()) {
+ // user has REWIND access to all repositories
+ return list;
+ }
+ for (Map.Entry<String, AccessPermission> 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<RegistrantAccessPermission> set = new LinkedHashSet<RegistrantAccessPermission>(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<RegistrantAccessPermission>(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.
+ * <p>
+ * Role may be formatted as:
+ * <ul>
+ * <li> myrepo.git <i>(this is implicitly RW+)</i>
+ * <li> RW+:myrepo.git
+ * </ul>
+ * @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);
+ }
+}
|