| | |
| | | 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.
|
| | |
| | | */
|
| | | public class IssueModel implements Serializable, Comparable<IssueModel> {
|
| | |
|
| | | private static final long serialVersionUID = 1L;;
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public String id;
|
| | |
|
| | |
| | | public List<Change> changes;
|
| | |
|
| | | public IssueModel() {
|
| | | created = new Date();
|
| | | // the first applied change set the date appropriately
|
| | | created = new Date(0);
|
| | |
|
| | | type = Type.Defect;
|
| | | status = Status.New;
|
| | |
| | | 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.hasFieldChanges()) {
|
| | | FieldChange field = change.getField(Field.Labels);
|
| | | if (field != null) {
|
| | | labels = field.value.toString();
|
| | | }
|
| | | if (change.hasField(Field.Labels)) {
|
| | | labels = change.getString(Field.Labels);
|
| | | }
|
| | | }
|
| | | if (!StringUtils.isEmpty(labels)) {
|
| | | list.addAll(StringUtils.getStringsFromValue(labels, " "));
|
| | | }
|
| | | return list;
|
| | | }
|
| | |
|
| | | public boolean hasLabel(String label) {
|
| | | return getLabels().contains(label);
|
| | | }
|
| | |
|
| | | public Attachment getAttachment(String name) {
|
| | |
| | | return attachment;
|
| | | }
|
| | |
|
| | | public void addChange(Change change) {
|
| | | if (changes == null) {
|
| | | changes = new ArrayList<Change>();
|
| | | 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() {
|
| | | return summary;
|
| | | 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
|
| | |
| | | return id.hashCode();
|
| | | }
|
| | |
|
| | | public static class Change implements Serializable {
|
| | | public static class Change implements Serializable, Comparable<Change> {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public Date created;
|
| | | public final Date created;
|
| | |
|
| | | public String author;
|
| | | public final String author;
|
| | |
|
| | | public String id;
|
| | |
|
| | | public char code;
|
| | |
|
| | | public Comment comment;
|
| | |
|
| | | public List<FieldChange> fieldChanges;
|
| | | public Set<FieldChange> fieldChanges;
|
| | |
|
| | | public List<Attachment> attachments;
|
| | | public Set<Attachment> attachments;
|
| | |
|
| | | public void comment(String text) {
|
| | | comment = new Comment(text);
|
| | | 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;
|
| | | 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 boolean hasFieldChanges() {
|
| | | return !ArrayUtils.isEmpty(fieldChanges);
|
| | | }
|
| | |
|
| | | public FieldChange getField(Field field) {
|
| | | if (fieldChanges != null) {
|
| | | for (FieldChange fieldChange : fieldChanges) {
|
| | | if (fieldChange.field == field) {
|
| | | return fieldChange;
|
| | | }
|
| | | }
|
| | | }
|
| | | return null;
|
| | | }
|
| | |
|
| | | public void setField(Field field, Object value) {
|
| | | FieldChange fieldChange = new FieldChange();
|
| | | fieldChange.field = field;
|
| | | fieldChange.value = value;
|
| | | if (fieldChanges == null) {
|
| | | fieldChanges = new ArrayList<FieldChange>();
|
| | | }
|
| | | fieldChanges.add(fieldChange);
|
| | | }
|
| | |
|
| | | public String getString(Field field) {
|
| | | FieldChange fieldChange = getField(field);
|
| | | if (fieldChange == null) {
|
| | | return null;
|
| | | }
|
| | | return fieldChange.value.toString();
|
| | | }
|
| | |
|
| | | public void addAttachment(Attachment attachment) {
|
| | | if (attachments == null) {
|
| | | attachments = new ArrayList<Attachment>();
|
| | | attachments = new LinkedHashSet<Attachment>();
|
| | | }
|
| | | attachments.add(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() {
|
| | | return created.toString() + " by " + author;
|
| | | 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();
|
| | | }
|
| | | }
|
| | |
|
| | |
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public String text;
|
| | |
|
| | | public String id;
|
| | |
|
| | | public boolean deleted;
|
| | |
|
| | | Comment(String text) {
|
| | |
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public Field field;
|
| | | public final Field field;
|
| | |
|
| | | public Object value;
|
| | | 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() {
|
| | |
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | public String name;
|
| | | public final String name;
|
| | | public String id;
|
| | | public long size;
|
| | | public byte[] content;
|
| | | public boolean deleted;
|
| | |
| | | }
|
| | |
|
| | | @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 {
|
| | | Summary, Description, Reporter, Owner, Type, Status, Priority, Milestone, Labels;
|
| | | 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();
|
| | |
| | | return ordinal() > status.ordinal();
|
| | | }
|
| | |
|
| | | public boolean isClosed() {
|
| | | return ordinal() >= Done.ordinal();
|
| | | }
|
| | |
|
| | | public Status next() {
|
| | | switch (this) {
|
| | | case New:
|