Skip to content

Commit

Permalink
#33 related actions panel
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexey Belostotskiy committed Oct 3, 2019
1 parent 05b0bae commit 5c2bfdc
Show file tree
Hide file tree
Showing 10 changed files with 287 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ public class AuditLogEntryDto extends AuditLogEntryForm {
private Integer scriptId;
@XmlElement
private JiraUser user;
@XmlElement
private String url;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ru.mail.jira.plugins.groovy.api.entity;

import net.java.ao.Entity;
import net.java.ao.schema.Indexed;
import net.java.ao.schema.NotNull;
import net.java.ao.schema.Table;

@Table("AUDIT_ISSUE_REL")
public interface AuditLogIssueRelation extends Entity {
@NotNull
AuditLogEntry getAuditLog();

@NotNull
@Indexed
Long getIssueId();
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package ru.mail.jira.plugins.groovy.api.repository;

import com.atlassian.activeobjects.tx.Transactional;
import com.atlassian.jira.user.ApplicationUser;
import ru.mail.jira.plugins.groovy.api.dto.audit.AuditLogEntryDto;
import ru.mail.jira.plugins.groovy.api.dto.audit.AuditLogEntryForm;
import ru.mail.jira.plugins.groovy.api.dto.Page;
import ru.mail.jira.plugins.groovy.api.entity.AuditLogEntry;
import ru.mail.jira.plugins.groovy.api.entity.EntityAction;
import ru.mail.jira.plugins.groovy.api.entity.EntityType;

Expand All @@ -16,4 +18,9 @@ public interface AuditLogRepository {
List<AuditLogEntryDto> findAllForEntity(int id, EntityType entityType);

Page<AuditLogEntryDto> getPagedEntries(int offset, int limit, Set<String> users, Set<EntityType> categories, Set<EntityAction> actions);

@Transactional
void createRelations(AuditLogEntry auditLogEntry);

List<AuditLogEntryDto> getRelated(long issueId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

import com.atlassian.activeobjects.external.ActiveObjects;
import com.atlassian.jira.datetime.DateTimeFormatter;
import com.atlassian.jira.issue.IssueManager;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.util.JiraKeyUtils;
import com.atlassian.plugin.spring.scanner.annotation.export.ExportAsDevService;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import com.atlassian.pocketknife.api.querydsl.DatabaseAccessor;
Expand All @@ -23,15 +26,18 @@

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static ru.mail.jira.plugins.groovy.util.QueryDslTables.AUDIT_LOG_ENTRY;
import static ru.mail.jira.plugins.groovy.util.QueryDslTables.AUDIT_LOG_ISSUE_RELATION;

@Component
@ExportAsDevService(AuditLogRepository.class)
public class AuditLogRepositoryImpl implements AuditLogRepository {
private final IssueManager issueManager;
private final ActiveObjects activeObjects;
private final DateTimeFormatter dateTimeFormatter;
private final DatabaseAccessor databaseAccessor;
Expand All @@ -40,12 +46,14 @@ public class AuditLogRepositoryImpl implements AuditLogRepository {

@Autowired
public AuditLogRepositoryImpl(
@ComponentImport IssueManager issueManager,
@ComponentImport ActiveObjects activeObjects,
@ComponentImport DateTimeFormatter dateTimeFormatter,
DatabaseAccessor databaseAccessor,
CustomFieldHelper customFieldHelper,
UserMapper userMapper
) {
this.issueManager = issueManager;
this.activeObjects = activeObjects;
this.dateTimeFormatter = dateTimeFormatter;
this.databaseAccessor = databaseAccessor;
Expand All @@ -55,7 +63,7 @@ public AuditLogRepositoryImpl(

@Override
public void create(ApplicationUser user, AuditLogEntryForm form) {
activeObjects.create(
AuditLogEntry auditLogEntry = activeObjects.create(
AuditLogEntry.class,
new DBParam("DATE", new Timestamp(System.currentTimeMillis())),
new DBParam("USER_KEY", user.getKey()),
Expand All @@ -64,6 +72,8 @@ public void create(ApplicationUser user, AuditLogEntryForm form) {
new DBParam("DESCRIPTION", form.getDescription()),
new DBParam("ENTITY_ID", form.getEntityId())
);

createRelations(auditLogEntry);
}

@Override
Expand Down Expand Up @@ -126,6 +136,109 @@ public Page<AuditLogEntryDto> getPagedEntries(int offset, int limit, Set<String>
}, OnRollback.NOOP);
}

@Override
public void createRelations(AuditLogEntry entry) {
EntityAction action = entry.getAction();
if (action == EntityAction.DISABLED || action == EntityAction.ENABLED || action == EntityAction.DELETED ||
action == EntityAction.RESTORED || action == EntityAction.MOVED ||
entry.getCategory() == EntityType.REGISTRY_DIRECTORY
) {
return;
}

Set<String> issueKeys = new HashSet<>(JiraKeyUtils.getIssueKeysFromString(entry.getDescription()));

Integer entityId = entry.getEntityId();
//search for issue key in name only for CREATED action
if (action == EntityAction.CREATED && entityId != null) {
String name = null;
switch (entry.getCategory()) {
case ADMIN_SCRIPT: {
AdminScript script = activeObjects.get(AdminScript.class, entityId);
name = script.getName();
break;
}
case REGISTRY_SCRIPT: {
Script script = activeObjects.get(Script.class, entityId);
name = script.getName();
break;
}
case REGISTRY_DIRECTORY: {
ScriptDirectory directory = activeObjects.get(ScriptDirectory.class, entityId);
name = directory.getName();
break;
}
case LISTENER: {
Listener listener = activeObjects.get(Listener.class, entityId);
name = listener.getName();
break;
}
case REST: {
RestScript script = activeObjects.get(RestScript.class, entityId);
name = script.getName();
break;
}
case CUSTOM_FIELD: {
Long fieldConfigId = activeObjects.get(FieldScript.class, entityId).getFieldConfigId();
name = customFieldHelper.getFieldName(fieldConfigId);
break;
}
case SCHEDULED_TASK: {
ScheduledTask task = activeObjects.get(ScheduledTask.class, entityId);
name = task.getName();
break;
}
case JQL_FUNCTION:
JqlFunctionScript function = activeObjects.get(JqlFunctionScript.class, entityId);
name = function.getName();
break;
case GLOBAL_OBJECT:
GlobalObject globalObject = activeObjects.get(GlobalObject.class, entityId);
name = globalObject.getName();
break;
}
if (name != null) {
issueKeys.addAll(JiraKeyUtils.getIssueKeysFromString(name));
}
}

databaseAccessor.run(
connection -> connection
.delete(AUDIT_LOG_ISSUE_RELATION)
.where(AUDIT_LOG_ISSUE_RELATION.AUDIT_LOG_ID.eq(entry.getID()))
.execute(),
OnRollback.NOOP
);
for (String issueKey : issueKeys) {
MutableIssue issue = issueManager.getIssueObject(issueKey);

if (issue != null) {
activeObjects.create(
AuditLogIssueRelation.class,
new DBParam("AUDIT_LOG_ID", entry.getID()),
new DBParam("ISSUE_ID", issue.getId())
);
}
}
}

@Override
public List<AuditLogEntryDto> getRelated(long issueId) {
return databaseAccessor.run(connection ->
connection
.select(AUDIT_LOG_ENTRY.all())
.from(AUDIT_LOG_ENTRY)
.join(AUDIT_LOG_ISSUE_RELATION).on(AUDIT_LOG_ENTRY.ID.eq(AUDIT_LOG_ISSUE_RELATION.AUDIT_LOG_ID))
.where(AUDIT_LOG_ISSUE_RELATION.ISSUE_ID.eq(issueId))
.orderBy(AUDIT_LOG_ENTRY.ID.desc())
.fetch()
.stream()
.map(this::buildDto)
.collect(Collectors.toList()),
OnRollback.NOOP
);
}

private void fillEntityData(AuditLogEntryDto result, EntityType category, Integer entityId) {
if (entityId != null) {
result.setScriptId(entityId);
Expand Down Expand Up @@ -202,13 +315,15 @@ private AuditLogEntryDto buildDto(Tuple row) {
AuditLogEntryDto result = new AuditLogEntryDto();

EntityType category = EntityType.valueOf(row.get(AUDIT_LOG_ENTRY.CATEGORY));
Integer id = row.get(AUDIT_LOG_ENTRY.ID);

result.setDate(dateTimeFormatter.forLoggedInUser().format(row.get(AUDIT_LOG_ENTRY.DATE)));
result.setId(row.get(AUDIT_LOG_ENTRY.ID));
result.setId(id);
result.setUser(userMapper.buildUser(row.get(AUDIT_LOG_ENTRY.USER_KEY)));
result.setAction(EntityAction.valueOf(row.get(AUDIT_LOG_ENTRY.ACTION)));
result.setCategory(category);
result.setDescription(row.get(AUDIT_LOG_ENTRY.DESCRIPTION));
result.setUrl(ScriptUtil.getPermalink(category, id));

fillEntityData(result, category, row.get(AUDIT_LOG_ENTRY.ENTITY_ID));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package ru.mail.jira.plugins.groovy.impl.repository.querydsl;

import com.atlassian.pocketknife.spi.querydsl.EnhancedRelationalPathBase;
import com.querydsl.core.types.dsl.NumberPath;

public class QAuditLogIssueRelation extends EnhancedRelationalPathBase<QAuditLogIssueRelation> {
public final NumberPath<Integer> ID = createIntegerCol("ID").asPrimaryKey().build();
public final NumberPath<Integer> AUDIT_LOG_ID = createIntegerCol("AUDIT_LOG_ID").build();
public final NumberPath<Long> ISSUE_ID = createLongCol("ISSUE_ID").build();

public QAuditLogIssueRelation() {
super(QAuditLogIssueRelation.class, "AO_2FC5DA_AUDIT_ISSUE_REL");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package ru.mail.jira.plugins.groovy.impl.upgrade;

import com.atlassian.activeobjects.external.ActiveObjects;
import com.atlassian.plugin.spring.scanner.annotation.export.ExportAsService;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import com.atlassian.sal.api.message.Message;
import com.atlassian.sal.api.upgrade.PluginUpgradeTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import ru.mail.jira.plugins.groovy.api.entity.AuditLogEntry;
import ru.mail.jira.plugins.groovy.api.repository.AuditLogRepository;
import ru.mail.jira.plugins.groovy.util.Const;

import java.util.Collection;
import java.util.Collections;

@Component
@ExportAsService(PluginUpgradeTask.class)
public class Upgrade001CreateAuditLogIssueRelation implements PluginUpgradeTask {
private final ActiveObjects activeObjects;
private final AuditLogRepository auditLogRepository;

@Autowired
public Upgrade001CreateAuditLogIssueRelation(
@ComponentImport ActiveObjects activeObjects,
AuditLogRepository auditLogRepository
) {
this.activeObjects = activeObjects;
this.auditLogRepository = auditLogRepository;
}

@Override
public int getBuildNumber() {
return 100;
}

@Override
public String getShortDescription() {
return "Created relation between audit log entry and Jira issues";
}

@Override
public Collection<Message> doUpgrade() throws Exception {
for (AuditLogEntry auditLogEntry : activeObjects.find(AuditLogEntry.class)) {
auditLogRepository.createRelations(auditLogEntry);
}

return Collections.emptyList();
}

@Override
public String getPluginKey() {
return Const.PLUGIN_KEY;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package ru.mail.jira.plugins.groovy.servlet;

import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.plugin.webfragment.contextproviders.AbstractJiraContextProvider;
import com.atlassian.jira.plugin.webfragment.model.JiraHelper;
import com.atlassian.jira.user.ApplicationUser;
import com.google.common.collect.ImmutableMap;
import ru.mail.jira.plugins.groovy.api.repository.AuditLogRepository;

import java.util.Collections;
import java.util.Map;

public class IssuePanelContextProvider extends AbstractJiraContextProvider {
private final AuditLogRepository auditLogRepository;

public IssuePanelContextProvider(
AuditLogRepository auditLogRepository
) {
this.auditLogRepository = auditLogRepository;
}

@Override
public Map getContextMap(
ApplicationUser applicationUser, JiraHelper jiraHelper
) {
Map<String, Object> params = jiraHelper.getContextParams();

Issue issue = (Issue) params.get("issue");

if (issue == null) {
return ImmutableMap.of("changes", Collections.emptyList());
}

return ImmutableMap.of(
"changes", auditLogRepository.getRelated(issue.getId())
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ public final class QueryDslTables {
private QueryDslTables() {}

public static final QAuditLogEntry AUDIT_LOG_ENTRY = new QAuditLogEntry();
public static final QAuditLogIssueRelation AUDIT_LOG_ISSUE_RELATION = new QAuditLogIssueRelation();
public static final QScriptExecution SCRIPT_EXECUTION = new QScriptExecution();

public static final QAbstractScript ADMIN_SCRIPT = new QAbstractScript("ADMIN_SCRIPT");
Expand Down
10 changes: 10 additions & 0 deletions src/main/resources/atlassian-plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
<entity>ru.mail.jira.plugins.groovy.api.entity.Listener</entity>
<entity>ru.mail.jira.plugins.groovy.api.entity.ListenerChangelog</entity>
<entity>ru.mail.jira.plugins.groovy.api.entity.AuditLogEntry</entity>
<entity>ru.mail.jira.plugins.groovy.api.entity.AuditLogIssueRelation</entity>
<entity>ru.mail.jira.plugins.groovy.api.entity.RestScript</entity>
<entity>ru.mail.jira.plugins.groovy.api.entity.RestChangelog</entity>
<entity>ru.mail.jira.plugins.groovy.api.entity.FieldScript</entity>
Expand Down Expand Up @@ -434,4 +435,13 @@
key="mygroovy-comment-search-extractor"
class="ru.mail.jira.plugins.groovy.impl.jql.indexers.AdditionalFieldsCommentExtractor"
/>

<web-panel name="MyGroovy" key="due-date-indicator" location="atl.jira.view.issue.right.context" weight="1000">
<context-provider class="ru.mail.jira.plugins.groovy.servlet.IssuePanelContextProvider"/>
<resource name="view" type="velocity" location="ru/mail/jira/plugins/groovy/templates/issue-panel.vm"/>
<label>MyGroovy</label>
<condition class="com.atlassian.jira.plugin.webfragment.conditions.JiraGlobalPermissionCondition">
<param name="permission">admin</param>
</condition>
</web-panel>
</atlassian-plugin>
Loading

0 comments on commit 5c2bfdc

Please sign in to comment.