mirror of
https://github.com/theonedev/onedev.git
synced 2025-12-08 18:26:30 +00:00
Improve email notification as well as service desk feature
Make service desk a separate setting from mail setting. Strip off quoted contents when post comments via email. Improve notification email to make the information more explicit, and much more...
This commit is contained in:
parent
357670d463
commit
f7f34f3493
10
pom.xml
10
pom.xml
@ -267,7 +267,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-compress</artifactId>
|
||||
<version>1.19</version>
|
||||
<version>1.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-io</groupId>
|
||||
@ -502,7 +502,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-core</artifactId>
|
||||
<version>2.2.0</version>
|
||||
<version>2.7.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
@ -558,12 +558,12 @@
|
||||
</repository>
|
||||
</repositories>
|
||||
<properties>
|
||||
<commons.version>2.0.11</commons.version>
|
||||
<k8shelper.version>2.1.6</k8shelper.version>
|
||||
<commons.version>2.0.12</commons.version>
|
||||
<k8shelper.version>2.1.7</k8shelper.version>
|
||||
<slf4j.version>1.7.5</slf4j.version>
|
||||
<logback.version>1.2.0</logback.version>
|
||||
<antlr.version>4.7.2</antlr.version>
|
||||
<jetty.version>9.4.37.v20210219</jetty.version>
|
||||
<jetty.version>9.4.43.v20210629</jetty.version>
|
||||
<wicket.version>7.17.0</wicket.version>
|
||||
<jersey.version>2.26</jersey.version>
|
||||
<hibernate.version>5.4.9.Final</hibernate.version>
|
||||
|
||||
@ -165,6 +165,8 @@ import io.onedev.server.entitymanager.impl.DefaultSettingManager;
|
||||
import io.onedev.server.entitymanager.impl.DefaultSshKeyManager;
|
||||
import io.onedev.server.entitymanager.impl.DefaultUserAuthorizationManager;
|
||||
import io.onedev.server.entitymanager.impl.DefaultUserManager;
|
||||
import io.onedev.server.entityreference.DefaultEntityReferenceManager;
|
||||
import io.onedev.server.entityreference.EntityReferenceManager;
|
||||
import io.onedev.server.git.GitFilter;
|
||||
import io.onedev.server.git.GitSshCommandCreator;
|
||||
import io.onedev.server.git.config.GitConfig;
|
||||
@ -185,6 +187,9 @@ import io.onedev.server.maintenance.DefaultDataManager;
|
||||
import io.onedev.server.maintenance.ResetAdminPassword;
|
||||
import io.onedev.server.maintenance.RestoreDatabase;
|
||||
import io.onedev.server.maintenance.Upgrade;
|
||||
import io.onedev.server.markdown.DefaultMarkdownManager;
|
||||
import io.onedev.server.markdown.MarkdownManager;
|
||||
import io.onedev.server.markdown.MarkdownProcessor;
|
||||
import io.onedev.server.model.Build;
|
||||
import io.onedev.server.model.support.administration.GroovyScript;
|
||||
import io.onedev.server.model.support.administration.authenticator.Authenticator;
|
||||
@ -250,10 +255,6 @@ import io.onedev.server.util.jackson.git.GitObjectMapperConfigurator;
|
||||
import io.onedev.server.util.jackson.hibernate.HibernateObjectMapperConfigurator;
|
||||
import io.onedev.server.util.jetty.DefaultJettyLauncher;
|
||||
import io.onedev.server.util.jetty.JettyLauncher;
|
||||
import io.onedev.server.util.markdown.DefaultMarkdownManager;
|
||||
import io.onedev.server.util.markdown.EntityReferenceManager;
|
||||
import io.onedev.server.util.markdown.MarkdownManager;
|
||||
import io.onedev.server.util.markdown.MarkdownProcessor;
|
||||
import io.onedev.server.util.schedule.DefaultTaskScheduler;
|
||||
import io.onedev.server.util.schedule.TaskScheduler;
|
||||
import io.onedev.server.util.script.ScriptContribution;
|
||||
@ -288,8 +289,8 @@ import io.onedev.server.web.editable.EditSupport;
|
||||
import io.onedev.server.web.editable.EditSupportLocator;
|
||||
import io.onedev.server.web.editable.EditSupportRegistry;
|
||||
import io.onedev.server.web.mapper.DynamicPathPageMapper;
|
||||
import io.onedev.server.web.page.layout.ContributedAdministrationSetting;
|
||||
import io.onedev.server.web.page.layout.AdministrationSettingContribution;
|
||||
import io.onedev.server.web.page.layout.ContributedAdministrationSetting;
|
||||
import io.onedev.server.web.page.layout.DefaultMainMenuCustomization;
|
||||
import io.onedev.server.web.page.layout.MainMenuCustomization;
|
||||
import io.onedev.server.web.page.project.blob.render.BlobRendererContribution;
|
||||
@ -385,7 +386,6 @@ public class CoreModule extends AbstractPluginModule {
|
||||
bind(CommitNotificationManager.class);
|
||||
bind(BuildNotificationManager.class);
|
||||
bind(IssueNotificationManager.class);
|
||||
bind(EntityReferenceManager.class);
|
||||
bind(CodeCommentNotificationManager.class);
|
||||
bind(CodeCommentManager.class).to(DefaultCodeCommentManager.class);
|
||||
bind(IssueWatchManager.class).to(DefaultIssueWatchManager.class);
|
||||
@ -405,6 +405,7 @@ public class CoreModule extends AbstractPluginModule {
|
||||
bind(PullRequestAssignmentManager.class).to(DefaultPullRequestAssignmentManager.class);
|
||||
bind(SshKeyManager.class).to(DefaultSshKeyManager.class);
|
||||
bind(BuildMetricManager.class).to(DefaultBuildMetricManager.class);
|
||||
bind(EntityReferenceManager.class).to(DefaultEntityReferenceManager.class);
|
||||
|
||||
bind(WebHookManager.class);
|
||||
|
||||
|
||||
@ -17,8 +17,6 @@ public interface IssueChangeManager extends EntityManager<IssueChange> {
|
||||
|
||||
void changeTitle(Issue issue, String title);
|
||||
|
||||
void changeDescription(Issue issue, @Nullable String description);
|
||||
|
||||
void changeMilestone(Issue issue, Milestone milestone);
|
||||
|
||||
void changeFields(Issue issue, Map<String, Object> fieldValues);
|
||||
|
||||
@ -58,6 +58,9 @@ public interface IssueManager extends EntityManager<Issue> {
|
||||
|
||||
void fixFieldValueOrders();
|
||||
|
||||
void saveDescription(Issue issue, @Nullable String description);
|
||||
|
||||
@Override
|
||||
void delete(Issue issue);
|
||||
|
||||
Collection<Long> getIssueNumbers(Long projectId);
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
package io.onedev.server.entitymanager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import io.onedev.server.model.PullRequest;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.model.support.pullrequest.MergeStrategy;
|
||||
@ -13,6 +11,4 @@ public interface PullRequestChangeManager extends EntityManager<PullRequestChang
|
||||
|
||||
void changeTitle(PullRequest request, String title);
|
||||
|
||||
void changeDescription(PullRequest request, @Nullable String description);
|
||||
|
||||
}
|
||||
|
||||
@ -73,4 +73,6 @@ public interface PullRequestManager extends EntityManager<PullRequest> {
|
||||
|
||||
void delete(Collection<PullRequest> requests);
|
||||
|
||||
void saveDescription(PullRequest request, @Nullable String description);
|
||||
|
||||
}
|
||||
|
||||
@ -124,6 +124,7 @@ public interface SettingManager extends EntityManager<Setting> {
|
||||
|
||||
void saveNotificationTemplateSetting(NotificationTemplateSetting notificationTemplateSetting);
|
||||
|
||||
@Nullable
|
||||
ServiceDeskSetting getServiceDeskSetting();
|
||||
|
||||
void saveServiceDeskSetting(ServiceDeskSetting serviceDeskSetting);
|
||||
|
||||
@ -57,7 +57,6 @@ import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
import io.onedev.server.model.support.issue.TransitionSpec;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueBatchUpdateData;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueDescriptionChangeData;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueFieldChangeData;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueMilestoneChangeData;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueStateChangeData;
|
||||
@ -161,22 +160,6 @@ public class DefaultIssueChangeManager extends BaseEntityManager<IssueChange>
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void changeDescription(Issue issue, @Nullable String description) {
|
||||
String prevDescription = issue.getDescription();
|
||||
if (!Objects.equal(description, prevDescription)) {
|
||||
issue.setDescription(description);
|
||||
|
||||
IssueChange change = new IssueChange();
|
||||
change.setIssue(issue);
|
||||
change.setDate(new Date());
|
||||
change.setUser(SecurityUtils.getUser());
|
||||
change.setData(new IssueDescriptionChangeData(prevDescription, issue.getDescription()));
|
||||
save(change);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void changeMilestone(Issue issue, @Nullable Milestone milestone) {
|
||||
|
||||
@ -22,6 +22,7 @@ import javax.persistence.criteria.JoinType;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.apache.wicket.util.lang.Objects;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.criterion.MatchMode;
|
||||
import org.hibernate.criterion.Order;
|
||||
@ -44,6 +45,9 @@ import io.onedev.server.entitymanager.ProjectManager;
|
||||
import io.onedev.server.entitymanager.RoleManager;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.entityreference.EntityReferenceManager;
|
||||
import io.onedev.server.entityreference.ReferenceMigrator;
|
||||
import io.onedev.server.entityreference.ReferencedFromAware;
|
||||
import io.onedev.server.event.entity.EntityRemoved;
|
||||
import io.onedev.server.event.issue.IssueChangeEvent;
|
||||
import io.onedev.server.event.issue.IssueEvent;
|
||||
@ -61,9 +65,6 @@ import io.onedev.server.model.support.administration.GlobalIssueSetting;
|
||||
import io.onedev.server.model.support.inputspec.choiceinput.choiceprovider.SpecifiedChoices;
|
||||
import io.onedev.server.model.support.issue.NamedIssueQuery;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueChangeData;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueReferencedFromCodeCommentData;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueReferencedFromIssueData;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueReferencedFromPullRequestData;
|
||||
import io.onedev.server.model.support.issue.field.spec.FieldSpec;
|
||||
import io.onedev.server.persistence.TransactionManager;
|
||||
import io.onedev.server.persistence.annotation.Sessional;
|
||||
@ -82,7 +83,6 @@ import io.onedev.server.storage.AttachmentStorageManager;
|
||||
import io.onedev.server.util.MilestoneAndState;
|
||||
import io.onedev.server.util.Pair;
|
||||
import io.onedev.server.util.ProjectScopedNumber;
|
||||
import io.onedev.server.util.ReferenceMigrator;
|
||||
import io.onedev.server.util.facade.IssueFacade;
|
||||
import io.onedev.server.web.component.issue.workflowreconcile.UndefinedFieldResolution;
|
||||
import io.onedev.server.web.component.issue.workflowreconcile.UndefinedFieldValue;
|
||||
@ -112,6 +112,8 @@ public class DefaultIssueManager extends BaseEntityManager<Issue> implements Iss
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
private final EntityReferenceManager entityReferenceManager;
|
||||
|
||||
private final RoleManager roleManager;
|
||||
|
||||
private final Map<Long, IssueFacade> cache = new HashMap<>();
|
||||
@ -124,7 +126,7 @@ public class DefaultIssueManager extends BaseEntityManager<Issue> implements Iss
|
||||
SettingManager settingManager, ListenerRegistry listenerRegistry,
|
||||
ProjectManager projectManager, UserManager userManager,
|
||||
RoleManager roleManager, AttachmentStorageManager attachmentStorageManager,
|
||||
IssueCommentManager issueCommentManager) {
|
||||
IssueCommentManager issueCommentManager, EntityReferenceManager entityReferenceManager) {
|
||||
super(dao);
|
||||
this.issueFieldManager = issueFieldManager;
|
||||
this.issueQuerySettingManager = issueQuerySettingManager;
|
||||
@ -136,6 +138,7 @@ public class DefaultIssueManager extends BaseEntityManager<Issue> implements Iss
|
||||
this.roleManager = roleManager;
|
||||
this.attachmentStorageManager = attachmentStorageManager;
|
||||
this.issueCommentManager = issueCommentManager;
|
||||
this.entityReferenceManager = entityReferenceManager;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -303,11 +306,8 @@ public class DefaultIssueManager extends BaseEntityManager<Issue> implements Iss
|
||||
boolean minorChange = false;
|
||||
if (event instanceof IssueChangeEvent) {
|
||||
IssueChangeData changeData = ((IssueChangeEvent)event).getChange().getData();
|
||||
if (changeData instanceof IssueReferencedFromCodeCommentData
|
||||
|| changeData instanceof IssueReferencedFromIssueData
|
||||
|| changeData instanceof IssueReferencedFromPullRequestData) {
|
||||
if (changeData instanceof ReferencedFromAware)
|
||||
minorChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(event instanceof IssueOpened || minorChange))
|
||||
@ -808,7 +808,18 @@ public class DefaultIssueManager extends BaseEntityManager<Issue> implements Iss
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void saveDescription(Issue issue, @Nullable String description) {
|
||||
String prevDescription = issue.getDescription();
|
||||
if (!Objects.equal(description, prevDescription)) {
|
||||
issue.setDescription(description);
|
||||
entityReferenceManager.addReferenceChange(issue, description);
|
||||
save(issue);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void delete(Collection<Issue> issues) {
|
||||
|
||||
@ -2,19 +2,15 @@ package io.onedev.server.entitymanager.impl;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
import io.onedev.commons.launcher.loader.ListenerRegistry;
|
||||
import io.onedev.server.entitymanager.PullRequestChangeManager;
|
||||
import io.onedev.server.event.pullrequest.PullRequestChangeEvent;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.model.support.pullrequest.MergeStrategy;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestDescriptionChangeData;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestMergeStrategyChangeData;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestTitleChangeData;
|
||||
import io.onedev.server.persistence.annotation.Transactional;
|
||||
@ -69,20 +65,4 @@ public class DefaultPullRequestChangeManager extends BaseEntityManager<PullReque
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void changeDescription(PullRequest request, @Nullable String description) {
|
||||
String prevDescription = request.getDescription();
|
||||
if (!Objects.equal(prevDescription, description)) {
|
||||
request.setDescription(description);
|
||||
|
||||
PullRequestChange change = new PullRequestChange();
|
||||
change.setDate(new Date());
|
||||
change.setRequest(request);
|
||||
change.setData(new PullRequestDescriptionChangeData(prevDescription, description));
|
||||
change.setUser(SecurityUtils.getUser());
|
||||
save(change);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -31,6 +31,7 @@ import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.apache.wicket.util.lang.Objects;
|
||||
import org.eclipse.jgit.lib.CommitBuilder;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectInserter;
|
||||
@ -65,6 +66,8 @@ import io.onedev.server.entitymanager.PullRequestChangeManager;
|
||||
import io.onedev.server.entitymanager.PullRequestManager;
|
||||
import io.onedev.server.entitymanager.PullRequestReviewManager;
|
||||
import io.onedev.server.entitymanager.PullRequestUpdateManager;
|
||||
import io.onedev.server.entityreference.EntityReferenceManager;
|
||||
import io.onedev.server.entityreference.ReferencedFromAware;
|
||||
import io.onedev.server.event.RefUpdated;
|
||||
import io.onedev.server.event.build.BuildEvent;
|
||||
import io.onedev.server.event.entity.EntityRemoved;
|
||||
@ -77,6 +80,7 @@ import io.onedev.server.event.pullrequest.PullRequestOpened;
|
||||
import io.onedev.server.event.pullrequest.PullRequestUpdated;
|
||||
import io.onedev.server.git.GitUtils;
|
||||
import io.onedev.server.infomanager.CommitInfoManager;
|
||||
import io.onedev.server.markdown.MarkdownManager;
|
||||
import io.onedev.server.model.Build;
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.Project;
|
||||
@ -99,9 +103,6 @@ import io.onedev.server.model.support.pullrequest.changedata.PullRequestChangeDa
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestDiscardData;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestMergeData;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestMergeStrategyChangeData;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestReferencedFromCodeCommentData;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestReferencedFromIssueData;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestReferencedFromPullRequestData;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestReopenData;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestReviewerAddData;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestReviewerRemoveData;
|
||||
@ -123,7 +124,6 @@ import io.onedev.server.security.permission.ReadCode;
|
||||
import io.onedev.server.util.ProjectAndBranch;
|
||||
import io.onedev.server.util.ProjectScopedNumber;
|
||||
import io.onedev.server.util.concurrent.Prioritized;
|
||||
import io.onedev.server.util.markdown.MarkdownManager;
|
||||
import io.onedev.server.util.reviewrequirement.ReviewRequirement;
|
||||
import io.onedev.server.util.work.BatchWorkManager;
|
||||
import io.onedev.server.util.work.BatchWorker;
|
||||
@ -159,6 +159,8 @@ public class DefaultPullRequestManager extends BaseEntityManager<PullRequest> im
|
||||
|
||||
private final ExecutorService executorService;
|
||||
|
||||
private final EntityReferenceManager entityReferenceManager;
|
||||
|
||||
@Inject
|
||||
public DefaultPullRequestManager(Dao dao, PullRequestUpdateManager pullRequestUpdateManager,
|
||||
PullRequestReviewManager pullRequestReviewManager, MarkdownManager markdownManager,
|
||||
@ -166,7 +168,8 @@ public class DefaultPullRequestManager extends BaseEntityManager<PullRequest> im
|
||||
SessionManager sessionManager, PullRequestChangeManager pullRequestChangeManager,
|
||||
ExecutorService executorService, BuildManager buildManager,
|
||||
TransactionManager transactionManager, ProjectManager projectManager,
|
||||
CommitInfoManager commitInfoManager, PullRequestAssignmentManager pullRequestAssignmentManager) {
|
||||
CommitInfoManager commitInfoManager, PullRequestAssignmentManager pullRequestAssignmentManager,
|
||||
EntityReferenceManager entityReferenceManager) {
|
||||
super(dao);
|
||||
|
||||
this.pullRequestUpdateManager = pullRequestUpdateManager;
|
||||
@ -181,6 +184,7 @@ public class DefaultPullRequestManager extends BaseEntityManager<PullRequest> im
|
||||
this.projectManager = projectManager;
|
||||
this.commitInfoManager = commitInfoManager;
|
||||
this.pullRequestAssignmentManager = pullRequestAssignmentManager;
|
||||
this.entityReferenceManager = entityReferenceManager;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@ -660,9 +664,7 @@ public class DefaultPullRequestManager extends BaseEntityManager<PullRequest> im
|
||||
|| changeData instanceof PullRequestAssigneeRemoveData
|
||||
|| changeData instanceof PullRequestSourceBranchDeleteData
|
||||
|| changeData instanceof PullRequestSourceBranchRestoreData
|
||||
|| changeData instanceof PullRequestReferencedFromCodeCommentData
|
||||
|| changeData instanceof PullRequestReferencedFromIssueData
|
||||
|| changeData instanceof PullRequestReferencedFromPullRequestData) {
|
||||
|| changeData instanceof ReferencedFromAware) {
|
||||
minorChange = true;
|
||||
}
|
||||
}
|
||||
@ -1034,4 +1036,15 @@ public class DefaultPullRequestManager extends BaseEntityManager<PullRequest> im
|
||||
delete(request);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void saveDescription(PullRequest request, @Nullable String description) {
|
||||
String prevDescription = request.getDescription();
|
||||
if (!Objects.equal(description, prevDescription)) {
|
||||
request.setDescription(description);
|
||||
entityReferenceManager.addReferenceChange(request, description);
|
||||
save(request);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.entityreference;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -8,6 +8,7 @@ import org.unbescape.html.HtmlEscape;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.BuildManager;
|
||||
import io.onedev.server.markdown.MarkdownProcessor;
|
||||
import io.onedev.server.model.Build;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.util.ProjectScopedNumber;
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.entityreference;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -17,10 +17,9 @@ import io.onedev.server.entitymanager.PullRequestManager;
|
||||
import io.onedev.server.event.codecomment.CodeCommentCreated;
|
||||
import io.onedev.server.event.codecomment.CodeCommentUpdated;
|
||||
import io.onedev.server.event.entity.EntityPersisted;
|
||||
import io.onedev.server.event.issue.IssueChangeEvent;
|
||||
import io.onedev.server.event.issue.IssueOpened;
|
||||
import io.onedev.server.event.pullrequest.PullRequestChangeEvent;
|
||||
import io.onedev.server.event.pullrequest.PullRequestOpened;
|
||||
import io.onedev.server.markdown.MarkdownManager;
|
||||
import io.onedev.server.model.CodeComment;
|
||||
import io.onedev.server.model.CodeCommentReply;
|
||||
import io.onedev.server.model.Issue;
|
||||
@ -29,15 +28,11 @@ import io.onedev.server.model.IssueComment;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.model.PullRequestComment;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueDescriptionChangeData;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueTitleChangeData;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestDescriptionChangeData;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestTitleChangeData;
|
||||
import io.onedev.server.persistence.annotation.Transactional;
|
||||
import io.onedev.server.util.ProjectScopedNumber;
|
||||
|
||||
@Singleton
|
||||
public class EntityReferenceManager {
|
||||
public class DefaultEntityReferenceManager implements EntityReferenceManager {
|
||||
|
||||
private final IssueChangeManager issueChangeManager;
|
||||
|
||||
@ -46,14 +41,15 @@ public class EntityReferenceManager {
|
||||
private final MarkdownManager markdownManager;
|
||||
|
||||
@Inject
|
||||
public EntityReferenceManager(IssueChangeManager issueChangeManager,
|
||||
public DefaultEntityReferenceManager(IssueChangeManager issueChangeManager,
|
||||
PullRequestChangeManager pullRequestChangeManager, MarkdownManager markdownManager) {
|
||||
this.issueChangeManager = issueChangeManager;
|
||||
this.pullRequestChangeManager = pullRequestChangeManager;
|
||||
this.markdownManager = markdownManager;
|
||||
}
|
||||
|
||||
private void addReferenceChange(Issue issue, String markdown) {
|
||||
@Override
|
||||
public void addReferenceChange(Issue issue, String markdown) {
|
||||
if (markdown != null) {
|
||||
Document document = Jsoup.parseBodyFragment(markdownManager.render(markdown));
|
||||
for (ProjectScopedNumber referencedIssueFQN: new ReferenceParser(Issue.class).parseReferences(document, issue.getProject())) {
|
||||
@ -111,7 +107,8 @@ public class EntityReferenceManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void addReferenceChange(PullRequest request, String markdown) {
|
||||
@Override
|
||||
public void addReferenceChange(PullRequest request, String markdown) {
|
||||
if (markdown != null) {
|
||||
Document document = Jsoup.parseBodyFragment(markdownManager.render(markdown));
|
||||
for (ProjectScopedNumber referencedIssueFQN: new ReferenceParser(Issue.class).parseReferences(document, request.getTargetProject())) {
|
||||
@ -169,7 +166,8 @@ public class EntityReferenceManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void addReferenceChange(CodeComment comment, String markdown) {
|
||||
@Override
|
||||
public void addReferenceChange(CodeComment comment, String markdown) {
|
||||
if (markdown != null) {
|
||||
Document document = Jsoup.parseBodyFragment(markdownManager.render(markdown));
|
||||
for (ProjectScopedNumber referencedIssueFQN: new ReferenceParser(Issue.class).parseReferences(document, comment.getProject())) {
|
||||
@ -257,15 +255,6 @@ public class EntityReferenceManager {
|
||||
addReferenceChange(event.getRequest(), event.getRequest().getDescription());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Listen
|
||||
public void on(PullRequestChangeEvent event) {
|
||||
if (event.getChange().getData() instanceof PullRequestTitleChangeData)
|
||||
addReferenceChange(event.getRequest(), event.getRequest().getTitle());
|
||||
if (event.getChange().getData() instanceof PullRequestDescriptionChangeData)
|
||||
addReferenceChange(event.getRequest(), event.getRequest().getDescription());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Listen
|
||||
public void on(IssueOpened event) {
|
||||
@ -273,15 +262,6 @@ public class EntityReferenceManager {
|
||||
addReferenceChange(event.getIssue(), event.getIssue().getDescription());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Listen
|
||||
public void on(IssueChangeEvent event) {
|
||||
if (event.getChange().getData() instanceof IssueTitleChangeData)
|
||||
addReferenceChange(event.getIssue(), event.getIssue().getTitle());
|
||||
if (event.getChange().getData() instanceof IssueDescriptionChangeData)
|
||||
addReferenceChange(event.getIssue(), event.getIssue().getDescription());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Listen
|
||||
public void on(CodeCommentCreated event) {
|
||||
@ -0,0 +1,17 @@
|
||||
package io.onedev.server.entityreference;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import io.onedev.server.model.CodeComment;
|
||||
import io.onedev.server.model.Issue;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
|
||||
public interface EntityReferenceManager {
|
||||
|
||||
void addReferenceChange(Issue issue, @Nullable String markdown);
|
||||
|
||||
void addReferenceChange(PullRequest request, @Nullable String markdown);
|
||||
|
||||
void addReferenceChange(CodeComment comment, @Nullable String markdown);
|
||||
|
||||
}
|
||||
@ -1,10 +1,11 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.entityreference;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.request.cycle.RequestCycle;
|
||||
import org.jsoup.nodes.Document;
|
||||
|
||||
import io.onedev.server.markdown.MarkdownProcessor;
|
||||
import io.onedev.server.model.Issue;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.util.ProjectScopedNumber;
|
||||
@ -1,10 +1,11 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.entityreference;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.request.cycle.RequestCycle;
|
||||
import org.jsoup.nodes.Document;
|
||||
|
||||
import io.onedev.server.markdown.MarkdownProcessor;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
import io.onedev.server.util.ProjectScopedNumber;
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util;
|
||||
package io.onedev.server.entityreference;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.entityreference;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
@ -14,13 +14,13 @@ import org.jsoup.select.NodeTraversor;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import io.onedev.commons.utils.HtmlUtils;
|
||||
import io.onedev.commons.utils.StringUtils;
|
||||
import io.onedev.commons.utils.WordUtils;
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.ProjectManager;
|
||||
import io.onedev.server.model.AbstractEntity;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.util.HtmlUtils;
|
||||
import io.onedev.server.util.ProjectScopedNumber;
|
||||
import io.onedev.server.util.TextNodeVisitor;
|
||||
import io.onedev.server.util.validation.ProjectNameValidator;
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util;
|
||||
package io.onedev.server.entityreference;
|
||||
|
||||
import io.onedev.server.model.Project;
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
package io.onedev.server.entityreference;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import io.onedev.server.model.AbstractEntity;
|
||||
|
||||
public interface ReferencedFromAware<T extends AbstractEntity> {
|
||||
|
||||
@Nullable
|
||||
T getReferencedFrom();
|
||||
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
package io.onedev.server.event;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface MarkdownAware {
|
||||
@Nullable String getMarkdown();
|
||||
}
|
||||
@ -1,15 +1,25 @@
|
||||
package io.onedev.server.event;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.markdown.MarkdownManager;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.model.support.LastUpdate;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
|
||||
public abstract class ProjectEvent extends Event {
|
||||
|
||||
private final Project project;
|
||||
|
||||
private transient Optional<String> renderedMarkdown;
|
||||
|
||||
private transient Optional<String> processedMarkdown;
|
||||
|
||||
public ProjectEvent(User user, Date date, Project project) {
|
||||
super(user, date);
|
||||
this.project = project;
|
||||
@ -21,6 +31,16 @@ public abstract class ProjectEvent extends Event {
|
||||
|
||||
public abstract String getActivity();
|
||||
|
||||
@Nullable
|
||||
public String getMarkdown() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ActivityDetail getActivityDetail() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public LastUpdate getLastUpdate() {
|
||||
LastUpdate lastUpdate = new LastUpdate();
|
||||
lastUpdate.setUser(getUser());
|
||||
@ -28,5 +48,61 @@ public abstract class ProjectEvent extends Event {
|
||||
lastUpdate.setDate(getDate());
|
||||
return lastUpdate;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getRenderedMarkdown() {
|
||||
if (renderedMarkdown == null) {
|
||||
String markdown = getMarkdown();
|
||||
if (markdown != null)
|
||||
renderedMarkdown = Optional.of(OneDev.getInstance(MarkdownManager.class).render(markdown));
|
||||
else
|
||||
renderedMarkdown = Optional.empty();
|
||||
}
|
||||
return renderedMarkdown.orElse(null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getProcessedMarkdown() {
|
||||
if (processedMarkdown == null) {
|
||||
String renderedMarkdown = getRenderedMarkdown();
|
||||
if (renderedMarkdown != null) {
|
||||
processedMarkdown = Optional.of(OneDev.getInstance(MarkdownManager.class)
|
||||
.process(renderedMarkdown, getProject(), null, true));
|
||||
} else {
|
||||
processedMarkdown = Optional.empty();
|
||||
}
|
||||
}
|
||||
return processedMarkdown.orElse(null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTextBody() {
|
||||
ActivityDetail activityDetail = getActivityDetail();
|
||||
String markdown = getMarkdown();
|
||||
|
||||
if (activityDetail != null && markdown != null)
|
||||
return activityDetail.getTextVersion() + "\n\n" + markdown;
|
||||
else if (activityDetail != null)
|
||||
return activityDetail.getTextVersion();
|
||||
else if (markdown != null)
|
||||
return markdown;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getHtmlBody() {
|
||||
ActivityDetail activityDetail = getActivityDetail();
|
||||
String processedMarkdown = getProcessedMarkdown();
|
||||
|
||||
if (activityDetail != null && processedMarkdown != null)
|
||||
return activityDetail.getHtmlVersion() + "<br>" + processedMarkdown;
|
||||
else if (activityDetail != null)
|
||||
return activityDetail.getHtmlVersion();
|
||||
else if (processedMarkdown != null)
|
||||
return processedMarkdown;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package io.onedev.server.event.codecomment;
|
||||
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.model.CodeComment;
|
||||
|
||||
public class CodeCommentCreated extends CodeCommentEvent implements MarkdownAware {
|
||||
public class CodeCommentCreated extends CodeCommentEvent {
|
||||
|
||||
public CodeCommentCreated(CodeComment comment) {
|
||||
super(comment.getUser(), comment.getCreateDate(), comment);
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package io.onedev.server.event.codecomment;
|
||||
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.model.CodeCommentReply;
|
||||
|
||||
public class CodeCommentReplied extends CodeCommentEvent implements MarkdownAware {
|
||||
public class CodeCommentReplied extends CodeCommentEvent {
|
||||
|
||||
private final CodeCommentReply reply;
|
||||
|
||||
|
||||
@ -2,11 +2,10 @@ package io.onedev.server.event.codecomment;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.model.CodeComment;
|
||||
import io.onedev.server.model.User;
|
||||
|
||||
public class CodeCommentUpdated extends CodeCommentEvent implements MarkdownAware {
|
||||
public class CodeCommentUpdated extends CodeCommentEvent {
|
||||
|
||||
public CodeCommentUpdated(User user, CodeComment comment) {
|
||||
super(user, new Date(), comment);
|
||||
|
||||
@ -3,12 +3,12 @@ package io.onedev.server.event.issue;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.IssueChange;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
|
||||
public class IssueChangeEvent extends IssueEvent implements MarkdownAware {
|
||||
public class IssueChangeEvent extends IssueEvent {
|
||||
|
||||
private final IssueChange change;
|
||||
|
||||
@ -49,4 +49,9 @@ public class IssueChangeEvent extends IssueEvent implements MarkdownAware {
|
||||
return getChange().getData().getActivity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
return getChange().getData().getActivityDetail();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,10 +2,9 @@ package io.onedev.server.event.issue;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.model.IssueComment;
|
||||
|
||||
public class IssueCommented extends IssueEvent implements MarkdownAware {
|
||||
public class IssueCommented extends IssueEvent {
|
||||
|
||||
private final IssueComment comment;
|
||||
|
||||
|
||||
@ -9,14 +9,13 @@ import java.util.stream.Collectors;
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.GroupManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.Issue;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.model.support.issue.field.spec.FieldSpec;
|
||||
import io.onedev.server.util.Input;
|
||||
|
||||
public class IssueOpened extends IssueEvent implements MarkdownAware {
|
||||
public class IssueOpened extends IssueEvent {
|
||||
|
||||
public IssueOpened(Issue issue) {
|
||||
super(issue.getSubmitter(), issue.getSubmitDate(), issue);
|
||||
|
||||
@ -2,7 +2,6 @@ package io.onedev.server.event.pullrequest;
|
||||
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.model.support.pullrequest.MergePreview;
|
||||
import io.onedev.server.model.support.pullrequest.changedata.PullRequestDiscardData;
|
||||
@ -10,7 +9,7 @@ import io.onedev.server.model.support.pullrequest.changedata.PullRequestMergeDat
|
||||
import io.onedev.server.util.CommitAware;
|
||||
import io.onedev.server.util.ProjectScopedCommit;
|
||||
|
||||
public class PullRequestChangeEvent extends PullRequestEvent implements MarkdownAware, CommitAware {
|
||||
public class PullRequestChangeEvent extends PullRequestEvent implements CommitAware {
|
||||
|
||||
private final PullRequestChange change;
|
||||
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
package io.onedev.server.event.pullrequest;
|
||||
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.model.CodeComment;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
|
||||
public class PullRequestCodeCommentCreated extends PullRequestCodeCommentEvent implements MarkdownAware {
|
||||
public class PullRequestCodeCommentCreated extends PullRequestCodeCommentEvent {
|
||||
|
||||
public PullRequestCodeCommentCreated(PullRequest request, CodeComment comment) {
|
||||
super(comment.getUser(), comment.getCreateDate(), request, comment);
|
||||
|
||||
@ -2,12 +2,11 @@ package io.onedev.server.event.pullrequest;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.model.CodeComment;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
import io.onedev.server.model.User;
|
||||
|
||||
public abstract class PullRequestCodeCommentEvent extends PullRequestEvent implements MarkdownAware {
|
||||
public abstract class PullRequestCodeCommentEvent extends PullRequestEvent {
|
||||
|
||||
private final CodeComment comment;
|
||||
|
||||
|
||||
@ -2,10 +2,9 @@ package io.onedev.server.event.pullrequest;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.model.PullRequestComment;
|
||||
|
||||
public class PullRequestCommented extends PullRequestEvent implements MarkdownAware {
|
||||
public class PullRequestCommented extends PullRequestEvent {
|
||||
|
||||
private final PullRequestComment comment;
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
package io.onedev.server.event.pullrequest;
|
||||
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
|
||||
public class PullRequestOpened extends PullRequestEvent implements MarkdownAware {
|
||||
public class PullRequestOpened extends PullRequestEvent {
|
||||
|
||||
public PullRequestOpened(PullRequest request) {
|
||||
super(request.getSubmitter(), request.getSubmitDate(), request);
|
||||
|
||||
@ -25,7 +25,7 @@ public class PullRequestUpdated extends PullRequestEvent {
|
||||
|
||||
@Override
|
||||
public String getActivity() {
|
||||
return "Commits added";
|
||||
return "added commits";
|
||||
}
|
||||
|
||||
public Collection<User> getCommitters() {
|
||||
|
||||
@ -17,9 +17,10 @@ import org.apache.shiro.util.ThreadContext;
|
||||
import org.apache.sshd.common.channel.ChannelOutputStream;
|
||||
import org.apache.sshd.server.Environment;
|
||||
import org.apache.sshd.server.ExitCallback;
|
||||
import org.apache.sshd.server.SessionAware;
|
||||
import org.apache.sshd.server.channel.ChannelSession;
|
||||
import org.apache.sshd.server.command.Command;
|
||||
import org.apache.sshd.server.session.ServerSession;
|
||||
import org.apache.sshd.server.session.ServerSessionAware;
|
||||
import org.eclipse.jgit.transport.RemoteConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@ -117,7 +118,7 @@ public class GitSshCommandCreator implements SshCommandCreator {
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class GitSshCommand implements Command, SessionAware {
|
||||
private abstract class GitSshCommand implements Command, ServerSessionAware {
|
||||
|
||||
private static final int PRIORITY = 2;
|
||||
|
||||
@ -156,7 +157,7 @@ public class GitSshCommandCreator implements SshCommandCreator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Environment env) throws IOException {
|
||||
public void start(ChannelSession channel, Environment env) throws IOException {
|
||||
ThreadContext.bind(SecurityUtils.asSubject(authenticator.getPublicKeyOwnerId(session)));
|
||||
|
||||
File gitDir;
|
||||
@ -206,7 +207,7 @@ public class GitSshCommandCreator implements SshCommandCreator {
|
||||
protected abstract ExecutionResult execute(File gitDir, Map<String, String> gitEnvs);
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
public void destroy(ChannelSession channel) throws Exception {
|
||||
if (commandFuture != null)
|
||||
commandFuture.cancel(true);
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -225,8 +226,23 @@ public class DefaultDataManager implements DataManager, Serializable {
|
||||
settingManager.saveProjectSetting(new GlobalProjectSetting());
|
||||
}
|
||||
setting = settingManager.getSetting(Key.SERVICE_DESK_SETTING);
|
||||
if (setting == null) {
|
||||
settingManager.saveServiceDeskSetting(new ServiceDeskSetting());
|
||||
if (setting == null) {
|
||||
settingManager.saveServiceDeskSetting(null);
|
||||
} else if (setting.getValue() != null && !validator.validate(setting.getValue()).isEmpty()) {
|
||||
manualConfigs.add(new ManualConfig("Specify Service Desk Setting", null,
|
||||
setting.getValue(), new HashSet<>(), true) {
|
||||
|
||||
@Override
|
||||
public Skippable getSkippable() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete() {
|
||||
settingManager.saveServiceDeskSetting((ServiceDeskSetting) getSetting());
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
setting = settingManager.getSetting(Key.NOTIFICATION_TEMPLATE_SETTING);
|
||||
if (setting == null) {
|
||||
@ -345,8 +361,8 @@ public class DefaultDataManager implements DataManager, Serializable {
|
||||
+ "%s",
|
||||
url, Throwables.getStackTraceAsString(e));
|
||||
mailManager.sendMail(Lists.newArrayList(root.getEmail()), Lists.newArrayList(),
|
||||
"OneDev database auto-backup failed", htmlBody, textBody,
|
||||
null, null);
|
||||
Lists.newArrayList(), "[Backup] OneDev Database Auto-backup Failed",
|
||||
htmlBody, textBody, null, null);
|
||||
}
|
||||
|
||||
public Object writeReplace() throws ObjectStreamException {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.markdown;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.markdown;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.regex.Matcher;
|
||||
@ -14,9 +14,9 @@ import org.jsoup.select.NodeTraversor;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import io.onedev.commons.utils.HtmlUtils;
|
||||
import io.onedev.server.git.GitUtils;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.util.HtmlUtils;
|
||||
import io.onedev.server.util.TextNodeVisitor;
|
||||
import io.onedev.server.web.page.project.commits.CommitDetailPage;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.markdown;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -8,8 +8,6 @@ import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
|
||||
@ -27,9 +25,9 @@ import com.vladsch.flexmark.parser.ParserEmulationProfile;
|
||||
import com.vladsch.flexmark.util.options.MutableDataHolder;
|
||||
import com.vladsch.flexmark.util.options.MutableDataSet;
|
||||
|
||||
import io.onedev.commons.utils.HtmlUtils;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.util.HtmlUtils;
|
||||
import io.onedev.server.web.resource.AttachmentResource;
|
||||
|
||||
@Singleton
|
||||
@ -80,13 +78,6 @@ public class DefaultMarkdownManager implements MarkdownManager {
|
||||
return HtmlRenderer.builder(options).softBreak("<br>").build().render(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String escape(String markdown) {
|
||||
markdown = StringEscapeUtils.escapeHtml4(markdown);
|
||||
markdown = StringUtils.replace(markdown, "\n", "<br>");
|
||||
return markdown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Document process(Document document, @Nullable Project project, @Nullable Object context, boolean forExternal) {
|
||||
document = HtmlUtils.sanitize(document);
|
||||
@ -100,7 +91,11 @@ public class DefaultMarkdownManager implements MarkdownManager {
|
||||
src = settingManager.getSystemSetting().getServerUrl() + src;
|
||||
element.attr("src", AttachmentResource.authorizeGroup(src));
|
||||
}
|
||||
element.attr("width", "100%");
|
||||
String style = element.attr("style");
|
||||
if (!style.endsWith(";"))
|
||||
style += ";";
|
||||
style += "max-width:100%";
|
||||
element.attr("style", style);
|
||||
}
|
||||
for (Element element: document.body().getElementsByTag("a")) {
|
||||
String href = element.attr("href");
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.markdown;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -27,15 +27,4 @@ public interface MarkdownManager {
|
||||
|
||||
String process(String html, @Nullable Project project, @Nullable Object context, boolean forExternal);
|
||||
|
||||
/**
|
||||
* Escape html characters in specified markdown so that the markdown plain text
|
||||
* can be embedded in html content such as html email.
|
||||
*
|
||||
* @param markdown
|
||||
* markdown to be escaped
|
||||
* @return
|
||||
* escaped markdown plain text
|
||||
*/
|
||||
String escape(String markdown);
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.markdown;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.markdown;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
@ -12,7 +12,7 @@ import org.jsoup.select.NodeTraversor;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import io.onedev.commons.utils.HtmlUtils;
|
||||
import io.onedev.server.util.HtmlUtils;
|
||||
import io.onedev.server.util.TextNodeVisitor;
|
||||
|
||||
public class MentionParser {
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.markdown;
|
||||
|
||||
import org.apache.wicket.request.cycle.RequestCycle;
|
||||
import org.jsoup.nodes.Document;
|
||||
@ -1,4 +1,4 @@
|
||||
package io.onedev.server.util.markdown;
|
||||
package io.onedev.server.markdown;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@ -2648,13 +2648,21 @@ public class DataMigrator {
|
||||
dom.writeToFile(file, false);
|
||||
} else if (file.getName().startsWith("IssueChanges.xml")) {
|
||||
VersionedXmlDoc dom = VersionedXmlDoc.fromFile(file);
|
||||
for (Element element: dom.getRootElement().elements())
|
||||
useUnknownUser(element, "user");
|
||||
for (Element element: dom.getRootElement().elements()) {
|
||||
if (element.element("data").attributeValue("class").contains("IssueDescriptionChangeData"))
|
||||
element.detach();
|
||||
else
|
||||
useUnknownUser(element, "user");
|
||||
}
|
||||
dom.writeToFile(file, false);
|
||||
} else if (file.getName().startsWith("PullRequestChanges.xml")) {
|
||||
VersionedXmlDoc dom = VersionedXmlDoc.fromFile(file);
|
||||
for (Element element: dom.getRootElement().elements())
|
||||
useUnknownUser(element, "user");
|
||||
for (Element element: dom.getRootElement().elements()) {
|
||||
if (element.element("data").attributeValue("class").contains("PullRequestDescriptionChangeData"))
|
||||
element.detach();
|
||||
else
|
||||
useUnknownUser(element, "user");
|
||||
}
|
||||
dom.writeToFile(file, false);
|
||||
} else if (file.getName().startsWith("IssueComments.xml")) {
|
||||
VersionedXmlDoc dom = VersionedXmlDoc.fromFile(file);
|
||||
@ -2717,45 +2725,47 @@ public class DataMigrator {
|
||||
if (id > maxId)
|
||||
maxId = id;
|
||||
}
|
||||
Element serviceDeskSettingElement = dom.getRootElement().addElement("io.onedev.server.model.Setting");
|
||||
serviceDeskSettingElement.addAttribute("revision", "0.0");
|
||||
serviceDeskSettingElement.addElement("id").setText(String.valueOf(maxId+1));
|
||||
serviceDeskSettingElement.addElement("key").setText("SERVICE_DESK_SETTING");
|
||||
Element valueElement = serviceDeskSettingElement.addElement("value");
|
||||
valueElement.addAttribute("class", "io.onedev.server.model.support.administration.ServiceDeskSetting");
|
||||
Element senderAuthorizationsElement = valueElement.addElement("senderAuthorizations");
|
||||
Element defaultProjectDesignationsElement = valueElement.addElement("defaultProjectDesignations");
|
||||
Element issueCreationSettingsElement = valueElement.addElement("issueCreationSettings");
|
||||
for (Element oldSenderAuthorizationElement: oldSenderAuthorizationElements) {
|
||||
Element senderAuthorizationElement = senderAuthorizationsElement
|
||||
.addElement("io.onedev.server.model.support.administration.SenderAuthorization");
|
||||
Element defaultProjectDesignationElement = defaultProjectDesignationsElement
|
||||
.addElement("io.onedev.server.model.support.administration.DefaultProjectDesignation");
|
||||
Element issueCreationSettingElement = issueCreationSettingsElement
|
||||
.addElement("io.onedev.server.model.support.administration.IssueCreationSetting");
|
||||
|
||||
Element senderEmailsElement = oldSenderAuthorizationElement.element("senderEmails");
|
||||
if (senderEmailsElement != null) {
|
||||
String senderEmails = senderEmailsElement.getText().trim();
|
||||
senderAuthorizationElement.addElement("senderEmails").setText(senderEmails);
|
||||
defaultProjectDesignationElement.addElement("senderEmails").setText(senderEmails);
|
||||
issueCreationSettingElement.addElement("senderEmails").setText(senderEmails);
|
||||
}
|
||||
|
||||
Element authorizedProjectsElement = oldSenderAuthorizationElement.element("authorizedProjects");
|
||||
if (authorizedProjectsElement != null) {
|
||||
senderAuthorizationElement.addElement("authorizedProjects")
|
||||
.setText(authorizedProjectsElement.getText().trim());
|
||||
}
|
||||
senderAuthorizationElement.addElement("authorizedRoleName")
|
||||
.setText(oldSenderAuthorizationElement.elementText("authorizedRoleName").trim());
|
||||
defaultProjectDesignationElement.addElement("defaultProject")
|
||||
.setText(oldSenderAuthorizationElement.elementText("defaultProject").trim());
|
||||
Element issueFieldsElement = oldSenderAuthorizationElement.element("issueFields");
|
||||
issueFieldsElement.detach();
|
||||
issueCreationSettingElement.add(issueFieldsElement);
|
||||
}
|
||||
|
||||
if (oldSenderAuthorizationElements != null && !oldSenderAuthorizationElements.isEmpty()) {
|
||||
Element serviceDeskSettingElement = dom.getRootElement().addElement("io.onedev.server.model.Setting");
|
||||
serviceDeskSettingElement.addAttribute("revision", "0.0");
|
||||
serviceDeskSettingElement.addElement("id").setText(String.valueOf(maxId+1));
|
||||
serviceDeskSettingElement.addElement("key").setText("SERVICE_DESK_SETTING");
|
||||
Element valueElement = serviceDeskSettingElement.addElement("value");
|
||||
valueElement.addAttribute("class", "io.onedev.server.model.support.administration.ServiceDeskSetting");
|
||||
Element senderAuthorizationsElement = valueElement.addElement("senderAuthorizations");
|
||||
Element projectDesignationsElement = valueElement.addElement("projectDesignations");
|
||||
Element issueCreationSettingsElement = valueElement.addElement("issueCreationSettings");
|
||||
for (Element oldSenderAuthorizationElement: oldSenderAuthorizationElements) {
|
||||
Element senderAuthorizationElement = senderAuthorizationsElement
|
||||
.addElement("io.onedev.server.model.support.administration.SenderAuthorization");
|
||||
Element projectDesignationElement = projectDesignationsElement
|
||||
.addElement("io.onedev.server.model.support.administration.ProjectDesignation");
|
||||
Element issueCreationSettingElement = issueCreationSettingsElement
|
||||
.addElement("io.onedev.server.model.support.administration.IssueCreationSetting");
|
||||
|
||||
Element senderEmailsElement = oldSenderAuthorizationElement.element("senderEmails");
|
||||
if (senderEmailsElement != null) {
|
||||
String senderEmails = senderEmailsElement.getText().trim();
|
||||
senderAuthorizationElement.addElement("senderEmails").setText(senderEmails);
|
||||
projectDesignationElement.addElement("senderEmails").setText(senderEmails);
|
||||
issueCreationSettingElement.addElement("senderEmails").setText(senderEmails);
|
||||
}
|
||||
|
||||
Element authorizedProjectsElement = oldSenderAuthorizationElement.element("authorizedProjects");
|
||||
if (authorizedProjectsElement != null) {
|
||||
senderAuthorizationElement.addElement("authorizedProjects")
|
||||
.setText(authorizedProjectsElement.getText().trim());
|
||||
}
|
||||
senderAuthorizationElement.addElement("authorizedRoleName")
|
||||
.setText(oldSenderAuthorizationElement.elementText("authorizedRoleName").trim());
|
||||
projectDesignationElement.addElement("project")
|
||||
.setText(oldSenderAuthorizationElement.elementText("defaultProject").trim());
|
||||
Element issueFieldsElement = oldSenderAuthorizationElement.element("issueFields");
|
||||
issueFieldsElement.detach();
|
||||
issueCreationSettingElement.add(issueFieldsElement);
|
||||
}
|
||||
}
|
||||
dom.writeToFile(file, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,6 +67,7 @@ import io.onedev.server.buildspec.param.spec.ParamSpec;
|
||||
import io.onedev.server.buildspec.param.spec.SecretParam;
|
||||
import io.onedev.server.buildspec.param.supply.ParamSupply;
|
||||
import io.onedev.server.entitymanager.BuildManager;
|
||||
import io.onedev.server.entityreference.Referenceable;
|
||||
import io.onedev.server.git.GitUtils;
|
||||
import io.onedev.server.git.RefInfo;
|
||||
import io.onedev.server.infomanager.CommitInfoManager;
|
||||
@ -86,7 +87,6 @@ import io.onedev.server.util.IssueUtils;
|
||||
import io.onedev.server.util.JobSecretAuthorizationContext;
|
||||
import io.onedev.server.util.MatrixRunner;
|
||||
import io.onedev.server.util.ProjectScopedNumber;
|
||||
import io.onedev.server.util.Referenceable;
|
||||
import io.onedev.server.util.facade.BuildFacade;
|
||||
import io.onedev.server.util.match.WildcardUtils;
|
||||
import io.onedev.server.util.patternset.PatternSet;
|
||||
|
||||
@ -53,6 +53,7 @@ import io.onedev.server.entitymanager.GroupManager;
|
||||
import io.onedev.server.entitymanager.PullRequestManager;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.entityreference.Referenceable;
|
||||
import io.onedev.server.infomanager.CommitInfoManager;
|
||||
import io.onedev.server.infomanager.PullRequestInfoManager;
|
||||
import io.onedev.server.infomanager.UserInfoManager;
|
||||
@ -66,7 +67,6 @@ import io.onedev.server.storage.AttachmentStorageSupport;
|
||||
import io.onedev.server.util.CollectionUtils;
|
||||
import io.onedev.server.util.Input;
|
||||
import io.onedev.server.util.ProjectScopedNumber;
|
||||
import io.onedev.server.util.Referenceable;
|
||||
import io.onedev.server.util.facade.IssueFacade;
|
||||
import io.onedev.server.web.editable.BeanDescriptor;
|
||||
import io.onedev.server.web.editable.PropertyDescriptor;
|
||||
@ -298,6 +298,13 @@ public class Issue extends AbstractEntity implements Referenceable, AttachmentSt
|
||||
this.threadingReference = threadingReference;
|
||||
}
|
||||
|
||||
public String getEffectiveThreadingReference() {
|
||||
String threadingReference = getThreadingReference();
|
||||
if (threadingReference == null)
|
||||
threadingReference = "<" + getUUID() + "@onedev>";
|
||||
return threadingReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getNumber() {
|
||||
return number;
|
||||
|
||||
@ -56,6 +56,7 @@ import com.google.common.collect.Lists;
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.PullRequestManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.entityreference.Referenceable;
|
||||
import io.onedev.server.git.GitUtils;
|
||||
import io.onedev.server.infomanager.PullRequestInfoManager;
|
||||
import io.onedev.server.infomanager.UserInfoManager;
|
||||
@ -73,7 +74,6 @@ import io.onedev.server.util.ComponentContext;
|
||||
import io.onedev.server.util.IssueUtils;
|
||||
import io.onedev.server.util.ProjectAndBranch;
|
||||
import io.onedev.server.util.ProjectScopedNumber;
|
||||
import io.onedev.server.util.Referenceable;
|
||||
import io.onedev.server.web.util.PullRequestAware;
|
||||
import io.onedev.server.web.util.WicketUtils;
|
||||
|
||||
@ -1175,5 +1175,14 @@ public class PullRequest extends AbstractEntity implements Referenceable, Attach
|
||||
return "Source branch already exists";
|
||||
return null;
|
||||
}
|
||||
|
||||
public String getStatusName() {
|
||||
if (isMerged())
|
||||
return "Merged";
|
||||
else if (isDiscarded())
|
||||
return "Discarded";
|
||||
else
|
||||
return "Open";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -71,7 +71,8 @@ public class MailSetting implements Serializable {
|
||||
}
|
||||
|
||||
@Editable(order=410, name="System Email Address", description="This email address will be used as sender "
|
||||
+ "address for various notifications")
|
||||
+ "address for various notifications. Its inbox will also be checked if <tt>Check Incoming Email</tt>"
|
||||
+ "option is enabled below")
|
||||
@NotEmpty
|
||||
public String getEmailAddress() {
|
||||
return emailAddress;
|
||||
@ -81,10 +82,9 @@ public class MailSetting implements Serializable {
|
||||
this.emailAddress = emailAddress;
|
||||
}
|
||||
|
||||
@Editable(order=450, name="Check Incoming Email", description="Enable this to use the service desk feature (creating issue, "
|
||||
+ "posting issue or pull request comments from email) <br>"
|
||||
@Editable(order=450, name="Check Incoming Email", description="Enable this to post issue and pull request comments via email<br>"
|
||||
+ "<b class='text-danger'>NOTE:</b> <a href='https://en.wikipedia.org/wiki/Email_address#Subaddressing' target='_blank'>Sub addressing</a> "
|
||||
+ "needs to be enabled for your mail server, as OneDev needs to use this to track context of sent email and received email")
|
||||
+ "needs to be enabled for system email address, as OneDev uses it to track issue and pull request contexts")
|
||||
public ReceiveMailSetting getReceiveMailSetting() {
|
||||
return receiveMailSetting;
|
||||
}
|
||||
|
||||
@ -15,13 +15,13 @@ import io.onedev.server.web.editable.annotation.NameOfEmptyValue;
|
||||
import io.onedev.server.web.editable.annotation.Patterns;
|
||||
|
||||
@Editable
|
||||
public class DefaultProjectDesignation implements Serializable {
|
||||
public class ProjectDesignation implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String senderEmails;
|
||||
|
||||
private String defaultProject;
|
||||
private String project;
|
||||
|
||||
@Editable(order=100, name="Applicable Senders", description="Specify space-separated sender "
|
||||
+ "email addresses applicable for this entry. Use '*' or '?' for wildcard match. "
|
||||
@ -39,12 +39,12 @@ public class DefaultProjectDesignation implements Serializable {
|
||||
@Editable(order=200)
|
||||
@ChoiceProvider("getProjectChoices")
|
||||
@NotEmpty
|
||||
public String getDefaultProject() {
|
||||
return defaultProject;
|
||||
public String getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public void setDefaultProject(String defaultProject) {
|
||||
this.defaultProject = defaultProject;
|
||||
public void setProject(String project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@ -7,38 +7,49 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
import edu.emory.mathcs.backport.java.util.Collections;
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.ProjectManager;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.support.issue.field.supply.FieldSupply;
|
||||
import io.onedev.server.util.match.Matcher;
|
||||
import io.onedev.server.util.match.StringMatcher;
|
||||
import io.onedev.server.util.patternset.PatternSet;
|
||||
import io.onedev.server.util.usage.Usage;
|
||||
import io.onedev.server.util.validation.Validatable;
|
||||
import io.onedev.server.util.validation.annotation.ClassValidating;
|
||||
import io.onedev.server.web.component.issue.workflowreconcile.UndefinedFieldResolution;
|
||||
import io.onedev.server.web.component.issue.workflowreconcile.UndefinedFieldValue;
|
||||
import io.onedev.server.web.component.issue.workflowreconcile.UndefinedFieldValuesResolution;
|
||||
import io.onedev.server.web.editable.annotation.Editable;
|
||||
import io.onedev.server.web.editable.annotation.OmitName;
|
||||
|
||||
@Editable
|
||||
public class ServiceDeskSetting implements Serializable {
|
||||
@ClassValidating
|
||||
public class ServiceDeskSetting implements Serializable, Validatable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String PROP_SENDER_AUTHORIZATIONS = "senderAuthorizations";
|
||||
|
||||
public static final String PROP_DEFAULT_PROJECT_DESIGNATIONS = "defaultProjectDesignations";
|
||||
private static final String PROP_PROJECT_DESIGNATIONS = "projectDesignations";
|
||||
|
||||
private static final String PROP_ISSUE_CREATION_SETTINGS = "issueCreationSettings";
|
||||
|
||||
private List<SenderAuthorization> senderAuthorizations = new ArrayList<>();
|
||||
|
||||
private List<DefaultProjectDesignation> defaultProjectDesignations = new ArrayList<>();
|
||||
private List<ProjectDesignation> projectDesignations = new ArrayList<>();
|
||||
|
||||
private List<IssueCreationSetting> issueCreationSettings = new ArrayList<>();
|
||||
|
||||
@Editable
|
||||
@OmitName
|
||||
|
||||
@Editable(order=100, description="When sender email address can not be mapped to an existing user, "
|
||||
+ "OneDev will use entries defined here to determine if the sender has permission to "
|
||||
+ "create issues. For a particular sender, the first matching entry will take "
|
||||
+ "effect")
|
||||
public List<SenderAuthorization> getSenderAuthorizations() {
|
||||
return senderAuthorizations;
|
||||
}
|
||||
@ -47,16 +58,29 @@ public class ServiceDeskSetting implements Serializable {
|
||||
this.senderAuthorizations = senderAuthorizations;
|
||||
}
|
||||
|
||||
@Editable
|
||||
@OmitName
|
||||
public List<DefaultProjectDesignation> getDefaultProjectDesignations() {
|
||||
return defaultProjectDesignations;
|
||||
@Editable(order=200, description="When email is sent to system email address without specifying "
|
||||
+ "project information, OneDev will use entries defined here to decide in which "
|
||||
+ "project to create issues. For a particular sender, the first matching entry will "
|
||||
+ "take effect")
|
||||
public List<ProjectDesignation> getProjectDesignations() {
|
||||
return projectDesignations;
|
||||
}
|
||||
|
||||
public void setDefaultProjectDesignations(List<DefaultProjectDesignation> defaultProjectDesignations) {
|
||||
this.defaultProjectDesignations = defaultProjectDesignations;
|
||||
public void setProjectDesignations(List<ProjectDesignation> projectDesignations) {
|
||||
this.projectDesignations = projectDesignations;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static List<String> getProjectChoices() {
|
||||
List<String> projectNames = OneDev.getInstance(ProjectManager.class)
|
||||
.query().stream().map(it->it.getName()).collect(Collectors.toList());
|
||||
Collections.sort(projectNames);
|
||||
return projectNames;
|
||||
}
|
||||
|
||||
@Editable(order=300, description="Specify issue creation settings. For a particular sender and project, "
|
||||
+ "the first matching entry will take effect. If no entry matches, default issue creation "
|
||||
+ "settings defined below will be used")
|
||||
public List<IssueCreationSetting> getIssueCreationSettings() {
|
||||
return issueCreationSettings;
|
||||
}
|
||||
@ -65,6 +89,11 @@ public class ServiceDeskSetting implements Serializable {
|
||||
this.issueCreationSettings = issueCreationSettings;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static Collection<String> getIssueFieldNames() {
|
||||
return OneDev.getInstance(SettingManager.class).getIssueSetting().getPromptFieldsUponIssueOpen();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SenderAuthorization getSenderAuthorization(String senderAddress) {
|
||||
Matcher matcher = new StringMatcher();
|
||||
@ -79,21 +108,20 @@ public class ServiceDeskSetting implements Serializable {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public DefaultProjectDesignation getDefaultProjectDesignation(String senderAddress) {
|
||||
public String getDesignatedProject(String senderAddress) {
|
||||
Matcher matcher = new StringMatcher();
|
||||
for (DefaultProjectDesignation designation: defaultProjectDesignations) {
|
||||
for (ProjectDesignation designation: projectDesignations) {
|
||||
String patterns = designation.getSenderEmails();
|
||||
if (patterns == null)
|
||||
patterns = "*";
|
||||
PatternSet patternSet = PatternSet.parse(patterns);
|
||||
if (patternSet.matches(matcher, senderAddress))
|
||||
return designation;
|
||||
return designation.getProject();
|
||||
}
|
||||
return null;
|
||||
throw new ExplicitException("No project designated for sender: " + senderAddress);
|
||||
}
|
||||
|
||||
public IssueCreationSetting getIssueCreationSetting(String senderAddress, Project project) {
|
||||
public List<FieldSupply> getIssueCreationSetting(String senderAddress, Project project) {
|
||||
Matcher matcher = new StringMatcher();
|
||||
for (IssueCreationSetting setting: issueCreationSettings) {
|
||||
String senderPatterns = setting.getSenderEmails();
|
||||
@ -107,9 +135,9 @@ public class ServiceDeskSetting implements Serializable {
|
||||
PatternSet projectPatternSet = PatternSet.parse(projectPatterns);
|
||||
|
||||
if (senderPatternSet.matches(matcher, senderAddress) && projectPatternSet.matches(matcher, project.getName()))
|
||||
return setting;
|
||||
return setting.getIssueFields();
|
||||
}
|
||||
String errorMessage = String.format("No issue creation setting found (sender: %s, project: %s)",
|
||||
String errorMessage = String.format("No issue creation setting (sender: %s, project: %s)",
|
||||
senderAddress, project.getName());
|
||||
throw new ExplicitException(errorMessage);
|
||||
}
|
||||
@ -143,9 +171,9 @@ public class ServiceDeskSetting implements Serializable {
|
||||
if (authorization.getAuthorizedProjects().length() == 0)
|
||||
authorization.setAuthorizedProjects(null);
|
||||
}
|
||||
for (DefaultProjectDesignation designation: getDefaultProjectDesignations()) {
|
||||
if (designation.getDefaultProject().equals(oldName))
|
||||
designation.setDefaultProject(newName);
|
||||
for (ProjectDesignation designation: getProjectDesignations()) {
|
||||
if (designation.getProject().equals(oldName))
|
||||
designation.setProject(newName);
|
||||
}
|
||||
for (IssueCreationSetting setting: getIssueCreationSettings()) {
|
||||
PatternSet patternSet = PatternSet.parse(setting.getApplicableProjects());
|
||||
@ -171,9 +199,9 @@ public class ServiceDeskSetting implements Serializable {
|
||||
}
|
||||
|
||||
index = 0;
|
||||
for (DefaultProjectDesignation designation: getDefaultProjectDesignations()) {
|
||||
if (designation.getDefaultProject().equals(projectName))
|
||||
usage.add("default project designation #" + index + ": default project");
|
||||
for (ProjectDesignation senderProject: getProjectDesignations()) {
|
||||
if (senderProject.getProject().equals(projectName))
|
||||
usage.add("sender project #" + index + ": project");
|
||||
index++;
|
||||
}
|
||||
|
||||
@ -210,5 +238,47 @@ public class ServiceDeskSetting implements Serializable {
|
||||
for (IssueCreationSetting setting: getIssueCreationSettings())
|
||||
setting.fixUndefinedFieldValues(resolutions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(ConstraintValidatorContext context) {
|
||||
boolean isValid = true;
|
||||
|
||||
boolean foundDefault = false;
|
||||
for (ProjectDesignation designation: getProjectDesignations()) {
|
||||
if (designation.getSenderEmails() == null) {
|
||||
foundDefault = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundDefault) {
|
||||
String errorMessage = "An entry with any sender should be defined to be used as "
|
||||
+ "default project designation";
|
||||
context.buildConstraintViolationWithTemplate(errorMessage)
|
||||
.addPropertyNode(PROP_PROJECT_DESIGNATIONS)
|
||||
.addConstraintViolation();
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
foundDefault = false;
|
||||
for (IssueCreationSetting setting: getIssueCreationSettings()) {
|
||||
if (setting.getSenderEmails() == null && setting.getApplicableProjects() == null) {
|
||||
foundDefault = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundDefault) {
|
||||
String errorMessage = "An entry with any sender and any project should be defined "
|
||||
+ "to be use as default issue creation setting";
|
||||
context.buildConstraintViolationWithTemplate(errorMessage)
|
||||
.addPropertyNode(PROP_ISSUE_CREATION_SETTINGS)
|
||||
.addConstraintViolation();
|
||||
isValid = false;
|
||||
}
|
||||
|
||||
if (!isValid)
|
||||
context.disableDefaultConstraintViolation();
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ public class NotificationTemplateSetting implements Serializable {
|
||||
+ "When evaluating this template, below variables will be available:"
|
||||
+ "<ul class='mb-0'>"
|
||||
+ "<li><code>event:</code> <a href='https://code.onedev.io/projects/onedev-server/blob/main/server-core/src/main/java/io/onedev/server/event/Event.java' target='_blank'>event object</a> triggering the notification"
|
||||
+ "<li><code>eventSummary:</code> a string representing summary of the event"
|
||||
+ "<li><code>eventSummary:</code> a string representing summary of the event. May be <code>null</code>"
|
||||
+ "<li><code>eventBody:</code> a string representing body of the event. May be <code>null</code>"
|
||||
+ "<li><code>eventUrl:</code> a string representing event detail url"
|
||||
+ "<li><code>replyable:</code> a boolean indiciating whether or not topic comment can be created directly by replying the email"
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
<%
|
||||
print "<b>${eventSummary}</b>"
|
||||
print "<br><br>"
|
||||
if (eventSummary != null) {
|
||||
print "<b>${eventSummary}</b>"
|
||||
print "<br><br>"
|
||||
}
|
||||
|
||||
if (eventBody != null) {
|
||||
print eventBody
|
||||
@ -21,7 +23,7 @@
|
||||
if (unsubscribable != null) {
|
||||
print """
|
||||
<div style='border-top:1px solid #EEE; margin-top:1em; padding-top:1em; color:#666; font-size:0.9em;'>You received this as you
|
||||
are participating or participated previously in this topic.
|
||||
are participating in this topic.
|
||||
"""
|
||||
if (unsubscribable.getEmailAddress() != null)
|
||||
print """
|
||||
|
||||
@ -5,15 +5,9 @@ import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.IssueChangeManager;
|
||||
import io.onedev.server.model.IssueChange;
|
||||
import io.onedev.server.model.Milestone;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.util.Input;
|
||||
import io.onedev.server.web.component.issue.activities.activity.IssueFieldChangePanel;
|
||||
|
||||
public class IssueBatchUpdateData extends IssueFieldChangeData {
|
||||
|
||||
@ -96,21 +90,6 @@ public class IssueBatchUpdateData extends IssueFieldChangeData {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, IssueChange change) {
|
||||
Long changeId = change.getId();
|
||||
return new IssueFieldChangePanel(componentId, true) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected IssueChange getChange() {
|
||||
return OneDev.getInstance(IssueChangeManager.class).load(changeId);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivity() {
|
||||
return "batch edited";
|
||||
|
||||
@ -6,26 +6,29 @@ import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.IssueChange;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public interface IssueChangeData extends Serializable {
|
||||
public abstract class IssueChangeData implements Serializable {
|
||||
|
||||
Component render(String componentId, IssueChange change);
|
||||
|
||||
String getActivity();
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public abstract String getActivity();
|
||||
|
||||
@Nullable
|
||||
CommentAware getCommentAware();
|
||||
public abstract CommentAware getCommentAware();
|
||||
|
||||
Map<String, Collection<User>> getNewUsers();
|
||||
public abstract Map<String, Collection<User>> getNewUsers();
|
||||
|
||||
Map<String, Group> getNewGroups();
|
||||
public abstract Map<String, Group> getNewGroups();
|
||||
|
||||
boolean affectsBoards();
|
||||
public abstract boolean affectsBoards();
|
||||
|
||||
@Nullable
|
||||
public ActivityDetail getActivityDetail() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,65 +0,0 @@
|
||||
package io.onedev.server.model.support.issue.changedata;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.IssueChange;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class IssueDescriptionChangeData implements IssueChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String oldDescription;
|
||||
|
||||
private final String newDescription;
|
||||
|
||||
public IssueDescriptionChangeData(String oldDescription, String newDescription) {
|
||||
this.oldDescription = oldDescription;
|
||||
this.newDescription = newDescription;
|
||||
}
|
||||
|
||||
public String getOldDescription() {
|
||||
return oldDescription;
|
||||
}
|
||||
|
||||
public String getNewDescription() {
|
||||
return newDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, IssueChange change) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivity() {
|
||||
return "changed description";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommentAware getCommentAware() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Collection<User>> getNewUsers() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Group> getNewGroups() {
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean affectsBoards() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@ -9,21 +9,18 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.commons.utils.StringUtils;
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.GroupManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.IssueChange;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.model.support.issue.field.spec.FieldSpec;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.util.Input;
|
||||
import io.onedev.server.web.component.propertychangepanel.PropertyChangePanel;
|
||||
|
||||
public class IssueFieldChangeData implements IssueChangeData {
|
||||
public class IssueFieldChangeData extends IssueChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -63,11 +60,6 @@ public class IssueFieldChangeData implements IssueChangeData {
|
||||
return field.getName() + ": " + StringUtils.join(field.getValues(), ", ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, IssueChange change) {
|
||||
return new PropertyChangePanel(componentId, getOldFieldValues(), getNewFieldValues(), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivity() {
|
||||
return "changed fields";
|
||||
@ -80,11 +72,6 @@ public class IssueFieldChangeData implements IssueChangeData {
|
||||
return lines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommentAware getCommentAware() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Collection<User>> getNewUsers() {
|
||||
UserManager userManager = OneDev.getInstance(UserManager.class);
|
||||
@ -151,4 +138,14 @@ public class IssueFieldChangeData implements IssueChangeData {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommentAware getCommentAware() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
return ActivityDetail.compare(getOldFieldValues(), getNewFieldValues(), false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -6,17 +6,13 @@ import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.IssueChange;
|
||||
import io.onedev.server.model.Milestone;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.util.CollectionUtils;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.web.component.propertychangepanel.PropertyChangePanel;
|
||||
|
||||
public class IssueMilestoneChangeData implements IssueChangeData {
|
||||
public class IssueMilestoneChangeData extends IssueChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -29,14 +25,6 @@ public class IssueMilestoneChangeData implements IssueChangeData {
|
||||
this.newMilestone = newMilestone!=null?newMilestone.getName():null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, IssueChange change) {
|
||||
return new PropertyChangePanel(componentId,
|
||||
CollectionUtils.newHashMap("Milestone", oldMilestone),
|
||||
CollectionUtils.newHashMap("Milestone", newMilestone),
|
||||
true);
|
||||
}
|
||||
|
||||
public String getOldMilestone() {
|
||||
return oldMilestone;
|
||||
}
|
||||
@ -69,5 +57,14 @@ public class IssueMilestoneChangeData implements IssueChangeData {
|
||||
public boolean affectsBoards() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
Map<String, String> oldFieldValues = new HashMap<>();
|
||||
oldFieldValues.put("Milestone", oldMilestone);
|
||||
Map<String, String> newFieldValues = new HashMap<>();
|
||||
oldFieldValues.put("Milestone", newMilestone);
|
||||
return ActivityDetail.compare(oldFieldValues, newFieldValues, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -4,17 +4,17 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.CodeCommentManager;
|
||||
import io.onedev.server.entityreference.ReferencedFromAware;
|
||||
import io.onedev.server.model.CodeComment;
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.IssueChange;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.rest.annotation.EntityId;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.web.component.codecomment.referencedfrom.ReferencedFromCodeCommentPanel;
|
||||
|
||||
public class IssueReferencedFromCodeCommentData implements IssueChangeData {
|
||||
public class IssueReferencedFromCodeCommentData extends IssueChangeData implements ReferencedFromAware<CodeComment> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -34,11 +34,6 @@ public class IssueReferencedFromCodeCommentData implements IssueChangeData {
|
||||
return "Referenced from code comment";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, IssueChange change) {
|
||||
return new ReferencedFromCodeCommentPanel(componentId, commentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommentAware getCommentAware() {
|
||||
return null;
|
||||
@ -59,4 +54,14 @@ public class IssueReferencedFromCodeCommentData implements IssueChangeData {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
return ActivityDetail.referencedFrom(getReferencedFrom());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeComment getReferencedFrom() {
|
||||
return OneDev.getInstance(CodeCommentManager.class).get(commentId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -4,17 +4,17 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.IssueManager;
|
||||
import io.onedev.server.entityreference.ReferencedFromAware;
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.Issue;
|
||||
import io.onedev.server.model.IssueChange;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.rest.annotation.EntityId;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.web.component.issue.referencedfrom.ReferencedFromIssuePanel;
|
||||
|
||||
public class IssueReferencedFromIssueData implements IssueChangeData {
|
||||
public class IssueReferencedFromIssueData extends IssueChangeData implements ReferencedFromAware<Issue> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -29,11 +29,6 @@ public class IssueReferencedFromIssueData implements IssueChangeData {
|
||||
return issueId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, IssueChange change) {
|
||||
return new ReferencedFromIssuePanel(componentId, issueId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivity() {
|
||||
return "Referenced from other issue";
|
||||
@ -58,5 +53,15 @@ public class IssueReferencedFromIssueData implements IssueChangeData {
|
||||
public boolean affectsBoards() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Issue getReferencedFrom() {
|
||||
return OneDev.getInstance(IssueManager.class).get(issueId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
return ActivityDetail.referencedFrom(getReferencedFrom());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -4,17 +4,17 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.PullRequestManager;
|
||||
import io.onedev.server.entityreference.ReferencedFromAware;
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.IssueChange;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.rest.annotation.EntityId;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.web.component.pullrequest.referencedfrom.ReferencedFromPullRequestPanel;
|
||||
|
||||
public class IssueReferencedFromPullRequestData implements IssueChangeData {
|
||||
public class IssueReferencedFromPullRequestData extends IssueChangeData implements ReferencedFromAware<PullRequest> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -29,11 +29,6 @@ public class IssueReferencedFromPullRequestData implements IssueChangeData {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, IssueChange change) {
|
||||
return new ReferencedFromPullRequestPanel(componentId, requestId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivity() {
|
||||
return "Referenced from pull request";
|
||||
@ -58,5 +53,15 @@ public class IssueReferencedFromPullRequestData implements IssueChangeData {
|
||||
public boolean affectsBoards() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public PullRequest getReferencedFrom() {
|
||||
return OneDev.getInstance(PullRequestManager.class).get(requestId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
return ActivityDetail.referencedFrom(getReferencedFrom());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -5,14 +5,9 @@ import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.IssueChangeManager;
|
||||
import io.onedev.server.model.IssueChange;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.util.Input;
|
||||
import io.onedev.server.web.component.issue.activities.activity.IssueFieldChangePanel;
|
||||
|
||||
public class IssueStateChangeData extends IssueFieldChangeData {
|
||||
|
||||
@ -76,25 +71,14 @@ public class IssueStateChangeData extends IssueFieldChangeData {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, IssueChange change) {
|
||||
Long changeId = change.getId();
|
||||
|
||||
return new IssueFieldChangePanel(componentId, true) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected IssueChange getChange() {
|
||||
return OneDev.getInstance(IssueChangeManager.class).load(changeId);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivity() {
|
||||
return "changed state to '" + newState + "'";
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
return ActivityDetail.compare(getOldFieldValues(), getNewFieldValues(), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -4,16 +4,12 @@ import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.IssueChange;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.util.CollectionUtils;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.web.component.propertychangepanel.PropertyChangePanel;
|
||||
|
||||
public class IssueTitleChangeData implements IssueChangeData {
|
||||
public class IssueTitleChangeData extends IssueChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -26,14 +22,6 @@ public class IssueTitleChangeData implements IssueChangeData {
|
||||
this.newTitle = newTitle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, IssueChange change) {
|
||||
return new PropertyChangePanel(componentId,
|
||||
CollectionUtils.newHashMap("Title", oldTitle),
|
||||
CollectionUtils.newHashMap("Title", newTitle),
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivity() {
|
||||
return "changed title";
|
||||
@ -58,5 +46,14 @@ public class IssueTitleChangeData implements IssueChangeData {
|
||||
public boolean affectsBoards() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
Map<String, String> oldFieldValues = new HashMap<>();
|
||||
oldFieldValues.put("Title", oldTitle);
|
||||
Map<String, String> newFieldValues = new HashMap<>();
|
||||
oldFieldValues.put("Title", newTitle);
|
||||
return ActivityDetail.compare(oldFieldValues, newFieldValues, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,14 +2,9 @@ package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.PullRequestChangeManager;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class PullRequestApproveData implements PullRequestChangeData {
|
||||
public class PullRequestApproveData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -24,21 +19,6 @@ public class PullRequestApproveData implements PullRequestChangeData {
|
||||
return "approved";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
Long changeId = change.getId();
|
||||
return new PullRequestChangeCommentPanel(componentId) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected PullRequestChange getChange() {
|
||||
return OneDev.getInstance(PullRequestChangeManager.class).load(changeId);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommentAware getCommentAware() {
|
||||
return new CommentAware() {
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class PullRequestAssigneeAddData implements PullRequestChangeData {
|
||||
public class PullRequestAssigneeAddData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -25,9 +22,4 @@ public class PullRequestAssigneeAddData implements PullRequestChangeData {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class PullRequestAssigneeRemoveData implements PullRequestChangeData {
|
||||
public class PullRequestAssigneeRemoveData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -25,9 +22,4 @@ public class PullRequestAssigneeRemoveData implements PullRequestChangeData {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,75 +0,0 @@
|
||||
package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.wicket.ajax.AjaxRequestTarget;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.PullRequestChangeManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import io.onedev.server.web.component.markdown.AttachmentSupport;
|
||||
import io.onedev.server.web.component.markdown.ContentVersionSupport;
|
||||
import io.onedev.server.web.component.project.comment.ProjectCommentPanel;
|
||||
import io.onedev.server.web.util.DeleteCallback;
|
||||
import io.onedev.server.web.util.ProjectAttachmentSupport;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class PullRequestChangeCommentPanel extends ProjectCommentPanel {
|
||||
|
||||
public PullRequestChangeCommentPanel(String id) {
|
||||
super(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getComment() {
|
||||
return getChange().getData().getCommentAware().getComment();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<User> getMentionables() {
|
||||
return OneDev.getInstance(UserManager.class).queryAndSort(getChange().getRequest().getParticipants());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveComment(AjaxRequestTarget target, String comment) {
|
||||
getChange().getData().getCommentAware().setComment(comment);
|
||||
OneDev.getInstance(PullRequestChangeManager.class).save(getChange());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Project getProject() {
|
||||
return getChange().getRequest().getTargetProject();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AttachmentSupport getAttachmentSupport() {
|
||||
return new ProjectAttachmentSupport(getProject(), getChange().getRequest().getUUID(),
|
||||
SecurityUtils.canManagePullRequests(getProject()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canModifyOrDeleteComment() {
|
||||
return SecurityUtils.canModifyOrDelete(getChange());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getRequiredLabel() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ContentVersionSupport getContentVersionSupport() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DeleteCallback getDeleteCallback() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected abstract PullRequestChange getChange();
|
||||
}
|
||||
@ -4,18 +4,21 @@ import java.io.Serializable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public interface PullRequestChangeData extends Serializable {
|
||||
public abstract class PullRequestChangeData implements Serializable {
|
||||
|
||||
Component render(String componentId, PullRequestChange change);
|
||||
|
||||
String getActivity();
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public abstract String getActivity();
|
||||
|
||||
@Nullable
|
||||
CommentAware getCommentAware();
|
||||
public abstract CommentAware getCommentAware();
|
||||
|
||||
@Nullable
|
||||
public ActivityDetail getActivityDetail() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class PullRequestDescriptionChangeData implements PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String oldDescription;
|
||||
|
||||
private final String newDescription;
|
||||
|
||||
public PullRequestDescriptionChangeData(String oldDescription, String newDescription) {
|
||||
this.oldDescription = oldDescription;
|
||||
this.newDescription = newDescription;
|
||||
}
|
||||
|
||||
public String getOldDescription() {
|
||||
return oldDescription;
|
||||
}
|
||||
|
||||
public String getNewDescription() {
|
||||
return newDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivity() {
|
||||
return "changed description";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommentAware getCommentAware() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@ -2,14 +2,9 @@ package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.PullRequestChangeManager;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class PullRequestDiscardData implements PullRequestChangeData {
|
||||
public class PullRequestDiscardData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -43,19 +38,4 @@ public class PullRequestDiscardData implements PullRequestChangeData {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
Long changeId = change.getId();
|
||||
return new PullRequestChangeCommentPanel(componentId) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected PullRequestChange getChange() {
|
||||
return OneDev.getInstance(PullRequestChangeManager.class).load(changeId);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,12 +2,9 @@ package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class PullRequestMergeData implements PullRequestChangeData {
|
||||
public class PullRequestMergeData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -25,11 +22,6 @@ public class PullRequestMergeData implements PullRequestChangeData {
|
||||
return "merged";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommentAware getCommentAware() {
|
||||
return null;
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.model.support.pullrequest.MergeStrategy;
|
||||
import io.onedev.server.util.CollectionUtils;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.web.component.propertychangepanel.PropertyChangePanel;
|
||||
|
||||
public class PullRequestMergeStrategyChangeData implements PullRequestChangeData {
|
||||
public class PullRequestMergeStrategyChangeData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -26,17 +25,19 @@ public class PullRequestMergeStrategyChangeData implements PullRequestChangeData
|
||||
return "changed merge strategy";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
return new PropertyChangePanel(componentId,
|
||||
CollectionUtils.newHashMap("Merge Strategy", oldStrategy.toString()),
|
||||
CollectionUtils.newHashMap("Merge Strategy", newStrategy.toString()),
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommentAware getCommentAware() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
Map<String, String> oldProperties = new HashMap<>();
|
||||
oldProperties.put("Merge Strategy", oldStrategy.name());
|
||||
Map<String, String> newProperties = new HashMap<>();
|
||||
oldProperties.put("Merge Strategy", newStrategy.name());
|
||||
|
||||
return ActivityDetail.compare(oldProperties, newProperties, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.CodeCommentManager;
|
||||
import io.onedev.server.entityreference.ReferencedFromAware;
|
||||
import io.onedev.server.model.CodeComment;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.rest.annotation.EntityId;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.web.component.codecomment.referencedfrom.ReferencedFromCodeCommentPanel;
|
||||
|
||||
public class PullRequestReferencedFromCodeCommentData implements PullRequestChangeData {
|
||||
public class PullRequestReferencedFromCodeCommentData
|
||||
extends PullRequestChangeData implements ReferencedFromAware<CodeComment> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -23,11 +24,6 @@ public class PullRequestReferencedFromCodeCommentData implements PullRequestChan
|
||||
return commentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
return new ReferencedFromCodeCommentPanel(componentId, commentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivity() {
|
||||
return "Referenced from code comment";
|
||||
@ -38,4 +34,14 @@ public class PullRequestReferencedFromCodeCommentData implements PullRequestChan
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeComment getReferencedFrom() {
|
||||
return OneDev.getInstance(CodeCommentManager.class).get(commentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
return ActivityDetail.referencedFrom(getReferencedFrom());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.IssueManager;
|
||||
import io.onedev.server.entityreference.ReferencedFromAware;
|
||||
import io.onedev.server.model.Issue;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.rest.annotation.EntityId;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.web.component.issue.referencedfrom.ReferencedFromIssuePanel;
|
||||
|
||||
public class PullRequestReferencedFromIssueData implements PullRequestChangeData {
|
||||
public class PullRequestReferencedFromIssueData
|
||||
extends PullRequestChangeData implements ReferencedFromAware<Issue> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -23,11 +24,6 @@ public class PullRequestReferencedFromIssueData implements PullRequestChangeData
|
||||
return issueId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
return new ReferencedFromIssuePanel(componentId, issueId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivity() {
|
||||
return "Referenced from issue";
|
||||
@ -38,4 +34,14 @@ public class PullRequestReferencedFromIssueData implements PullRequestChangeData
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Issue getReferencedFrom() {
|
||||
return OneDev.getInstance(IssueManager.class).get(issueId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
return ActivityDetail.referencedFrom(getReferencedFrom());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.PullRequestManager;
|
||||
import io.onedev.server.entityreference.ReferencedFromAware;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.rest.annotation.EntityId;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.web.component.pullrequest.referencedfrom.ReferencedFromPullRequestPanel;
|
||||
|
||||
public class PullRequestReferencedFromPullRequestData implements PullRequestChangeData {
|
||||
public class PullRequestReferencedFromPullRequestData
|
||||
extends PullRequestChangeData implements ReferencedFromAware<PullRequest> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -23,11 +24,6 @@ public class PullRequestReferencedFromPullRequestData implements PullRequestChan
|
||||
return requestId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
return new ReferencedFromPullRequestPanel(componentId, requestId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActivity() {
|
||||
return "Referenced from other pull request";
|
||||
@ -38,4 +34,14 @@ public class PullRequestReferencedFromPullRequestData implements PullRequestChan
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PullRequest getReferencedFrom() {
|
||||
return OneDev.getInstance(PullRequestManager.class).get(requestId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
return ActivityDetail.referencedFrom(getReferencedFrom());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,14 +2,9 @@ package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.PullRequestChangeManager;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class PullRequestReopenData implements PullRequestChangeData {
|
||||
public class PullRequestReopenData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -43,19 +38,4 @@ public class PullRequestReopenData implements PullRequestChangeData {
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
Long changeId = change.getId();
|
||||
return new PullRequestChangeCommentPanel(componentId) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected PullRequestChange getChange() {
|
||||
return OneDev.getInstance(PullRequestChangeManager.class).load(changeId);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,14 +2,9 @@ package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.PullRequestChangeManager;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class PullRequestRequestedForChangesData implements PullRequestChangeData {
|
||||
public class PullRequestRequestedForChangesData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -43,19 +38,4 @@ public class PullRequestRequestedForChangesData implements PullRequestChangeData
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
Long changeId = change.getId();
|
||||
return new PullRequestChangeCommentPanel(componentId) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected PullRequestChange getChange() {
|
||||
return OneDev.getInstance(PullRequestChangeManager.class).load(changeId);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,8 @@
|
||||
package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class PullRequestReviewerAddData implements PullRequestChangeData {
|
||||
public class PullRequestReviewerAddData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -25,9 +22,4 @@ public class PullRequestReviewerAddData implements PullRequestChangeData {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class PullRequestReviewerRemoveData implements PullRequestChangeData {
|
||||
public class PullRequestReviewerRemoveData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -25,9 +22,4 @@ public class PullRequestReviewerRemoveData implements PullRequestChangeData {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,14 +2,9 @@ package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.PullRequestChangeManager;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class PullRequestSourceBranchDeleteData implements PullRequestChangeData {
|
||||
public class PullRequestSourceBranchDeleteData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -43,19 +38,4 @@ public class PullRequestSourceBranchDeleteData implements PullRequestChangeData
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
Long changeId = change.getId();
|
||||
return new PullRequestChangeCommentPanel(componentId) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected PullRequestChange getChange() {
|
||||
return OneDev.getInstance(PullRequestChangeManager.class).load(changeId);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2,14 +2,9 @@ package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.PullRequestChangeManager;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
|
||||
public class PullRequestSourceBranchRestoreData implements PullRequestChangeData {
|
||||
public class PullRequestSourceBranchRestoreData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -43,19 +38,4 @@ public class PullRequestSourceBranchRestoreData implements PullRequestChangeData
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
Long changeId = change.getId();
|
||||
return new PullRequestChangeCommentPanel(componentId) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected PullRequestChange getChange() {
|
||||
return OneDev.getInstance(PullRequestChangeManager.class).load(changeId);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,13 +1,12 @@
|
||||
package io.onedev.server.model.support.pullrequest.changedata;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.util.CollectionUtils;
|
||||
import io.onedev.server.notification.ActivityDetail;
|
||||
import io.onedev.server.util.CommentAware;
|
||||
import io.onedev.server.web.component.propertychangepanel.PropertyChangePanel;
|
||||
|
||||
public class PullRequestTitleChangeData implements PullRequestChangeData {
|
||||
public class PullRequestTitleChangeData extends PullRequestChangeData {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -25,17 +24,19 @@ public class PullRequestTitleChangeData implements PullRequestChangeData {
|
||||
return "changed title";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component render(String componentId, PullRequestChange change) {
|
||||
return new PropertyChangePanel(componentId,
|
||||
CollectionUtils.newHashMap("Title", oldTitle),
|
||||
CollectionUtils.newHashMap("Title", newTitle),
|
||||
true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommentAware getCommentAware() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActivityDetail getActivityDetail() {
|
||||
Map<String, String> oldProperties = new HashMap<>();
|
||||
oldProperties.put("Title", oldTitle);
|
||||
Map<String, String> newProperties = new HashMap<>();
|
||||
oldProperties.put("Title", newTitle);
|
||||
|
||||
return ActivityDetail.compare(oldProperties, newProperties, true);
|
||||
}
|
||||
|
||||
}
|
||||
@ -13,17 +13,14 @@ import groovy.text.SimpleTemplateEngine;
|
||||
import io.onedev.commons.utils.StringUtils;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.event.Event;
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.event.ProjectEvent;
|
||||
import io.onedev.server.event.entity.EntityPersisted;
|
||||
import io.onedev.server.event.issue.IssueEvent;
|
||||
import io.onedev.server.event.pullrequest.PullRequestEvent;
|
||||
import io.onedev.server.markdown.MarkdownManager;
|
||||
import io.onedev.server.model.AbstractEntity;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.PullRequestAssignment;
|
||||
import io.onedev.server.model.PullRequestReview;
|
||||
import io.onedev.server.model.support.administration.notificationtemplate.NotificationTemplateSetting;
|
||||
import io.onedev.server.util.markdown.MarkdownManager;
|
||||
|
||||
public abstract class AbstractNotificationManager {
|
||||
|
||||
@ -36,23 +33,14 @@ public abstract class AbstractNotificationManager {
|
||||
this.settingManager = settingManager;
|
||||
}
|
||||
|
||||
protected String getHtmlBody(Event event, String eventSummary, @Nullable String eventBody,
|
||||
protected String getHtmlBody(Event event, @Nullable String eventSummary, @Nullable String eventBody,
|
||||
String eventUrl, boolean replyable, @Nullable Unsubscribable unsubscribable) {
|
||||
if (eventBody == null && event instanceof MarkdownAware) {
|
||||
eventBody = ((MarkdownAware) event).getMarkdown();
|
||||
if (eventBody != null) {
|
||||
Project project = null;
|
||||
if (event instanceof ProjectEvent)
|
||||
project = ((ProjectEvent) event).getProject();
|
||||
eventBody = markdownManager.process(markdownManager.render(eventBody), project, null, true);
|
||||
}
|
||||
}
|
||||
|
||||
String template = null;
|
||||
|
||||
Map<String, Object> bindings = new HashMap<>();
|
||||
|
||||
eventSummary = HtmlEscape.escapeHtml5(eventSummary);
|
||||
if (eventSummary != null)
|
||||
eventSummary = HtmlEscape.escapeHtml5(eventSummary);
|
||||
eventUrl = HtmlEscape.escapeHtml5(eventUrl);
|
||||
|
||||
bindings.put("event", event);
|
||||
@ -88,13 +76,11 @@ public abstract class AbstractNotificationManager {
|
||||
}
|
||||
}
|
||||
|
||||
protected String getTextBody(Event event, String eventSummary, @Nullable String eventBody,
|
||||
protected String getTextBody(Event event, @Nullable String eventSummary, @Nullable String eventBody,
|
||||
String eventUrl, boolean replyable, @Nullable Unsubscribable unsubscribable) {
|
||||
StringBuilder textBody = new StringBuilder(eventSummary).append("\n\n");
|
||||
|
||||
if (eventBody == null && event instanceof MarkdownAware)
|
||||
eventBody = ((MarkdownAware) event).getMarkdown();
|
||||
|
||||
StringBuilder textBody = new StringBuilder();
|
||||
if (eventSummary != null)
|
||||
textBody.append(eventSummary).append("\n\n");
|
||||
if (eventBody != null)
|
||||
textBody.append(eventBody).append("\n\n");
|
||||
|
||||
@ -104,8 +90,8 @@ public abstract class AbstractNotificationManager {
|
||||
textBody.append("Visit " + eventUrl + " for details");
|
||||
|
||||
if (unsubscribable != null) {
|
||||
textBody.append("\n\n---------------------------------------------\nYou received this as you "
|
||||
+ "are participating or participated previously in this topic. ");
|
||||
textBody.append("\n\n---------------------------------------------\nYou received this notification as you "
|
||||
+ "are participating in this topic. ");
|
||||
if (unsubscribable.getEmailAddress() != null) {
|
||||
textBody.append(String.format("Mail to %s with any content to unsubscribe",
|
||||
unsubscribable.getEmailAddress()));
|
||||
|
||||
@ -0,0 +1,185 @@
|
||||
package io.onedev.server.notification;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
import org.apache.wicket.markup.html.basic.Label;
|
||||
import org.unbescape.html.HtmlEscape;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.UrlManager;
|
||||
import io.onedev.server.model.CodeComment;
|
||||
import io.onedev.server.model.Issue;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
import io.onedev.server.util.HtmlUtils;
|
||||
import io.onedev.server.util.PropertyChange;
|
||||
import io.onedev.server.web.component.codecomment.referencedfrom.ReferencedFromCodeCommentPanel;
|
||||
import io.onedev.server.web.component.issue.referencedfrom.ReferencedFromIssuePanel;
|
||||
import io.onedev.server.web.component.pullrequest.referencedfrom.ReferencedFromPullRequestPanel;
|
||||
|
||||
public class ActivityDetail implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final String htmlVersion;
|
||||
|
||||
private final String textVersion;
|
||||
|
||||
public ActivityDetail(String htmlVersion, String textVersion) {
|
||||
this.htmlVersion = htmlVersion;
|
||||
this.textVersion = textVersion;
|
||||
}
|
||||
|
||||
public String getHtmlVersion() {
|
||||
return htmlVersion;
|
||||
}
|
||||
|
||||
public String getTextVersion() {
|
||||
return textVersion;
|
||||
}
|
||||
|
||||
public Component render(String componentId) {
|
||||
return new Label(componentId, htmlVersion).setEscapeModelStrings(false);
|
||||
}
|
||||
|
||||
private static String compareAsHtml(Map<String, String> oldProperties, Map<String, String> newProperties,
|
||||
boolean hideNameIfOnlyOneRow) {
|
||||
List<PropertyChange> changes = PropertyChange.listOf(oldProperties, newProperties);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("<table class='field-compare' style='border:1px solid #EBEDF3; border-collapse:collapse;'>");
|
||||
builder.append(" <thead>");
|
||||
builder.append(" <tr>");
|
||||
if (changes.size() != 1 || !hideNameIfOnlyOneRow)
|
||||
builder.append(" <th style='padding:0.4em 0.6em; border-bottom:1px solid #EBEDF3; font-size:0.9em; text-align:left;'>Name</th>");
|
||||
builder.append(" <th style='padding:0.4em 0.6em; border-bottom:1px solid #EBEDF3; font-size:0.9em; text-align:left;'>Previous Value</th>");
|
||||
builder.append(" <th style='padding:0.4em 0.6em; border-bottom:1px solid #EBEDF3; font-size:0.9em; text-align:left;'>Current Value</th>");
|
||||
builder.append(" </tr>");
|
||||
builder.append(" </thead>");
|
||||
builder.append(" <tbody>");
|
||||
for (PropertyChange change: changes) {
|
||||
builder.append("<tr>");
|
||||
if (changes.size() != 1 || !hideNameIfOnlyOneRow) {
|
||||
builder.append(" <td style='padding:0.4em 0.6em; border-bottom:1px solid #EBEDF3; font-size:0.9em; text-align:left;'>");
|
||||
builder.append(HtmlUtils.formatAsHtml(change.getName()));
|
||||
builder.append(" </td>");
|
||||
}
|
||||
builder.append(" <td style='padding:0.4em 0.6em; border-bottom:1px solid #EBEDF3; font-size:0.9em; text-align:left;'>");
|
||||
if (change.getOldValue() != null)
|
||||
builder.append(HtmlUtils.formatAsHtml(change.getOldValue()));
|
||||
else
|
||||
builder.append("<i>empty</i>");
|
||||
builder.append(" </td>");
|
||||
builder.append(" <td style='padding:0.4em 0.6em; border-bottom:1px solid #EBEDF3; font-size:0.9em; text-align:left;'>");
|
||||
if (change.getNewValue() != null)
|
||||
builder.append(HtmlUtils.formatAsHtml(change.getNewValue()));
|
||||
else
|
||||
builder.append("<i>empty</i>");
|
||||
builder.append(" </td>");
|
||||
builder.append("</tr>");
|
||||
}
|
||||
builder.append(" </tbody>");
|
||||
builder.append(" </table>");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static String compareAsText(Map<String, String> oldProperties, Map<String, String> newProperties,
|
||||
boolean hideNameIfOnlyOneRow) {
|
||||
List<PropertyChange> changes = PropertyChange.listOf(oldProperties, newProperties);
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (PropertyChange change: changes) {
|
||||
builder.append("----------------------------------------\n");
|
||||
if (changes.size() != 1 || !hideNameIfOnlyOneRow) {
|
||||
builder.append("Name: ").append(change.getName());
|
||||
builder.append("\n");
|
||||
}
|
||||
builder.append("Previous Value: ");
|
||||
if (change.getOldValue() != null)
|
||||
builder.append(change.getOldValue());
|
||||
else
|
||||
builder.append("<empty>");
|
||||
builder.append("\n");
|
||||
builder.append("Current Value: ");
|
||||
if (change.getNewValue() != null)
|
||||
builder.append(change.getNewValue());
|
||||
else
|
||||
builder.append("<empty>");
|
||||
builder.append("\n");
|
||||
}
|
||||
builder.append("----------------------------------------\n");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public static ActivityDetail compare(Map<String, String> oldProperties, Map<String, String> newProperties,
|
||||
boolean hideNameIfOnlyOneRow) {
|
||||
String htmlVersion = compareAsHtml(oldProperties, newProperties, hideNameIfOnlyOneRow);
|
||||
String textVersion = compareAsText(oldProperties, newProperties, hideNameIfOnlyOneRow);
|
||||
return new ActivityDetail(htmlVersion, textVersion);
|
||||
}
|
||||
|
||||
public static ActivityDetail referencedFrom(CodeComment comment) {
|
||||
String url = OneDev.getInstance(UrlManager.class).urlFor(comment, null);
|
||||
String htmlVersion = String.format("<div><a href='%s'>%s</a></div>",
|
||||
url, HtmlEscape.escapeHtml5(comment.getMark().getPath()));
|
||||
String textVersion = comment.getMark().getPath() + "\n";
|
||||
|
||||
Long commentId = comment.getId();
|
||||
|
||||
return new ActivityDetail(htmlVersion, textVersion) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Component render(String componentId) {
|
||||
return new ReferencedFromCodeCommentPanel(componentId, commentId);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static ActivityDetail referencedFrom(Issue issue) {
|
||||
String url = OneDev.getInstance(UrlManager.class).urlFor(issue);
|
||||
String htmlVersion = String.format("<div><a href='%s'>[%s] %s</a></div>",
|
||||
url, issue.getFQN(), HtmlEscape.escapeHtml5(issue.getTitle()));
|
||||
String textVersion = String.format("[%s] %s\n", issue.getFQN(), issue.getTitle());
|
||||
|
||||
Long issueId = issue.getId();
|
||||
return new ActivityDetail(htmlVersion, textVersion) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Component render(String componentId) {
|
||||
return new ReferencedFromIssuePanel(componentId, issueId);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public static ActivityDetail referencedFrom(PullRequest request) {
|
||||
String url = OneDev.getInstance(UrlManager.class).urlFor(request);
|
||||
String htmlVersion = String.format("<div><a href='%s'>[%s] %s</a></div>",
|
||||
url, request.getFQN(), HtmlEscape.escapeHtml5(request.getTitle()));
|
||||
String textVersion = String.format("[%s] %s\n", request.getFQN(), request.getTitle());
|
||||
|
||||
Long requestId = request.getId();
|
||||
return new ActivityDetail(htmlVersion, textVersion) {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public Component render(String componentId) {
|
||||
return new ReferencedFromPullRequestPanel(componentId, requestId);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@ -20,6 +20,7 @@ import io.onedev.server.entitymanager.UrlManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.event.build.BuildEvent;
|
||||
import io.onedev.server.event.build.BuildUpdated;
|
||||
import io.onedev.server.markdown.MarkdownManager;
|
||||
import io.onedev.server.model.Build;
|
||||
import io.onedev.server.model.BuildQuerySetting;
|
||||
import io.onedev.server.model.Project;
|
||||
@ -27,7 +28,6 @@ import io.onedev.server.model.User;
|
||||
import io.onedev.server.model.support.NamedQuery;
|
||||
import io.onedev.server.persistence.annotation.Sessional;
|
||||
import io.onedev.server.search.entity.build.BuildQuery;
|
||||
import io.onedev.server.util.markdown.MarkdownManager;
|
||||
|
||||
@Singleton
|
||||
public class BuildNotificationManager extends AbstractNotificationManager {
|
||||
@ -64,22 +64,17 @@ public class BuildNotificationManager extends AbstractNotificationManager {
|
||||
|
||||
public void notify(BuildEvent event, Collection<String> emails) {
|
||||
Build build = event.getBuild();
|
||||
String subject = String.format("[%s] %s - %s", build.getStatus().getDisplayName(),
|
||||
build.getProject().getName(), build.getJobName());
|
||||
String subject = String.format("[Build %s] %s", build.getFQN(), build.getJobName());
|
||||
|
||||
String summary;
|
||||
if (build.getVersion() != null)
|
||||
summary = String.format("Build %s (%s)", build.getFQN(), build.getVersion());
|
||||
else
|
||||
summary = String.format("Build %s", build.getFQN());
|
||||
|
||||
summary += " is " + build.getStatus().getDisplayName().toLowerCase();
|
||||
|
||||
String summary = build.getStatus().getDisplayName();
|
||||
if (build.getVersion() != null)
|
||||
summary = build.getVersion() + " " + summary;
|
||||
|
||||
String url = urlManager.urlFor(build);
|
||||
String threadingReferences = build.getProject().getName() + "-build" + build.getNumber() + "@onedev";
|
||||
String threadingReferences = "<" + build.getProject().getName() + "-build-" + build.getNumber() + "@onedev>";
|
||||
String htmlBody = getHtmlBody(event, summary, null, url, false, null);
|
||||
String textBody = getTextBody(event, summary, null, url, false, null);
|
||||
mailManager.sendMailAsync(Lists.newArrayList(), emails, subject, htmlBody,
|
||||
mailManager.sendMailAsync(Lists.newArrayList(), Lists.newArrayList(), emails, subject, htmlBody,
|
||||
textBody, null, threadingReferences);
|
||||
}
|
||||
|
||||
|
||||
@ -10,14 +10,13 @@ import io.onedev.commons.launcher.loader.Listen;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.entitymanager.UrlManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.event.codecomment.CodeCommentCreated;
|
||||
import io.onedev.server.event.codecomment.CodeCommentEvent;
|
||||
import io.onedev.server.event.codecomment.CodeCommentReplied;
|
||||
import io.onedev.server.markdown.MarkdownManager;
|
||||
import io.onedev.server.markdown.MentionParser;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.persistence.annotation.Transactional;
|
||||
import io.onedev.server.util.markdown.MarkdownManager;
|
||||
import io.onedev.server.util.markdown.MentionParser;
|
||||
|
||||
@Singleton
|
||||
public class CodeCommentNotificationManager extends AbstractNotificationManager {
|
||||
@ -41,11 +40,11 @@ public class CodeCommentNotificationManager extends AbstractNotificationManager
|
||||
@Listen
|
||||
public void on(CodeCommentEvent event) {
|
||||
if (event.getComment().getRequest() == null) {
|
||||
MarkdownAware markdownAware = (MarkdownAware) event;
|
||||
String markdown = markdownAware.getMarkdown();
|
||||
String rendered = markdownManager.render(markdown);
|
||||
String markdown = event.getMarkdown();
|
||||
String renderedMarkdown = markdownManager.render(markdown);
|
||||
String processedMarkdown = markdownManager.process(renderedMarkdown, event.getProject(), null, true);
|
||||
|
||||
for (String userName: new MentionParser().parseMentions(rendered)) {
|
||||
for (String userName: new MentionParser().parseMentions(renderedMarkdown)) {
|
||||
User user = userManager.findByName(userName);
|
||||
if (user != null) {
|
||||
String url;
|
||||
@ -57,14 +56,17 @@ public class CodeCommentNotificationManager extends AbstractNotificationManager
|
||||
url = null;
|
||||
|
||||
if (url != null) {
|
||||
String subject = "[File Comment] " + event.getComment().getMark().getPath();
|
||||
String summary = String.format("%s: %s commented on file",
|
||||
event.getProject().getName(), event.getUser().getDisplayName());
|
||||
String threadingReferences = event.getComment().getProject().getName()
|
||||
+ "-codecomment" + event.getComment().getId() + "@onedev";
|
||||
mailManager.sendMailAsync(Sets.newHashSet(user.getEmail()), Lists.newArrayList(), subject,
|
||||
getHtmlBody(event, summary, null, url, false, null),
|
||||
getTextBody(event, summary, null, url, false, null),
|
||||
String subject = String.format("[Code Comment] (Mentioned You) %s:%s",
|
||||
event.getProject().getName(), event.getComment().getMark().getPath());
|
||||
String summary = String.format("%s added code comment",
|
||||
event.getUser().getDisplayName());
|
||||
String threadingReferences = "<" + event.getComment().getProject().getName()
|
||||
+ "-codecomment-" + event.getComment().getId() + "@onedev>";
|
||||
|
||||
mailManager.sendMailAsync(Sets.newHashSet(user.getEmail()), Lists.newArrayList(),
|
||||
Lists.newArrayList(), subject,
|
||||
getHtmlBody(event, summary, processedMarkdown, url, false, null),
|
||||
getTextBody(event, summary, markdown, url, false, null),
|
||||
null, threadingReferences);
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,13 +22,13 @@ import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.entitymanager.UrlManager;
|
||||
import io.onedev.server.event.RefUpdated;
|
||||
import io.onedev.server.git.GitUtils;
|
||||
import io.onedev.server.markdown.MarkdownManager;
|
||||
import io.onedev.server.model.CommitQuerySetting;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.model.support.NamedQuery;
|
||||
import io.onedev.server.persistence.annotation.Sessional;
|
||||
import io.onedev.server.search.commit.CommitQuery;
|
||||
import io.onedev.server.util.markdown.MarkdownManager;
|
||||
|
||||
@Singleton
|
||||
public class CommitNotificationManager extends AbstractNotificationManager {
|
||||
@ -99,33 +99,30 @@ public class CommitNotificationManager extends AbstractNotificationManager {
|
||||
|
||||
RevCommit commit = project.getRevCommit(event.getNewCommitId(), false);
|
||||
if (commit != null) {
|
||||
String subject;
|
||||
|
||||
String branchName = GitUtils.ref2branch(event.getRefName());
|
||||
if (branchName != null) {
|
||||
subject = String.format("[%s] %s", branchName, commit.getShortMessage());
|
||||
} else {
|
||||
String tagName = GitUtils.ref2tag(event.getRefName());
|
||||
if (tagName != null) {
|
||||
subject = String.format("[%s] %s", tagName, commit.getShortMessage());
|
||||
} else {
|
||||
subject = String.format("[%s] %s", event.getRefName(), commit.getShortMessage());
|
||||
}
|
||||
String target = GitUtils.ref2branch(event.getRefName());
|
||||
if (target == null) {
|
||||
target = GitUtils.ref2tag(event.getRefName());
|
||||
if (target == null)
|
||||
target = event.getRefName();
|
||||
}
|
||||
|
||||
|
||||
String subject = String.format("[Commit %s:%s] (%s) %s",
|
||||
project.getName(), GitUtils.abbreviateSHA(commit.name()), target, commit.getShortMessage());
|
||||
|
||||
String url = urlManager.urlFor(project, commit);
|
||||
String summary = String.format("Commit %s:%s - Authored by %s", project.getName(),
|
||||
GitUtils.abbreviateSHA(commit.name()), commit.getAuthorIdent().getName());
|
||||
String summary = String.format("Authored by %s", commit.getAuthorIdent().getName());
|
||||
|
||||
String textMessage = GitUtils.getDetailMessage(commit);
|
||||
String htmlMessage = null;
|
||||
if (textMessage != null)
|
||||
htmlMessage = "<pre>" + HtmlEscape.escapeHtml5(textMessage) + "</pre>";
|
||||
|
||||
mailManager.sendMailAsync(Lists.newArrayList(), notifyEmails, subject,
|
||||
String threadingReferences = "<commit-" + commit.name() + "@onedev>";
|
||||
|
||||
mailManager.sendMailAsync(Lists.newArrayList(), Lists.newArrayList(), notifyEmails, subject,
|
||||
getHtmlBody(event, summary, htmlMessage, url, false, null),
|
||||
getTextBody(event, summary, textMessage, url, false, null),
|
||||
null, null);
|
||||
null, threadingReferences);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,12 +15,14 @@ import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.FolderClosedException;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.Multipart;
|
||||
@ -44,6 +46,10 @@ import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.nodes.Node;
|
||||
import org.jsoup.nodes.TextNode;
|
||||
import org.jsoup.select.NodeTraversor;
|
||||
import org.jsoup.select.NodeVisitor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -65,6 +71,7 @@ import io.onedev.server.entitymanager.PullRequestCommentManager;
|
||||
import io.onedev.server.entitymanager.PullRequestManager;
|
||||
import io.onedev.server.entitymanager.PullRequestWatchManager;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.entitymanager.UrlManager;
|
||||
import io.onedev.server.entitymanager.UserAuthorizationManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.event.entity.EntityPersisted;
|
||||
@ -81,9 +88,7 @@ import io.onedev.server.model.Role;
|
||||
import io.onedev.server.model.Setting;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.model.UserAuthorization;
|
||||
import io.onedev.server.model.support.administration.DefaultProjectDesignation;
|
||||
import io.onedev.server.model.support.administration.GlobalIssueSetting;
|
||||
import io.onedev.server.model.support.administration.IssueCreationSetting;
|
||||
import io.onedev.server.model.support.administration.MailSetting;
|
||||
import io.onedev.server.model.support.administration.ReceiveMailSetting;
|
||||
import io.onedev.server.model.support.administration.SenderAuthorization;
|
||||
@ -96,6 +101,7 @@ import io.onedev.server.security.permission.AccessProject;
|
||||
import io.onedev.server.security.permission.ProjectPermission;
|
||||
import io.onedev.server.security.permission.ReadCode;
|
||||
import io.onedev.server.util.EmailAddress;
|
||||
import io.onedev.server.util.HtmlUtils;
|
||||
import io.onedev.server.util.validation.UserNameValidator;
|
||||
|
||||
@Singleton
|
||||
@ -127,6 +133,8 @@ public class DefaultMailManager implements MailManager {
|
||||
|
||||
private final UserManager userManager;
|
||||
|
||||
private final UrlManager urlManager;
|
||||
|
||||
private volatile boolean stopping;
|
||||
|
||||
private volatile Thread thread;
|
||||
@ -137,7 +145,8 @@ public class DefaultMailManager implements MailManager {
|
||||
UserAuthorizationManager authorizationManager, IssueManager issueManager,
|
||||
IssueCommentManager issueCommentManager, IssueWatchManager issueWatchManager,
|
||||
PullRequestManager pullRequestManager, PullRequestCommentManager pullRequestCommentManager,
|
||||
PullRequestWatchManager pullRequestWatchManager, ExecutorService executorService) {
|
||||
PullRequestWatchManager pullRequestWatchManager, ExecutorService executorService,
|
||||
UrlManager urlManager) {
|
||||
this.transactionManager = transactionManager;
|
||||
this.settingManager = setingManager;
|
||||
this.userManager = userManager;
|
||||
@ -150,12 +159,13 @@ public class DefaultMailManager implements MailManager {
|
||||
this.pullRequestCommentManager = pullRequestCommentManager;
|
||||
this.pullRequestWatchManager = pullRequestWatchManager;
|
||||
this.executorService = executorService;
|
||||
this.urlManager = urlManager;
|
||||
}
|
||||
|
||||
@Sessional
|
||||
@Override
|
||||
public void sendMailAsync(Collection<String> toList, Collection<String> ccList, String subject,
|
||||
String htmlBody, String textBody, String replyAddress, String references) {
|
||||
public void sendMailAsync(Collection<String> toList, Collection<String> ccList, Collection<String> bccList,
|
||||
String subject, String htmlBody, String textBody, String replyAddress, String references) {
|
||||
transactionManager.runAfterCommit(new Runnable() {
|
||||
|
||||
@Override
|
||||
@ -165,7 +175,7 @@ public class DefaultMailManager implements MailManager {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
sendMail(toList, ccList, subject, htmlBody, textBody, replyAddress, references);
|
||||
sendMail(toList, ccList, bccList, subject, htmlBody, textBody, replyAddress, references);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error sending email (to: " + toList + ", subject: " + subject + ")", e);
|
||||
}
|
||||
@ -194,8 +204,9 @@ public class DefaultMailManager implements MailManager {
|
||||
|
||||
@Override
|
||||
public void sendMail(MailSetting mailSetting, Collection<String> toList, Collection<String> ccList,
|
||||
String subject, String htmlBody, String textBody, String replyAddress, String references) {
|
||||
if (toList.isEmpty() && ccList.isEmpty())
|
||||
Collection<String> bccList, String subject, String htmlBody, String textBody,
|
||||
String replyAddress, String references) {
|
||||
if (toList.isEmpty() && ccList.isEmpty() && bccList.isEmpty())
|
||||
return;
|
||||
|
||||
if (mailSetting == null)
|
||||
@ -232,6 +243,8 @@ public class DefaultMailManager implements MailManager {
|
||||
email.addTo(address);
|
||||
for (String address: ccList)
|
||||
email.addCc(address);
|
||||
for (String address: bccList)
|
||||
email.addBcc(address);
|
||||
|
||||
email.setHostName(mailSetting.getSmtpHost());
|
||||
email.setSmtpPort(mailSetting.getSmtpPort());
|
||||
@ -254,9 +267,9 @@ public class DefaultMailManager implements MailManager {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMail(Collection<String> toList, Collection<String> ccList, String subject,
|
||||
String htmlBody, String textBody, String replyAddress, String references) {
|
||||
sendMail(settingManager.getMailSetting(), toList, ccList, subject, htmlBody,
|
||||
public void sendMail(Collection<String> toList, Collection<String> ccList, Collection<String> bccList,
|
||||
String subject, String htmlBody, String textBody, String replyAddress, String references) {
|
||||
sendMail(settingManager.getMailSetting(), toList, ccList, bccList, subject, htmlBody,
|
||||
textBody, replyAddress, references);
|
||||
}
|
||||
|
||||
@ -305,10 +318,13 @@ public class DefaultMailManager implements MailManager {
|
||||
|
||||
User user = userManager.findByEmail(from.getAddress());
|
||||
|
||||
SenderAuthorization authorization = null;
|
||||
String designatedProject = null;
|
||||
ServiceDeskSetting serviceDeskSetting = settingManager.getServiceDeskSetting();
|
||||
|
||||
SenderAuthorization authorization = serviceDeskSetting.getSenderAuthorization(from.getAddress());
|
||||
DefaultProjectDesignation designation = serviceDeskSetting.getDefaultProjectDesignation(from.getAddress());
|
||||
if (serviceDeskSetting != null) {
|
||||
authorization = serviceDeskSetting.getSenderAuthorization(from.getAddress());
|
||||
designatedProject = serviceDeskSetting.getDesignatedProject(from.getAddress());
|
||||
}
|
||||
EmailAddress systemAddress = EmailAddress.parse(mailSetting.getEmailAddress());
|
||||
|
||||
Collection<Issue> issues = new ArrayList<>();
|
||||
@ -327,18 +343,19 @@ public class DefaultMailManager implements MailManager {
|
||||
for (InternetAddress receiver: receivers) {
|
||||
EmailAddress receiverAddress = EmailAddress.parse(receiver.getAddress());
|
||||
if (receiverAddress.toString().equals(systemAddress.toString())) {
|
||||
if (designation == null)
|
||||
throw new ExplicitException("No default project for sender: " + from.getAddress());
|
||||
String projectName = designation.getDefaultProject();
|
||||
Project project = projectManager.find(projectName);
|
||||
if (project == null) {
|
||||
String errorMessage = String.format(
|
||||
"Default project does not exist (sender: %s, project: %s)",
|
||||
from.getAddress(), projectName);
|
||||
throw new ExplicitException(errorMessage);
|
||||
if (serviceDeskSetting != null) {
|
||||
Project project = projectManager.find(designatedProject);
|
||||
if (project == null) {
|
||||
String errorMessage = String.format(
|
||||
"Sender project does not exist (sender: %s, project: %s)",
|
||||
from.getAddress(), designatedProject);
|
||||
throw new ExplicitException(errorMessage);
|
||||
}
|
||||
checkPermission(from, project, new AccessProject(), user, authorization);
|
||||
issues.add(openIssue(message, project, from, user, authorization));
|
||||
} else {
|
||||
throw new ExplicitException("Unable to create issue from email as service desk is not enabled");
|
||||
}
|
||||
checkPermission(from, project, new AccessProject(), user, authorization);
|
||||
issues.add(openIssue(message, project, from, user, authorization));
|
||||
} else if (receiverAddress.getDomain().equals(systemAddress.getDomain())
|
||||
&& receiverAddress.getPrefix().startsWith(systemAddress.getPrefix() + "+")) {
|
||||
String subAddress = receiverAddress.getPrefix().substring(systemAddress.getPrefix().length()+1);
|
||||
@ -351,8 +368,12 @@ public class DefaultMailManager implements MailManager {
|
||||
|
||||
String remaining = StringUtils.substringAfter(subAddress, "~");
|
||||
if (remaining.length() == 0) {
|
||||
checkPermission(from, project, new AccessProject(), user, authorization);
|
||||
issues.add(openIssue(message, project, from, user, authorization));
|
||||
if (serviceDeskSetting != null) {
|
||||
checkPermission(from, project, new AccessProject(), user, authorization);
|
||||
issues.add(openIssue(message, project, from, user, authorization));
|
||||
} else {
|
||||
throw new ExplicitException("Unable to create issue from email as service desk is not enabled");
|
||||
}
|
||||
} else if (remaining.startsWith("issue")) {
|
||||
remaining = remaining.substring("issue".length());
|
||||
Long issueNumber;
|
||||
@ -375,7 +396,8 @@ public class DefaultMailManager implements MailManager {
|
||||
+ "However if you subscribed to certain issue queries, you may still get notifications of newly "
|
||||
+ "created issues matching those queries. In this case, you will need to login to your account "
|
||||
+ "and unsubscribe those queries.";
|
||||
sendMailAsync(Lists.newArrayList(from.getAddress()), Lists.newArrayList(), subject, body, body, null, getMessageId(message));
|
||||
sendMailAsync(Lists.newArrayList(from.getAddress()), Lists.newArrayList(), Lists.newArrayList(),
|
||||
subject, body, body, null, getMessageId(message));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -406,7 +428,8 @@ public class DefaultMailManager implements MailManager {
|
||||
+ " unless mentioned. However if you subscribed to certain pull request queries, you may still "
|
||||
+ "get notifications of newly submitted pull request matching those queries. In this case, you "
|
||||
+ "will need to login to your account and unsubscribe those queries.";
|
||||
sendMailAsync(Lists.newArrayList(from.getAddress()), Lists.newArrayList(), subject, body, body, null, getMessageId(message));
|
||||
sendMailAsync(Lists.newArrayList(from.getAddress()), Lists.newArrayList(), Lists.newArrayList(),
|
||||
subject, body, body, null, getMessageId(message));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -425,7 +448,8 @@ public class DefaultMailManager implements MailManager {
|
||||
for (Issue issue: issues) {
|
||||
for (InternetAddress each: involved) {
|
||||
user = userManager.findByEmail(each.getAddress());
|
||||
authorization = serviceDeskSetting.getSenderAuthorization(each.getAddress());
|
||||
if (serviceDeskSetting != null)
|
||||
authorization = serviceDeskSetting.getSenderAuthorization(each.getAddress());
|
||||
try {
|
||||
checkPermission(each, issue.getProject(), new AccessProject(), user, authorization);
|
||||
if (user == null)
|
||||
@ -439,7 +463,8 @@ public class DefaultMailManager implements MailManager {
|
||||
for (PullRequest pullRequest: pullRequests) {
|
||||
for (InternetAddress each: involved) {
|
||||
user = userManager.findByEmail(each.getAddress());
|
||||
authorization = serviceDeskSetting.getSenderAuthorization(each.getAddress());
|
||||
if (serviceDeskSetting != null)
|
||||
authorization = serviceDeskSetting.getSenderAuthorization(each.getAddress());
|
||||
try {
|
||||
checkPermission(each, pullRequest.getProject(), new ReadCode(), user, authorization);
|
||||
if (user == null)
|
||||
@ -456,6 +481,73 @@ public class DefaultMailManager implements MailManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void removeNodesAfter(Node node) {
|
||||
Node current = node;
|
||||
while (current != null) {
|
||||
Node nextSibling = current.nextSibling();
|
||||
while (nextSibling != null) {
|
||||
Node temp = nextSibling.nextSibling();
|
||||
nextSibling.remove();
|
||||
nextSibling = temp;
|
||||
}
|
||||
current = current.parent();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String stripQuotation(String content) {
|
||||
String quotedSender = settingManager.getMailSetting().getEmailAddress();
|
||||
Pattern pattern = Pattern.compile("(^|\\W)" + quotedSender.replace(".", "\\.") + "($|\\W)");
|
||||
|
||||
Document document = HtmlUtils.parse(content);
|
||||
Element quotedSenderElement = null;
|
||||
for (Element element: document.getElementsContainingOwnText(quotedSender)) {
|
||||
if (pattern.matcher(element.text()).find()) {
|
||||
quotedSenderElement = element;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (quotedSenderElement != null) {
|
||||
Element quotedSenderBlockElement = quotedSenderElement.parent();
|
||||
while (quotedSenderBlockElement != null
|
||||
&& !quotedSenderBlockElement.tagName().equals("div")
|
||||
&& !quotedSenderBlockElement.tagName().equals("p")) {
|
||||
quotedSenderBlockElement = quotedSenderBlockElement.parent();
|
||||
}
|
||||
if (quotedSenderBlockElement != null) {
|
||||
removeNodesAfter(quotedSenderBlockElement);
|
||||
quotedSenderBlockElement.remove();
|
||||
}
|
||||
}
|
||||
|
||||
AtomicReference<Node> lastContentNodeRef = new AtomicReference<>(null);
|
||||
|
||||
new NodeTraversor(new NodeVisitor() {
|
||||
|
||||
@Override
|
||||
public void tail(Node node, int depth) {
|
||||
if (node instanceof Element && ((Element) node).tagName().equals("img")
|
||||
|| node instanceof TextNode && StringUtils.isNotBlank(((TextNode) node).getWholeText())) {
|
||||
lastContentNodeRef.set(node);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void head(Node node, int depth) {
|
||||
|
||||
}
|
||||
|
||||
}).traverse(document);
|
||||
|
||||
Node lastContentNode = lastContentNodeRef.get();
|
||||
if (lastContentNode != null) {
|
||||
removeNodesAfter(lastContentNode);
|
||||
return document.body().html();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void addComment(Issue issue, Message message, InternetAddress author,
|
||||
Collection<String> receiverEmailAddresses, @Nullable User user,
|
||||
@Nullable SenderAuthorization authorization) throws IOException, MessagingException {
|
||||
@ -464,8 +556,8 @@ public class DefaultMailManager implements MailManager {
|
||||
if (user == null)
|
||||
user = createUserIfNotExist(author, issue.getProject(), authorization.getAuthorizedRole());
|
||||
comment.setUser(user);
|
||||
String content = readText(issue.getProject(), issue.getUUID(), message);
|
||||
if (StringUtils.isNotBlank(content)) {
|
||||
String content = stripQuotation(readText(issue.getProject(), issue.getUUID(), message));
|
||||
if (content != null) {
|
||||
comment.setContent(content);
|
||||
issueCommentManager.save(comment, receiverEmailAddresses);
|
||||
}
|
||||
@ -479,8 +571,8 @@ public class DefaultMailManager implements MailManager {
|
||||
if (user == null)
|
||||
user = createUserIfNotExist(author, pullRequest.getProject(), authorization.getAuthorizedRole());
|
||||
comment.setUser(user);
|
||||
String content = readText(pullRequest.getProject(), pullRequest.getUUID(), message);
|
||||
if (StringUtils.isNotBlank(content)) {
|
||||
String content = stripQuotation(readText(pullRequest.getProject(), pullRequest.getUUID(), message));
|
||||
if (content != null) {
|
||||
comment.setContent(content);
|
||||
pullRequestCommentManager.save(comment, receiverEmailAddresses);
|
||||
}
|
||||
@ -519,15 +611,24 @@ public class DefaultMailManager implements MailManager {
|
||||
GlobalIssueSetting issueSetting = settingManager.getIssueSetting();
|
||||
issue.setState(issueSetting.getInitialStateSpec().getName());
|
||||
|
||||
IssueCreationSetting issueCreationSetting = settingManager.getServiceDeskSetting()
|
||||
List<FieldSupply> issueFields = settingManager.getServiceDeskSetting()
|
||||
.getIssueCreationSetting(submitter.getAddress(), project);
|
||||
for (FieldSupply supply: issueCreationSetting.getIssueFields()) {
|
||||
for (FieldSupply supply: issueFields) {
|
||||
Object fieldValue = issueSetting.getFieldSpec(supply.getName())
|
||||
.convertToObject(supply.getValueProvider().getValue());
|
||||
issue.setFieldValue(supply.getName(), fieldValue);
|
||||
}
|
||||
|
||||
issueManager.open(issue);
|
||||
|
||||
String htmlBody = String.format("Issue <a href='%s'>%s</a> is created. You may reply this email to add more comments",
|
||||
urlManager.urlFor(issue), issue.getFQN());
|
||||
String textBody = String.format("Issue %s is created. You may reply this email to add more comments",
|
||||
issue.getFQN());
|
||||
|
||||
sendMailAsync(Lists.newArrayList(submitter.getAddress()), Lists.newArrayList(), Lists.newArrayList(),
|
||||
"Re: " + issue.getTitle(), htmlBody, textBody, getReplyAddress(issue),
|
||||
issue.getEffectiveThreadingReference());
|
||||
return issue;
|
||||
}
|
||||
|
||||
@ -538,7 +639,7 @@ public class DefaultMailManager implements MailManager {
|
||||
user.setName(UserNameValidator.suggestUserName(EmailAddress.parse(address.getAddress()).getPrefix()));
|
||||
user.setEmail(address.getAddress());
|
||||
user.setFullName(address.getPersonal());
|
||||
user.setPassword("12345");
|
||||
user.setPassword("impossible password");
|
||||
userManager.save(user);
|
||||
}
|
||||
|
||||
@ -712,8 +813,13 @@ public class DefaultMailManager implements MailManager {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
while (!stopping.get())
|
||||
inboxRef.get().idle();
|
||||
while (!stopping.get()) {
|
||||
try {
|
||||
inboxRef.get().idle();
|
||||
} catch (FolderClosedException e) {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
exception.set(ExceptionUtils.unchecked(e));
|
||||
} finally {
|
||||
|
||||
@ -5,7 +5,6 @@ import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -19,28 +18,23 @@ import io.onedev.server.entitymanager.IssueWatchManager;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.entitymanager.UrlManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.entityreference.ReferencedFromAware;
|
||||
import io.onedev.server.event.issue.IssueChangeEvent;
|
||||
import io.onedev.server.event.issue.IssueCommented;
|
||||
import io.onedev.server.event.issue.IssueEvent;
|
||||
import io.onedev.server.infomanager.UserInfoManager;
|
||||
import io.onedev.server.markdown.MarkdownManager;
|
||||
import io.onedev.server.markdown.MentionParser;
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.Issue;
|
||||
import io.onedev.server.model.IssueWatch;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.model.support.NamedQuery;
|
||||
import io.onedev.server.model.support.QuerySetting;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueChangeData;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueDescriptionChangeData;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueReferencedFromCodeCommentData;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueReferencedFromIssueData;
|
||||
import io.onedev.server.model.support.issue.changedata.IssueReferencedFromPullRequestData;
|
||||
import io.onedev.server.persistence.annotation.Transactional;
|
||||
import io.onedev.server.search.entity.EntityQuery;
|
||||
import io.onedev.server.search.entity.QueryWatchBuilder;
|
||||
import io.onedev.server.search.entity.issue.IssueQuery;
|
||||
import io.onedev.server.util.markdown.MarkdownManager;
|
||||
import io.onedev.server.util.markdown.MentionParser;
|
||||
|
||||
@Singleton
|
||||
public class IssueNotificationManager extends AbstractNotificationManager {
|
||||
@ -73,8 +67,6 @@ public class IssueNotificationManager extends AbstractNotificationManager {
|
||||
Issue issue = event.getIssue();
|
||||
User user = event.getUser();
|
||||
|
||||
String subject = String.format("[%s] %s", issue.getState(), issue.getTitle());
|
||||
|
||||
String url;
|
||||
if (event instanceof IssueCommented)
|
||||
url = urlManager.urlFor(((IssueCommented)event).getComment());
|
||||
@ -82,7 +74,13 @@ public class IssueNotificationManager extends AbstractNotificationManager {
|
||||
url = urlManager.urlFor(((IssueChangeEvent)event).getChange());
|
||||
else
|
||||
url = urlManager.urlFor(issue);
|
||||
|
||||
|
||||
String summary = "[" + issue.getState() + "] ";
|
||||
if (user != null)
|
||||
summary = summary + user.getDisplayName() + " " + event.getActivity();
|
||||
else
|
||||
summary = summary + event.getActivity();
|
||||
|
||||
for (Map.Entry<User, Boolean> entry: new QueryWatchBuilder<Issue>() {
|
||||
|
||||
@Override
|
||||
@ -141,113 +139,102 @@ public class IssueNotificationManager extends AbstractNotificationManager {
|
||||
if (!user.isSystem())
|
||||
issueWatchManager.watch(issue, user, true);
|
||||
}
|
||||
|
||||
|
||||
Map<String, Group> newGroups = event.getNewGroups();
|
||||
Map<String, Collection<User>> newUsers = event.getNewUsers();
|
||||
|
||||
String replyAddress = mailManager.getReplyAddress(issue);
|
||||
boolean replyable = replyAddress != null;
|
||||
String threadingReferences = issue.getThreadingReference();
|
||||
if (threadingReferences == null)
|
||||
threadingReferences = "<" + issue.getUUID() + "@onedev>";
|
||||
for (Map.Entry<String, Group> entry: newGroups.entrySet()) {
|
||||
String summary = String.format("Issue %s: %s: You", issue.getFQN(), entry.getKey());
|
||||
Set<String> emails = entry.getValue().getMembers()
|
||||
.stream()
|
||||
.filter(it->!it.equals(user))
|
||||
.map(it->it.getEmail())
|
||||
.collect(Collectors.toSet());
|
||||
mailManager.sendMailAsync(emails, Lists.newArrayList(), subject,
|
||||
getHtmlBody(event, summary, null, url, replyable, null),
|
||||
getTextBody(event, summary, null, url, replyable, null),
|
||||
replyAddress, threadingReferences);
|
||||
String subject = String.format("[Issue %s] (%s: You) %s", issue.getFQN(), entry.getKey(), issue.getTitle());
|
||||
String threadingReferences = String.format("<you-in-field-%s-%s@onedev>", entry.getKey(), issue.getUUID());
|
||||
for (User member: entry.getValue().getMembers()) {
|
||||
if (!member.equals(user)) {
|
||||
mailManager.sendMailAsync(Sets.newHashSet(member.getEmail()),
|
||||
Lists.newArrayList(), Lists.newArrayList(), subject,
|
||||
getHtmlBody(event, summary, event.getHtmlBody(), url, replyable, null),
|
||||
getTextBody(event, summary, event.getTextBody(), url, replyable, null),
|
||||
replyAddress, threadingReferences);
|
||||
}
|
||||
}
|
||||
|
||||
for (User member: entry.getValue().getMembers())
|
||||
issueWatchManager.watch(issue, member, true);
|
||||
|
||||
notifiedUsers.addAll(entry.getValue().getMembers());
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Collection<User>> entry: newUsers.entrySet()) {
|
||||
String summary = String.format("Issue %s: %s: You", issue.getFQN(), entry.getKey());
|
||||
Set<String> emails = entry.getValue()
|
||||
.stream()
|
||||
.filter(it->!it.equals(user))
|
||||
.map(it->it.getEmail())
|
||||
.collect(Collectors.toSet());
|
||||
mailManager.sendMailAsync(emails, Lists.newArrayList(), subject,
|
||||
getHtmlBody(event, summary, null, url, replyable, null),
|
||||
getTextBody(event, summary, null, url, replyable, null),
|
||||
replyAddress, threadingReferences);
|
||||
String subject = String.format("[Issue %s] (%s: You) %s", issue.getFQN(), entry.getKey(), issue.getTitle());
|
||||
String threadingReferences = String.format("<you-in-field-%s-%s@onedev>", entry.getKey(), issue.getUUID());
|
||||
for (User member: entry.getValue()) {
|
||||
if (!member.equals(user)) {
|
||||
mailManager.sendMailAsync(Sets.newHashSet(member.getEmail()),
|
||||
Lists.newArrayList(), Lists.newArrayList(), subject,
|
||||
getHtmlBody(event, summary, event.getHtmlBody(), url, replyable, null),
|
||||
getTextBody(event, summary, event.getTextBody(), url, replyable, null),
|
||||
replyAddress, threadingReferences);
|
||||
}
|
||||
}
|
||||
|
||||
for (User each: entry.getValue())
|
||||
issueWatchManager.watch(issue, each, true);
|
||||
notifiedUsers.addAll(entry.getValue());
|
||||
}
|
||||
|
||||
Collection<User> mentionedUsers = new HashSet<>();
|
||||
if (event instanceof MarkdownAware) {
|
||||
MarkdownAware markdownAware = (MarkdownAware) event;
|
||||
String markdown = markdownAware.getMarkdown();
|
||||
if (markdown != null) {
|
||||
String rendered = markdownManager.render(markdown);
|
||||
|
||||
for (String userName: new MentionParser().parseMentions(rendered)) {
|
||||
User mentionedUser = userManager.findByName(userName);
|
||||
if (mentionedUser != null && notifiedUsers.add(mentionedUser)) {
|
||||
issueWatchManager.watch(issue, mentionedUser, true);
|
||||
mentionedUsers.add(mentionedUser);
|
||||
Collection<String> notifiedEmailAddresses;
|
||||
if (event instanceof IssueCommented)
|
||||
notifiedEmailAddresses = ((IssueCommented) event).getNotifiedEmailAddresses();
|
||||
else
|
||||
notifiedEmailAddresses = new ArrayList<>();
|
||||
|
||||
if (event.getRenderedMarkdown() != null) {
|
||||
for (String userName: new MentionParser().parseMentions(event.getRenderedMarkdown())) {
|
||||
User mentionedUser = userManager.findByName(userName);
|
||||
if (mentionedUser != null) {
|
||||
issueWatchManager.watch(issue, mentionedUser, true);
|
||||
if (!notifiedEmailAddresses.stream().anyMatch(mentionedUser.getEmails()::contains)) {
|
||||
String subject = String.format("[Issue %s] (Mentioned You) %s", issue.getFQN(), issue.getTitle());
|
||||
String threadingReferences = String.format("<mentioned-%s@onedev>", issue.getUUID());
|
||||
|
||||
mailManager.sendMailAsync(Sets.newHashSet(mentionedUser.getEmail()),
|
||||
Sets.newHashSet(), Sets.newHashSet(), subject,
|
||||
getHtmlBody(event, summary, event.getHtmlBody(), url, replyable, null),
|
||||
getTextBody(event, summary, event.getTextBody(), url, replyable, null),
|
||||
replyAddress, threadingReferences);
|
||||
notifiedUsers.add(mentionedUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean notifyWatchers = false;
|
||||
if (event instanceof IssueChangeEvent) {
|
||||
IssueChangeData changeData = ((IssueChangeEvent) event).getChange().getData();
|
||||
if (!(changeData instanceof IssueReferencedFromCodeCommentData
|
||||
|| changeData instanceof IssueReferencedFromIssueData
|
||||
|| changeData instanceof IssueReferencedFromPullRequestData
|
||||
|| changeData instanceof IssueDescriptionChangeData)) {
|
||||
notifyWatchers = true;
|
||||
}
|
||||
} else {
|
||||
notifyWatchers = true;
|
||||
}
|
||||
|
||||
if (!mentionedUsers.isEmpty() || notifyWatchers) {
|
||||
Collection<User> ccUsers = new HashSet<>();
|
||||
|
||||
if (!(event instanceof IssueChangeEvent)
|
||||
|| !(((IssueChangeEvent) event).getChange().getData() instanceof ReferencedFromAware)) {
|
||||
Collection<User> bccUsers = new HashSet<>();
|
||||
|
||||
Collection<String> notifiedEmailAddresses;
|
||||
if (event instanceof IssueCommented)
|
||||
notifiedEmailAddresses = ((IssueCommented) event).getNotifiedEmailAddresses();
|
||||
else
|
||||
notifiedEmailAddresses = new ArrayList<>();
|
||||
for (IssueWatch watch: issue.getWatches()) {
|
||||
Date visitDate = userInfoManager.getIssueVisitDate(watch.getUser(), issue);
|
||||
if (watch.isWatching()
|
||||
&& (visitDate == null || visitDate.before(event.getDate()))
|
||||
&& !notifiedUsers.contains(watch.getUser())
|
||||
&& !notifiedEmailAddresses.stream().anyMatch(watch.getUser().getEmails()::contains)) {
|
||||
ccUsers.add(watch.getUser());
|
||||
bccUsers.add(watch.getUser());
|
||||
}
|
||||
}
|
||||
|
||||
if (!mentionedUsers.isEmpty() || !ccUsers.isEmpty()) {
|
||||
String summary;
|
||||
if (user != null)
|
||||
summary = String.format("Issue %s: %s %s", issue.getFQN(), user.getDisplayName(), event.getActivity());
|
||||
else
|
||||
summary = "Issue " + issue.getFQN() + ": " + event.getActivity();
|
||||
|
||||
|
||||
if (!bccUsers.isEmpty()) {
|
||||
String subject = String.format("[Issue %s] (Updated) %s", issue.getFQN(), issue.getTitle());
|
||||
|
||||
Unsubscribable unsubscribable = new Unsubscribable(mailManager.getUnsubscribeAddress(issue));
|
||||
String htmlBody = getHtmlBody(event, summary, null, url, replyable, unsubscribable);
|
||||
String textBody = getTextBody(event, summary, null, url, replyable, unsubscribable);
|
||||
|
||||
mailManager.sendMailAsync(
|
||||
mentionedUsers.stream().map(User::getEmail).collect(Collectors.toList()),
|
||||
ccUsers.stream().map(User::getEmail).collect(Collectors.toList()),
|
||||
String htmlBody = getHtmlBody(event, summary, event.getHtmlBody(), url, replyable, unsubscribable);
|
||||
String textBody = getTextBody(event, summary, event.getTextBody(), url, replyable, unsubscribable);
|
||||
|
||||
String threadingReferences = issue.getEffectiveThreadingReference();
|
||||
mailManager.sendMailAsync(Sets.newHashSet(), Sets.newHashSet(),
|
||||
bccUsers.stream().map(User::getEmail).collect(Collectors.toList()),
|
||||
subject, htmlBody, textBody, replyAddress, threadingReferences);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -12,16 +12,18 @@ public interface MailManager {
|
||||
|
||||
public static final String TEST_SUB_ADDRESSING = "test-sub-addressing";
|
||||
|
||||
void sendMail(Collection<String> toList, Collection<String> ccList, String subject,
|
||||
String htmlBody, String textBody, @Nullable String replyAddress, @Nullable String references);
|
||||
void sendMail(Collection<String> toList, Collection<String> ccList,
|
||||
Collection<String> bccList, String subject, String htmlBody,
|
||||
String textBody, @Nullable String replyAddress, @Nullable String references);
|
||||
|
||||
void sendMail(MailSetting mailSetting, Collection<String> toList, Collection<String> ccList,
|
||||
Collection<String> bccList, String subject, String htmlBody, String textBody,
|
||||
@Nullable String replyAddress, @Nullable String references);
|
||||
|
||||
void sendMailAsync(Collection<String> toList, Collection<String> ccList, Collection<String> bccList,
|
||||
String subject, String htmlBody, String textBody, @Nullable String replyAddress,
|
||||
@Nullable String references);
|
||||
|
||||
void sendMailAsync(Collection<String> toList, Collection<String> ccList, String subject,
|
||||
String htmlBody, String textBody, @Nullable String replyAddress, @Nullable String references);
|
||||
|
||||
@Nullable
|
||||
String getReplyAddress(Issue issue);
|
||||
|
||||
|
||||
@ -10,6 +10,8 @@ import java.util.stream.Collectors;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.apache.commons.text.WordUtils;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
@ -18,7 +20,6 @@ import io.onedev.server.entitymanager.PullRequestWatchManager;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.entitymanager.UrlManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.event.MarkdownAware;
|
||||
import io.onedev.server.event.entity.EntityPersisted;
|
||||
import io.onedev.server.event.pullrequest.PullRequestBuildEvent;
|
||||
import io.onedev.server.event.pullrequest.PullRequestChangeEvent;
|
||||
@ -30,6 +31,8 @@ import io.onedev.server.event.pullrequest.PullRequestMergePreviewCalculated;
|
||||
import io.onedev.server.event.pullrequest.PullRequestOpened;
|
||||
import io.onedev.server.event.pullrequest.PullRequestUpdated;
|
||||
import io.onedev.server.infomanager.UserInfoManager;
|
||||
import io.onedev.server.markdown.MarkdownManager;
|
||||
import io.onedev.server.markdown.MentionParser;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
import io.onedev.server.model.PullRequestAssignment;
|
||||
import io.onedev.server.model.PullRequestReview;
|
||||
@ -48,8 +51,6 @@ import io.onedev.server.search.entity.EntityQuery;
|
||||
import io.onedev.server.search.entity.QueryWatchBuilder;
|
||||
import io.onedev.server.search.entity.pullrequest.PullRequestQuery;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import io.onedev.server.util.markdown.MarkdownManager;
|
||||
import io.onedev.server.util.markdown.MentionParser;
|
||||
|
||||
@Singleton
|
||||
public class PullRequestNotificationManager extends AbstractNotificationManager {
|
||||
@ -76,23 +77,12 @@ public class PullRequestNotificationManager extends AbstractNotificationManager
|
||||
this.userManager = userManager;
|
||||
}
|
||||
|
||||
private String getSubject(PullRequest request) {
|
||||
String state;
|
||||
if (request.isMerged())
|
||||
state = "Merged";
|
||||
else if (request.isDiscarded())
|
||||
state = "Discarded";
|
||||
else
|
||||
state = "Open";
|
||||
return String.format("[%s] %s", state, request.getTitle());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Listen
|
||||
public void on(PullRequestEvent event) {
|
||||
PullRequest request = event.getRequest();
|
||||
User user = event.getUser();
|
||||
|
||||
|
||||
String url;
|
||||
if (event instanceof PullRequestCommented)
|
||||
url = urlManager.urlFor(((PullRequestCommented)event).getComment());
|
||||
@ -178,6 +168,14 @@ public class PullRequestNotificationManager extends AbstractNotificationManager
|
||||
}
|
||||
}
|
||||
|
||||
String summary = "[" + request.getStatusName() + "] ";
|
||||
if (user != null)
|
||||
summary = summary + user.getDisplayName() + " " + event.getActivity();
|
||||
else if (committer != null)
|
||||
summary = summary + committer.getDisplayName() + " " + event.getActivity();
|
||||
else
|
||||
summary = summary + event.getActivity();
|
||||
|
||||
if (event instanceof PullRequestOpened) {
|
||||
for (PullRequestReview review: request.getReviews()) {
|
||||
if (review.getResult() == null) {
|
||||
@ -189,43 +187,49 @@ public class PullRequestNotificationManager extends AbstractNotificationManager
|
||||
|
||||
String replyAddress = mailManager.getReplyAddress(request);
|
||||
boolean replyable = replyAddress != null;
|
||||
String threadingReferences = getThreadingReferences(request);
|
||||
if (event instanceof PullRequestChangeEvent
|
||||
&& request.getSubmitter() != null
|
||||
&& !notifiedUsers.contains(request.getSubmitter())) {
|
||||
PullRequestChangeEvent changeEvent = (PullRequestChangeEvent) event;
|
||||
PullRequestChangeData changeData = changeEvent.getChange().getData();
|
||||
String summary = null;
|
||||
if (changeData instanceof PullRequestApproveData)
|
||||
summary = user.getDisplayName() + " approved";
|
||||
else if (changeData instanceof PullRequestRequestedForChangesData)
|
||||
summary = user.getDisplayName() + " requested changes";
|
||||
else if (changeData instanceof PullRequestDiscardData)
|
||||
summary = user.getDisplayName() + " discarded";
|
||||
if (summary != null) {
|
||||
summary = "Pull request " + request.getFQN() + ": " + summary;
|
||||
if (changeData instanceof PullRequestApproveData
|
||||
|| changeData instanceof PullRequestRequestedForChangesData
|
||||
|| changeData instanceof PullRequestDiscardData) {
|
||||
String subject = String.format("[Pull Request %s] (%s) %s", request.getFQN(),
|
||||
WordUtils.capitalize(changeData.getActivity()), request.getTitle());
|
||||
String threadingReferences = String.format("<%s-%s@onedev>",
|
||||
changeData.getActivity().replace(' ', '-'), request.getUUID());
|
||||
mailManager.sendMailAsync(Lists.newArrayList(request.getSubmitter().getEmail()),
|
||||
Lists.newArrayList(), getSubject(request),
|
||||
getHtmlBody(event, summary, null, url, replyable, null),
|
||||
getTextBody(event, summary, null, url, replyable, null),
|
||||
Lists.newArrayList(), Lists.newArrayList(), subject,
|
||||
getHtmlBody(event, summary, event.getHtmlBody(), url, replyable, null),
|
||||
getTextBody(event, summary, event.getTextBody(), url, replyable, null),
|
||||
replyAddress, threadingReferences);
|
||||
notifiedUsers.add(request.getSubmitter());
|
||||
}
|
||||
}
|
||||
|
||||
Collection<User> mentionedUsers = new HashSet<>();
|
||||
if (event instanceof MarkdownAware) {
|
||||
MarkdownAware markdownAware = (MarkdownAware) event;
|
||||
String markdown = markdownAware.getMarkdown();
|
||||
if (markdown != null) {
|
||||
String rendered = markdownManager.render(markdown);
|
||||
|
||||
for (String userName: new MentionParser().parseMentions(rendered)) {
|
||||
User mentionedUser = userManager.findByName(userName);
|
||||
if (mentionedUser != null && notifiedUsers.add(mentionedUser)) {
|
||||
pullRequestWatchManager.watch(request, mentionedUser, true);
|
||||
mentionedUsers.add(mentionedUser);
|
||||
}
|
||||
Collection<String> notifiedEmailAddresses;
|
||||
if (event instanceof PullRequestCommented)
|
||||
notifiedEmailAddresses = ((PullRequestCommented) event).getNotifiedEmailAddresses();
|
||||
else
|
||||
notifiedEmailAddresses = new ArrayList<>();
|
||||
|
||||
if (event.getRenderedMarkdown() != null) {
|
||||
for (String userName: new MentionParser().parseMentions(event.getRenderedMarkdown())) {
|
||||
User mentionedUser = userManager.findByName(userName);
|
||||
if (mentionedUser != null) {
|
||||
pullRequestWatchManager.watch(request, mentionedUser, true);
|
||||
if (!notifiedEmailAddresses.stream().anyMatch(mentionedUser.getEmails()::contains)) {
|
||||
String subject = String.format("[Pull Request %s] (Mentioned You) %s", request.getFQN(), request.getTitle());
|
||||
String threadingReferences = String.format("<mentioned-%s@onedev>", request.getUUID());
|
||||
|
||||
mailManager.sendMailAsync(Sets.newHashSet(mentionedUser.getEmail()),
|
||||
Sets.newHashSet(), Sets.newHashSet(), subject,
|
||||
getHtmlBody(event, summary, event.getHtmlBody(), url, replyable, null),
|
||||
getTextBody(event, summary, event.getTextBody(), url, replyable, null),
|
||||
replyAddress, threadingReferences);
|
||||
notifiedUsers.add(mentionedUser);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -244,14 +248,9 @@ public class PullRequestNotificationManager extends AbstractNotificationManager
|
||||
notifyWatchers = true;
|
||||
}
|
||||
|
||||
if (!mentionedUsers.isEmpty() || notifyWatchers) {
|
||||
Collection<User> ccUsers = new HashSet<>();
|
||||
if (notifyWatchers) {
|
||||
Collection<User> bccUsers = new HashSet<>();
|
||||
|
||||
Collection<String> notifiedEmailAddresses;
|
||||
if (event instanceof PullRequestCommented)
|
||||
notifiedEmailAddresses = ((PullRequestCommented) event).getNotifiedEmailAddresses();
|
||||
else
|
||||
notifiedEmailAddresses = new ArrayList<>();
|
||||
for (PullRequestWatch watch: request.getWatches()) {
|
||||
Date visitDate = userInfoManager.getPullRequestVisitDate(watch.getUser(), request);
|
||||
if (watch.isWatching()
|
||||
@ -259,34 +258,24 @@ public class PullRequestNotificationManager extends AbstractNotificationManager
|
||||
&& (!(event instanceof PullRequestUpdated) || !watch.getUser().equals(request.getSubmitter()))
|
||||
&& !notifiedUsers.contains(watch.getUser())
|
||||
&& !notifiedEmailAddresses.stream().anyMatch(watch.getUser().getEmails()::contains)) {
|
||||
ccUsers.add(watch.getUser());
|
||||
bccUsers.add(watch.getUser());
|
||||
}
|
||||
}
|
||||
|
||||
if (!mentionedUsers.isEmpty() || !ccUsers.isEmpty()) {
|
||||
String summary;
|
||||
if (user != null)
|
||||
summary = String.format("Pull request %s: %s %s", request.getFQN(), user.getDisplayName(), event.getActivity());
|
||||
else if (committer != null)
|
||||
summary = String.format("Pull request %s: %s added commits", request.getFQN(), committer.getDisplayName());
|
||||
else
|
||||
summary = "Pull request " + request.getFQN() + ": " + event.getActivity();
|
||||
|
||||
if (!bccUsers.isEmpty()) {
|
||||
String subject = String.format("[Pull Request %s] (Updated) %s", request.getFQN(), request.getTitle());
|
||||
String threadingReferences = "<" + request.getUUID() + "@onedev>";
|
||||
Unsubscribable unsubscribable = new Unsubscribable(mailManager.getUnsubscribeAddress(request));
|
||||
String htmlBody = getHtmlBody(event, summary, null, url, replyable, unsubscribable);
|
||||
String textBody = getTextBody(event, summary, null, url, replyable, unsubscribable);
|
||||
String htmlBody = getHtmlBody(event, summary, event.getHtmlBody(), url, replyable, unsubscribable);
|
||||
String textBody = getTextBody(event, summary, event.getTextBody(), url, replyable, unsubscribable);
|
||||
mailManager.sendMailAsync(
|
||||
mentionedUsers.stream().map(User::getEmail).collect(Collectors.toList()),
|
||||
ccUsers.stream().map(User::getEmail).collect(Collectors.toList()),
|
||||
getSubject(request), htmlBody, textBody, replyAddress, threadingReferences);
|
||||
Lists.newArrayList(), Lists.newArrayList(),
|
||||
bccUsers.stream().map(User::getEmail).collect(Collectors.toList()),
|
||||
subject, htmlBody, textBody, replyAddress, threadingReferences);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getThreadingReferences(PullRequest request) {
|
||||
return "<" + request.getUUID() + "@onedev>";
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Listen
|
||||
public void on(EntityPersisted event) {
|
||||
@ -297,13 +286,15 @@ public class PullRequestNotificationManager extends AbstractNotificationManager
|
||||
if (review.getResult() == null && !review.getUser().equals(SecurityUtils.getUser())) {
|
||||
pullRequestWatchManager.watch(request, review.getUser(), true);
|
||||
String url = urlManager.urlFor(request);
|
||||
String summary = "Pull request " + request.getFQN() + ": You are invited to review";
|
||||
String subject = String.format("[Pull Request %s] (Review Invitation) %s",
|
||||
request.getFQN(), request.getTitle());
|
||||
String threadingReferences = "<review-invitation-" + request.getUUID() + "@onedev>";
|
||||
String replyAddress = mailManager.getReplyAddress(request);
|
||||
mailManager.sendMailAsync(Lists.newArrayList(review.getUser().getEmail()),
|
||||
Lists.newArrayList(), getSubject(request),
|
||||
getHtmlBody(event, summary, null, url, replyAddress != null, null),
|
||||
getTextBody(event, summary, null, url, replyAddress != null, null),
|
||||
replyAddress, getThreadingReferences(request));
|
||||
Lists.newArrayList(), Lists.newArrayList(), subject,
|
||||
getHtmlBody(event, null, null, url, replyAddress != null, null),
|
||||
getTextBody(event, null, null, url, replyAddress != null, null),
|
||||
replyAddress, threadingReferences);
|
||||
}
|
||||
} else if (event.getEntity() instanceof PullRequestAssignment) {
|
||||
PullRequestAssignment assignment = (PullRequestAssignment) event.getEntity();
|
||||
@ -311,13 +302,14 @@ public class PullRequestNotificationManager extends AbstractNotificationManager
|
||||
if (!assignment.getUser().equals(SecurityUtils.getUser())) {
|
||||
pullRequestWatchManager.watch(request, assignment.getUser(), true);
|
||||
String url = urlManager.urlFor(request);
|
||||
String summary = "Pull request " + request.getFQN() + ": You are assigned and expected to merge";
|
||||
String subject = String.format("[Pull Request %s] (Assigned) %s", request.getFQN(), request.getTitle());
|
||||
String threadingReferences = "<assigned-" + request.getUUID() + "@onedev>";
|
||||
String replyAddress = mailManager.getReplyAddress(request);
|
||||
mailManager.sendMailAsync(Lists.newArrayList(assignment.getUser().getEmail()),
|
||||
Lists.newArrayList(), getSubject(request),
|
||||
getHtmlBody(event, summary, null, url, replyAddress != null, null),
|
||||
getTextBody(event, summary, null, url, replyAddress != null, null),
|
||||
replyAddress, getThreadingReferences(request));
|
||||
Lists.newArrayList(), Lists.newArrayList(), subject,
|
||||
getHtmlBody(event, null, null, url, replyAddress != null, null),
|
||||
getTextBody(event, null, null, url, replyAddress != null, null),
|
||||
replyAddress, threadingReferences);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,7 +245,7 @@ public class IssueResource {
|
||||
Issue issue = issueManager.load(issueId);
|
||||
if (!SecurityUtils.canModify(issue))
|
||||
throw new UnauthorizedException();
|
||||
issueChangeManager.changeDescription(issue, description);
|
||||
issueManager.saveDescription(issue, description);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -289,7 +289,7 @@ public class PullRequestResource {
|
||||
PullRequest request = pullRequestManager.load(requestId);
|
||||
if (!SecurityUtils.canModify(request))
|
||||
throw new UnauthorizedException();
|
||||
pullRequestChangeManager.changeDescription(request, description);
|
||||
pullRequestManager.saveDescription(request, description);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -3,22 +3,24 @@ package io.onedev.server.ssh;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import org.apache.sshd.common.Factory;
|
||||
|
||||
import org.apache.sshd.server.Environment;
|
||||
import org.apache.sshd.server.ExitCallback;
|
||||
import org.apache.sshd.server.SessionAware;
|
||||
import org.apache.sshd.server.channel.ChannelSession;
|
||||
import org.apache.sshd.server.command.Command;
|
||||
import org.apache.sshd.server.session.ServerSession;
|
||||
import org.apache.sshd.server.session.ServerSessionAware;
|
||||
import org.apache.sshd.server.shell.ShellFactory;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
|
||||
public class DisableShellAccess implements Factory<Command> {
|
||||
public class DisableShellAccess implements ShellFactory {
|
||||
|
||||
@Override
|
||||
public Command create() {
|
||||
public Command createShell(ChannelSession channel) {
|
||||
return new WelcomeMessage();
|
||||
}
|
||||
|
||||
private static class WelcomeMessage implements Command, SessionAware {
|
||||
private static class WelcomeMessage implements Command, ServerSessionAware {
|
||||
|
||||
private InputStream in;
|
||||
private OutputStream out;
|
||||
@ -26,7 +28,7 @@ public class DisableShellAccess implements Factory<Command> {
|
||||
private ExitCallback callback;
|
||||
|
||||
@Override
|
||||
public void start(Environment env) throws IOException {
|
||||
public void start(ChannelSession channel, Environment env) throws IOException {
|
||||
err.write(Constants.encode(generateWelcomeMessage()));
|
||||
err.flush();
|
||||
callback.onExit(0);
|
||||
@ -41,7 +43,7 @@ public class DisableShellAccess implements Factory<Command> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
public void destroy(ChannelSession channel) throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -50,7 +50,7 @@ public class SshServerLauncher {
|
||||
server.setPublickeyAuthenticator(new CachingPublicKeyAuthenticator(authenticator));
|
||||
server.setKeyboardInteractiveAuthenticator(null);
|
||||
|
||||
server.setCommandFactory(command -> {
|
||||
server.setCommandFactory((channel, command) -> {
|
||||
for (SshCommandCreator creator: commandCreators) {
|
||||
Command sshCommand = creator.createCommand(command);
|
||||
if (sshCommand != null)
|
||||
|
||||
125
server-core/src/main/java/io/onedev/server/util/HtmlUtils.java
Normal file
125
server-core/src/main/java/io/onedev/server/util/HtmlUtils.java
Normal file
@ -0,0 +1,125 @@
|
||||
package io.onedev.server.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Attribute;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.nodes.Node;
|
||||
import org.jsoup.nodes.TextNode;
|
||||
import org.jsoup.safety.Cleaner;
|
||||
import org.jsoup.safety.Whitelist;
|
||||
import org.unbescape.html.HtmlEscape;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import io.onedev.commons.utils.StringUtils;
|
||||
|
||||
public class HtmlUtils {
|
||||
|
||||
private static final String[] SAFE_TAGS = new String[] { "h1", "h2", "h3", "h4", "h5", "h6", "h7", "h8", "br", "b",
|
||||
"i", "strong", "em", "a", "pre", "code", "img", "tt", "div", "ins", "del", "sup", "sub", "p", "ol", "ul",
|
||||
"li", "table", "thead", "tbody", "tfoot", "th", "tr", "td", "rt", "rp", "blockquote", "dl", "dt", "dd",
|
||||
"kbd", "q", "hr", "strike", "caption", "cite", "col", "colgroup", "small", "span", "u", "input", "video", "source"};
|
||||
|
||||
private static final String[] SAFE_ATTRIBUTES = new String[] { "abbr", "accept", "accept-charset", "accesskey",
|
||||
"action", "align", "alt", "axis", "border", "cellpadding", "cellspacing", "char", "charoff", "charset",
|
||||
"checked", "cite", "clear", "cols", "colspan", "color", "compact", "coords", "datetime", "details", "dir",
|
||||
"disabled", "enctype", "for", "frame", "headers", "height", "hreflang", "hspace", "ismap", "label", "lang",
|
||||
"longdesc", "maxlength", "media", "method", "multiple", "name", "nohref", "noshade", "nowrap", "prompt",
|
||||
"readonly", "rel", "rev", "rows", "rowspan", "rules", "scope", "selected", "shape", "size", "span", "start",
|
||||
"style", "summary", "tabindex", "target", "title", "type", "usemap", "valign", "value", "vspace", "width",
|
||||
"itemprop", "class", "controls", "id"};
|
||||
|
||||
private static final String[] SAFE_ANCHOR_SCHEMES = new String[] { "http", "https", "mailto", };
|
||||
|
||||
private static final Whitelist whiteList;
|
||||
|
||||
static {
|
||||
whiteList = new Whitelist() {
|
||||
|
||||
@Override
|
||||
protected boolean isSafeAttribute(String tagName, Element el, Attribute attr) {
|
||||
if (attr.getKey().startsWith("data-"))
|
||||
return true;
|
||||
else
|
||||
return super.isSafeAttribute(tagName, el, attr);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
whiteList.addTags(SAFE_TAGS)
|
||||
.addAttributes("a", "href", "title")
|
||||
.addAttributes("img", "align", "alt", "height", "src", "title", "width")
|
||||
.addAttributes("div", "itemscope", "itemtype")
|
||||
.addAttributes("source", "src")
|
||||
.addAttributes(":all", SAFE_ATTRIBUTES)
|
||||
.addProtocols("a", "href", SAFE_ANCHOR_SCHEMES)
|
||||
.addProtocols("blockquote", "cite", "http", "https")
|
||||
.addProtocols("cite", "cite", "http", "https")
|
||||
.addProtocols("img", "src", "http", "https")
|
||||
.addProtocols("q", "cite", "http", "https")
|
||||
.preserveRelativeLinks(true);
|
||||
}
|
||||
|
||||
public static boolean hasAncestor(Node node, Collection<String> tags) {
|
||||
Node parent = node.parentNode();
|
||||
while (parent != null) {
|
||||
if (parent instanceof Element) {
|
||||
Element e = (Element) parent;
|
||||
if (tags.contains(e.tagName().toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
parent = parent.parentNode();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasAncestor(Node node, String tag) {
|
||||
return hasAncestor(node, Lists.newArrayList(tag));
|
||||
}
|
||||
|
||||
public static void appendReplacement(Matcher matcher, Node node, String replacement) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
matcher.appendReplacement(buffer, "");
|
||||
if (buffer.length() != 0)
|
||||
node.before(new TextNode(buffer.toString(), node.baseUri()));
|
||||
node.before(replacement);
|
||||
}
|
||||
|
||||
public static void appendTail(Matcher matcher, Node node) {
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
matcher.appendTail(buffer);
|
||||
if (buffer.length() != 0)
|
||||
node.before(new TextNode(buffer.toString(), node.baseUri()));
|
||||
node.remove();
|
||||
}
|
||||
|
||||
public static Document sanitize(Document doc) {
|
||||
return new Cleaner(whiteList).clean(doc);
|
||||
}
|
||||
|
||||
public static Document parse(String html) {
|
||||
// Use a faked baseURI, otherwise all relative urls will be stripped out
|
||||
return Jsoup.parseBodyFragment(html, "http://localhost/sanitize");
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape text and preserving line breaks and white spaces
|
||||
* @param text
|
||||
* @return
|
||||
*/
|
||||
public static String formatAsHtml(String text) {
|
||||
text = HtmlEscape.escapeHtml5(text);
|
||||
text = StringUtils.replace(text, "\n", "<br>");
|
||||
text = StringUtils.replace(text, " ", " ");
|
||||
text = StringUtils.replace(text, "\t", " ");
|
||||
return text;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
package io.onedev.server.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.collect.MapDifference;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.MapDifference.ValueDifference;
|
||||
|
||||
public class PropertyChange implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String name;
|
||||
|
||||
private String oldValue;
|
||||
|
||||
private String newValue;
|
||||
|
||||
public PropertyChange(String name, String oldValue, String newValue) {
|
||||
this.name = name;
|
||||
this.oldValue = oldValue;
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getOldValue() {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
public void setOldValue(String oldValue) {
|
||||
this.oldValue = oldValue;
|
||||
}
|
||||
|
||||
public String getNewValue() {
|
||||
return newValue;
|
||||
}
|
||||
|
||||
public void setNewValue(String newValue) {
|
||||
this.newValue = newValue;
|
||||
}
|
||||
|
||||
public static List<PropertyChange> listOf(Map<String, String> oldProperties, Map<String, String> newProperties) {
|
||||
List<PropertyChange> changes = new ArrayList<>();
|
||||
MapDifference<String, String> diff = Maps.difference(oldProperties, newProperties);
|
||||
for (Map.Entry<String, ValueDifference<String>> entry: diff.entriesDiffering().entrySet()) {
|
||||
changes.add(new PropertyChange(entry.getKey(),
|
||||
entry.getValue().leftValue(), entry.getValue().rightValue()));
|
||||
}
|
||||
for (Map.Entry<String, String> entry: diff.entriesOnlyOnLeft().entrySet())
|
||||
changes.add(new PropertyChange(entry.getKey(), entry.getValue(), null));
|
||||
for (Map.Entry<String, String> entry: diff.entriesOnlyOnRight().entrySet())
|
||||
changes.add(new PropertyChange(entry.getKey(), null, entry.getValue()));
|
||||
return changes;
|
||||
}
|
||||
|
||||
}
|
||||
@ -17,12 +17,20 @@ public abstract class ManualConfig implements Serializable {
|
||||
|
||||
private final Collection<String> excludedProperties;
|
||||
|
||||
private final boolean forceOrdinaryStyle;
|
||||
|
||||
public ManualConfig(String title, @Nullable String description, Serializable setting,
|
||||
Collection<String> excludedProperties) {
|
||||
Collection<String> excludedProperties, boolean forceOrdinaryStyle) {
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.setting = setting;
|
||||
this.excludedProperties = excludedProperties;
|
||||
this.forceOrdinaryStyle = forceOrdinaryStyle;
|
||||
}
|
||||
|
||||
public ManualConfig(String title, @Nullable String description, Serializable setting,
|
||||
Collection<String> excludedProperties) {
|
||||
this(title, description, setting, excludedProperties, false);
|
||||
}
|
||||
|
||||
public ManualConfig(String title, @Nullable String description, Serializable setting) {
|
||||
@ -41,6 +49,10 @@ public abstract class ManualConfig implements Serializable {
|
||||
return setting;
|
||||
}
|
||||
|
||||
public boolean isForceOrdinaryStyle() {
|
||||
return forceOrdinaryStyle;
|
||||
}
|
||||
|
||||
public Collection<String> getExcludeProperties() {
|
||||
return excludedProperties;
|
||||
}
|
||||
|
||||
@ -35,9 +35,7 @@ import io.onedev.server.web.page.admin.role.RoleDetailPage;
|
||||
import io.onedev.server.web.page.admin.role.RoleListPage;
|
||||
import io.onedev.server.web.page.admin.serverinformation.ServerInformationPage;
|
||||
import io.onedev.server.web.page.admin.serverlog.ServerLogPage;
|
||||
import io.onedev.server.web.page.admin.servicedesk.DefaultProjectDesignationListPage;
|
||||
import io.onedev.server.web.page.admin.servicedesk.IssueCreationSettingListPage;
|
||||
import io.onedev.server.web.page.admin.servicedesk.SenderAuthorizationListPage;
|
||||
import io.onedev.server.web.page.admin.servicedesk.ServiceDeskSettingPage;
|
||||
import io.onedev.server.web.page.admin.ssh.SshSettingPage;
|
||||
import io.onedev.server.web.page.admin.sso.SsoConnectorListPage;
|
||||
import io.onedev.server.web.page.admin.sso.SsoProcessPage;
|
||||
@ -219,12 +217,8 @@ public class OneUrlMapper extends CompoundRequestMapper {
|
||||
|
||||
add(new DynamicPathPageMapper("administration/settings/system", SystemSettingPage.class));
|
||||
add(new DynamicPathPageMapper("administration/settings/mail", MailSettingPage.class));
|
||||
add(new DynamicPathPageMapper("administration/settings/sender-authorizations",
|
||||
SenderAuthorizationListPage.class));
|
||||
add(new DynamicPathPageMapper("administration/settings/default-projects",
|
||||
DefaultProjectDesignationListPage.class));
|
||||
add(new DynamicPathPageMapper("administration/settings/issue-creation-settings",
|
||||
IssueCreationSettingListPage.class));
|
||||
add(new DynamicPathPageMapper("administration/settings/service-desk-setting",
|
||||
ServiceDeskSettingPage.class));
|
||||
add(new DynamicPathPageMapper("administration/settings/issue-notification-template",
|
||||
IssueNotificationTemplatePage.class));
|
||||
add(new DynamicPathPageMapper("administration/settings/pull-request-notification-template",
|
||||
|
||||
@ -2835,4 +2835,8 @@ a.badge.badge-light-dark:hover, a.badge.badge-light-dark:focus {
|
||||
|
||||
.form-text {
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 1.2rem;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user