mirror of
https://github.com/theonedev/onedev.git
synced 2025-12-08 18:26:30 +00:00
feat: Audit log for system and project setting changes (OD-2142)
This commit is contained in:
parent
5583a01fda
commit
a47b38e375
@ -371,6 +371,7 @@ import io.onedev.server.util.oauth.OAuthTokenManager;
|
||||
import io.onedev.server.util.xstream.CollectionConverter;
|
||||
import io.onedev.server.util.xstream.HibernateProxyConverter;
|
||||
import io.onedev.server.util.xstream.MapConverter;
|
||||
import io.onedev.server.util.xstream.ObjectMapperConverter;
|
||||
import io.onedev.server.util.xstream.ReflectionConverter;
|
||||
import io.onedev.server.util.xstream.StringConverter;
|
||||
import io.onedev.server.util.xstream.VersionedDocumentConverter;
|
||||
@ -393,7 +394,6 @@ 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.exceptionhandler.PageExpiredExceptionHandler;
|
||||
import io.onedev.server.web.page.layout.AdministrationMenuContribution;
|
||||
import io.onedev.server.web.page.layout.AdministrationSettingContribution;
|
||||
import io.onedev.server.web.page.project.blob.render.BlobRenderer;
|
||||
import io.onedev.server.web.page.project.setting.ProjectSettingContribution;
|
||||
@ -691,8 +691,6 @@ public class CoreModule extends AbstractPluginModule {
|
||||
bind(UploadManager.class).to(DefaultUploadManager.class);
|
||||
|
||||
bind(TaskButton.TaskFutureManager.class);
|
||||
|
||||
contribute(AdministrationMenuContribution.class, (AdministrationMenuContribution) ArrayList::new);
|
||||
}
|
||||
|
||||
private void configureBuild() {
|
||||
@ -856,6 +854,7 @@ public class CoreModule extends AbstractPluginModule {
|
||||
xstream.registerConverter(new HibernateProxyConverter(), XStream.PRIORITY_VERY_HIGH);
|
||||
xstream.registerConverter(new CollectionConverter(xstream.getMapper()), XStream.PRIORITY_VERY_HIGH);
|
||||
xstream.registerConverter(new MapConverter(xstream.getMapper()), XStream.PRIORITY_VERY_HIGH);
|
||||
xstream.registerConverter(new ObjectMapperConverter(), XStream.PRIORITY_VERY_HIGH);
|
||||
xstream.registerConverter(new ISO8601DateConverter(), XStream.PRIORITY_VERY_HIGH);
|
||||
xstream.registerConverter(new ISO8601SqlTimestampConverter(), XStream.PRIORITY_VERY_HIGH);
|
||||
xstream.registerConverter(new ReflectionConverter(xstream.getMapper(), xstream.getReflectionProvider()),
|
||||
|
||||
@ -99,6 +99,7 @@ import io.onedev.server.model.Setting.Key;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.model.support.administration.AgentSetting;
|
||||
import io.onedev.server.model.support.administration.AlertSetting;
|
||||
import io.onedev.server.model.support.administration.AuditSetting;
|
||||
import io.onedev.server.model.support.administration.BackupSetting;
|
||||
import io.onedev.server.model.support.administration.BrandingSetting;
|
||||
import io.onedev.server.model.support.administration.ClusterSetting;
|
||||
@ -897,6 +898,12 @@ public class DefaultDataManager implements DataManager, Serializable {
|
||||
clusterSetting.setReplicaCount(1);
|
||||
settingManager.saveClusterSetting(clusterSetting);
|
||||
}
|
||||
|
||||
setting = settingManager.findSetting(Key.AUDIT);
|
||||
if (setting == null) {
|
||||
AuditSetting auditSetting = new AuditSetting();
|
||||
settingManager.saveAuditSetting(auditSetting);
|
||||
}
|
||||
|
||||
if (roleManager.get(Role.OWNER_ID) == null) {
|
||||
Role owner = new Role();
|
||||
|
||||
@ -8129,4 +8129,7 @@ public class DataMigrator {
|
||||
}
|
||||
}
|
||||
|
||||
private void migrate205(File dataDir, Stack<Integer> versions) {
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
package io.onedev.server.entitymanager;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import io.onedev.server.entitymanager.support.AuditQuery;
|
||||
import io.onedev.server.model.Audit;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.persistence.dao.EntityManager;
|
||||
|
||||
public interface AuditManager extends EntityManager<Audit> {
|
||||
|
||||
void audit(@Nullable Project project, String action, @Nullable String oldContent, @Nullable String newContent);
|
||||
|
||||
List<Audit> query(@Nullable Project project, AuditQuery query, int firstResult, int maxResults);
|
||||
|
||||
int count(@Nullable Project project, AuditQuery query);
|
||||
|
||||
}
|
||||
@ -1,15 +1,16 @@
|
||||
package io.onedev.server.entitymanager;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import io.onedev.server.model.LinkAuthorization;
|
||||
import io.onedev.server.model.LinkSpec;
|
||||
import io.onedev.server.model.Role;
|
||||
import io.onedev.server.persistence.dao.EntityManager;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface LinkAuthorizationManager extends EntityManager<LinkAuthorization> {
|
||||
|
||||
void syncAuthorizations(Role role, Collection<LinkSpec> authorizedLinks);
|
||||
|
||||
void create(LinkAuthorization authorization);
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,20 @@
|
||||
package io.onedev.server.entitymanager;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
|
||||
import io.onedev.server.cluster.ClusterTask;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.support.code.GitPackConfig;
|
||||
@ -11,19 +26,6 @@ import io.onedev.server.util.criteria.Criteria;
|
||||
import io.onedev.server.util.facade.ProjectCache;
|
||||
import io.onedev.server.util.facade.ProjectFacade;
|
||||
import io.onedev.server.util.patternset.PatternSet;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public interface ProjectManager extends EntityManager<Project> {
|
||||
|
||||
|
||||
@ -15,9 +15,9 @@ public interface RoleManager extends EntityManager<Role> {
|
||||
|
||||
void replicate(Role role);
|
||||
|
||||
void create(Role role, Collection<LinkSpec> authorizedLinks);
|
||||
void create(Role role, @Nullable Collection<LinkSpec> authorizedLinks);
|
||||
|
||||
void update(Role role, Collection<LinkSpec> authorizedLinks, @Nullable String oldName);
|
||||
void update(Role role, @Nullable Collection<LinkSpec> authorizedLinks, @Nullable String oldName);
|
||||
|
||||
@Nullable
|
||||
Role find(String name);
|
||||
|
||||
@ -83,6 +83,10 @@ public interface SettingManager extends EntityManager<Setting> {
|
||||
ClusterSetting getClusterSetting();
|
||||
|
||||
void saveClusterSetting(ClusterSetting clusterSetting);
|
||||
|
||||
AuditSetting getAuditSetting();
|
||||
|
||||
void saveAuditSetting(AuditSetting auditSetting);
|
||||
|
||||
SecuritySetting getSecuritySetting();
|
||||
|
||||
|
||||
@ -29,7 +29,6 @@ import io.onedev.server.persistence.dao.BaseEntityManager;
|
||||
import io.onedev.server.persistence.dao.Dao;
|
||||
import io.onedev.server.util.CryptoUtils;
|
||||
import io.onedev.server.util.facade.AccessTokenCache;
|
||||
import io.onedev.server.util.facade.AccessTokenFacade;
|
||||
|
||||
@Singleton
|
||||
public class DefaultAccessTokenManager extends BaseEntityManager<AccessToken> implements AccessTokenManager {
|
||||
@ -134,7 +133,7 @@ public class DefaultAccessTokenManager extends BaseEntityManager<AccessToken> im
|
||||
@Listen
|
||||
public void on(EntityPersisted event) {
|
||||
if (event.getEntity() instanceof AccessToken) {
|
||||
var facade = (AccessTokenFacade) event.getEntity().getFacade();
|
||||
var facade = ((AccessToken) event.getEntity()).getFacade();
|
||||
transactionManager.runAfterCommit(() -> cache.put(facade.getId(), facade));
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ public class DefaultGroupManager extends BaseEntityManager<Group> implements Gro
|
||||
@Listen
|
||||
public void on(EntityPersisted event) {
|
||||
if (event.getEntity() instanceof Group) {
|
||||
var facade = (GroupFacade) event.getEntity().getFacade();
|
||||
var facade = ((Group) event.getEntity()).getFacade();
|
||||
transactionManager.runAfterCommit(() -> cache.put(facade.getId(), facade));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1093,7 +1093,6 @@ public class DefaultIssueManager extends BaseEntityManager<Issue> implements Iss
|
||||
Project oldProject = issue.getProject();
|
||||
Project numberScope = targetProject.getForkRoot();
|
||||
Long nextNumber = getNextNumber(numberScope);
|
||||
issue.setOldVersion(issue.getFacade());
|
||||
issue.setProject(targetProject);
|
||||
issue.setNumberScope(numberScope);
|
||||
Long oldNumber = issue.getNumber();
|
||||
|
||||
@ -6,6 +6,7 @@ import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import io.onedev.server.entitymanager.LinkAuthorizationManager;
|
||||
import io.onedev.server.model.LinkAuthorization;
|
||||
import io.onedev.server.model.LinkSpec;
|
||||
|
||||
@ -164,7 +164,7 @@ public class DefaultLinkSpecManager extends BaseEntityManager<LinkSpec> implemen
|
||||
@Listen
|
||||
public void on(EntityPersisted event) {
|
||||
if (event.getEntity() instanceof LinkSpec) {
|
||||
var facade = (LinkSpecFacade) event.getEntity().getFacade();
|
||||
var facade = ((LinkSpec) event.getEntity()).getFacade();
|
||||
transactionManager.runAfterCommit(() -> updateCache(facade));
|
||||
}
|
||||
}
|
||||
@ -173,7 +173,7 @@ public class DefaultLinkSpecManager extends BaseEntityManager<LinkSpec> implemen
|
||||
@Listen
|
||||
public void on(EntityRemoved event) {
|
||||
if (event.getEntity() instanceof LinkSpec) {
|
||||
var facade = (LinkSpecFacade) event.getEntity().getFacade();
|
||||
var facade = ((LinkSpec) event.getEntity()).getFacade();
|
||||
transactionManager.runAfterCommit(() -> {
|
||||
cache.remove(facade.getId());
|
||||
idCache.remove(facade.getName());
|
||||
|
||||
@ -117,6 +117,8 @@ import io.onedev.server.StorageManager;
|
||||
import io.onedev.server.attachment.AttachmentManager;
|
||||
import io.onedev.server.cluster.ClusterManager;
|
||||
import io.onedev.server.cluster.ClusterTask;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.BuildManager;
|
||||
import io.onedev.server.entitymanager.IssueManager;
|
||||
import io.onedev.server.entitymanager.LinkSpecManager;
|
||||
@ -256,6 +258,8 @@ public class DefaultProjectManager extends BaseEntityManager<Project>
|
||||
private final PackBlobManager packBlobManager;
|
||||
|
||||
private final ProjectLabelManager labelManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
private final Collection<String> reservedNames = Sets.newHashSet("robots.txt", "sitemap.xml", "sitemap.txt",
|
||||
"favicon.ico", "favicon.png", "logo.png", "wicket", "projects");
|
||||
@ -282,7 +286,8 @@ public class DefaultProjectManager extends BaseEntityManager<Project>
|
||||
AttachmentManager attachmentManager, BatchWorkManager batchWorkManager,
|
||||
VisitInfoManager visitInfoManager, StorageManager storageManager,
|
||||
PackManager packManager, PackBlobManager packBlobManager,
|
||||
ProjectLabelManager labelManager, Set<ProjectNameReservation> nameReservations) {
|
||||
ProjectLabelManager labelManager, AuditManager auditManager,
|
||||
Set<ProjectNameReservation> nameReservations) {
|
||||
super(dao);
|
||||
|
||||
this.commitInfoManager = commitInfoManager;
|
||||
@ -308,6 +313,7 @@ public class DefaultProjectManager extends BaseEntityManager<Project>
|
||||
this.packManager = packManager;
|
||||
this.packBlobManager = packBlobManager;
|
||||
this.labelManager = labelManager;
|
||||
this.auditManager = auditManager;
|
||||
|
||||
for (ProjectNameReservation reservation : nameReservations)
|
||||
reservedNames.addAll(reservation.getReserved());
|
||||
@ -369,8 +375,10 @@ public class DefaultProjectManager extends BaseEntityManager<Project>
|
||||
public void create(Project project) {
|
||||
Preconditions.checkState(project.isNew());
|
||||
Project parent = project.getParent();
|
||||
if (parent != null && parent.isNew())
|
||||
if (parent != null && parent.isNew()) {
|
||||
create(parent);
|
||||
auditManager.audit(parent, "created project", null, VersionedXmlDoc.fromBean(parent).toXML());
|
||||
}
|
||||
project.setPath(project.calcPath());
|
||||
|
||||
ProjectLastEventDate lastEventDate = new ProjectLastEventDate();
|
||||
@ -440,17 +448,7 @@ public class DefaultProjectManager extends BaseEntityManager<Project>
|
||||
@Transactional
|
||||
@Override
|
||||
public void delete(Collection<Project> projects) {
|
||||
Collection<Project> independents = new HashSet<>(projects);
|
||||
for (Iterator<Project> it = independents.iterator(); it.hasNext(); ) {
|
||||
Project independent = it.next();
|
||||
for (Project each : independents) {
|
||||
if (!each.equals(independent) && each.isSelfOrAncestorOf(independent)) {
|
||||
it.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (Project independent : independents)
|
||||
for (Project independent : Project.getIndependents(projects))
|
||||
delete(independent);
|
||||
}
|
||||
|
||||
|
||||
@ -112,7 +112,9 @@ public class DefaultRoleManager extends BaseEntityManager<Role> implements RoleM
|
||||
public void create(Role role, Collection<LinkSpec> authorizedLinks) {
|
||||
Preconditions.checkState(role.isNew());
|
||||
dao.persist(role);
|
||||
linkAuthorizationManager.syncAuthorizations(role, authorizedLinks);
|
||||
|
||||
if (authorizedLinks != null)
|
||||
linkAuthorizationManager.syncAuthorizations(role, authorizedLinks);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@ -122,9 +124,10 @@ public class DefaultRoleManager extends BaseEntityManager<Role> implements RoleM
|
||||
|
||||
if (oldName != null && !oldName.equals(role.getName()))
|
||||
settingManager.onRenameRole(oldName, role.getName());
|
||||
dao.persist(role);
|
||||
|
||||
linkAuthorizationManager.syncAuthorizations(role, authorizedLinks);
|
||||
dao.persist(role);
|
||||
|
||||
if (authorizedLinks != null)
|
||||
linkAuthorizationManager.syncAuthorizations(role, authorizedLinks);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@ -343,7 +346,7 @@ public class DefaultRoleManager extends BaseEntityManager<Role> implements RoleM
|
||||
@Listen
|
||||
public void on(EntityPersisted event) {
|
||||
if (event.getEntity() instanceof Role) {
|
||||
var facade = (RoleFacade) event.getEntity().getFacade();
|
||||
var facade = ((Role) event.getEntity()).getFacade();
|
||||
transactionManager.runAfterCommit(() -> cache.put(facade.getId(), facade));
|
||||
}
|
||||
}
|
||||
|
||||
@ -131,6 +131,11 @@ public class DefaultSettingManager extends BaseEntityManager<Setting>
|
||||
return (ClusterSetting) getSettingValue(Key.CLUSTER_SETTING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuditSetting getAuditSetting() {
|
||||
return (AuditSetting) getSettingValue(Key.AUDIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SecuritySetting getSecuritySetting() {
|
||||
return (SecuritySetting) getSettingValue(Key.SECURITY);
|
||||
@ -260,6 +265,12 @@ public class DefaultSettingManager extends BaseEntityManager<Setting>
|
||||
public void saveClusterSetting(ClusterSetting clusterSetting) {
|
||||
saveSetting(Key.CLUSTER_SETTING, clusterSetting);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public void saveAuditSetting(AuditSetting auditSetting) {
|
||||
saveSetting(Key.AUDIT, auditSetting);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
|
||||
@ -54,7 +54,7 @@ public class DefaultSshKeyManager extends BaseEntityManager<SshKey> implements S
|
||||
sshKey.setContent(content);
|
||||
sshKey.setOwner(user);
|
||||
sshKey.setCreatedAt(new Date());
|
||||
sshKey.fingerprint();
|
||||
sshKey.generateFingerprint();
|
||||
syncMap.put(content, sshKey);
|
||||
}
|
||||
|
||||
|
||||
@ -502,7 +502,7 @@ public class DefaultUserManager extends BaseEntityManager<User> implements UserM
|
||||
public void on(EntityPersisted event) {
|
||||
// Cache will be null when we run reset-admin-password command
|
||||
if (cache != null && event.getEntity() instanceof User) {
|
||||
var facade = (UserFacade) event.getEntity().getFacade();
|
||||
var facade = ((User) event.getEntity()).getFacade();
|
||||
if (facade.getId() > 0)
|
||||
transactionManager.runAfterCommit(() -> cache.put(facade.getId(), facade));
|
||||
}
|
||||
|
||||
@ -0,0 +1,47 @@
|
||||
package io.onedev.server.entitymanager.support;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import io.onedev.server.model.User;
|
||||
|
||||
public class AuditQuery implements Serializable {
|
||||
|
||||
private final List<User> users;
|
||||
|
||||
private final Date sinceDate;
|
||||
|
||||
private final Date untilDate;
|
||||
|
||||
private final String action;
|
||||
|
||||
public AuditQuery(List<User> users, @Nullable Date sinceDate, @Nullable Date untilDate, @Nullable String action) {
|
||||
this.users = users;
|
||||
this.sinceDate = sinceDate;
|
||||
this.untilDate = untilDate;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public List<User> getUsers() {
|
||||
return users;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Date getSinceDate() {
|
||||
return sinceDate;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Date getUntilDate() {
|
||||
return untilDate;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,24 +1,27 @@
|
||||
package io.onedev.server.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.onedev.server.model.support.EntityWatch;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.util.facade.EntityFacade;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import static com.fasterxml.jackson.annotation.JsonProperty.Access.READ_ONLY;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import static com.fasterxml.jackson.annotation.JsonProperty.Access.READ_ONLY;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.model.support.EntityWatch;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
|
||||
@MappedSuperclass
|
||||
@JsonIgnoreProperties("handler")
|
||||
@ -36,7 +39,7 @@ public abstract class AbstractEntity implements Serializable, Comparable<Abstrac
|
||||
|
||||
public static final String PROP_NUMBER = "number";
|
||||
|
||||
private transient EntityFacade oldVersion;
|
||||
private transient VersionedXmlDoc oldVersion;
|
||||
|
||||
@Api(order=1)
|
||||
@Id
|
||||
@ -117,11 +120,11 @@ public abstract class AbstractEntity implements Serializable, Comparable<Abstrac
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public EntityFacade getOldVersion() {
|
||||
public VersionedXmlDoc getOldVersion() {
|
||||
return oldVersion;
|
||||
}
|
||||
|
||||
public void setOldVersion(@Nullable EntityFacade oldVersion) {
|
||||
public void setOldVersion(VersionedXmlDoc oldVersion) {
|
||||
this.oldVersion = oldVersion;
|
||||
}
|
||||
|
||||
@ -146,10 +149,5 @@ public abstract class AbstractEntity implements Serializable, Comparable<Abstrac
|
||||
return entity.getId();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public EntityFacade getFacade() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -122,7 +122,6 @@ public class AccessToken extends AbstractEntity implements AuthenticationInfo {
|
||||
return SecurityUtils.asSubject(getPrincipals());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessTokenFacade getFacade() {
|
||||
return new AccessTokenFacade(getId(), getOwner().getId(), getName(), getValue(), getExpireDate());
|
||||
}
|
||||
|
||||
@ -1,9 +1,17 @@
|
||||
package io.onedev.server.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
import javax.persistence.*;
|
||||
import io.onedev.server.rest.annotation.Immutable;
|
||||
|
||||
@Entity
|
||||
@Table(
|
||||
@ -21,6 +29,7 @@ public class AccessTokenAuthorization extends AbstractEntity {
|
||||
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
@JoinColumn(nullable=false)
|
||||
@Immutable
|
||||
private AccessToken token;
|
||||
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
@ -50,5 +59,5 @@ public class AccessTokenAuthorization extends AbstractEntity {
|
||||
public void setRole(Role role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
116
server-core/src/main/java/io/onedev/server/model/Audit.java
Normal file
116
server-core/src/main/java/io/onedev/server/model/Audit.java
Normal file
@ -0,0 +1,116 @@
|
||||
package io.onedev.server.model;
|
||||
|
||||
import static io.onedev.server.model.Audit.PROP_ACTION;
|
||||
import static io.onedev.server.model.Audit.PROP_DATE;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(
|
||||
indexes={
|
||||
@Index(columnList="o_project_id"), @Index(columnList= "o_user_id"),
|
||||
@Index(columnList= PROP_DATE), @Index(columnList= PROP_ACTION)}
|
||||
)
|
||||
public class Audit extends AbstractEntity {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final int MAX_ACTION_LEN = 512;
|
||||
|
||||
private static final int MAX_CONTENT_LEN = 1048576;
|
||||
|
||||
public static final String PROP_PROJECT = "project";
|
||||
|
||||
public static final String PROP_USER = "user";
|
||||
|
||||
public static final String PROP_ACTION = "action";
|
||||
|
||||
public static final String PROP_DATE = "date";
|
||||
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
@JoinColumn
|
||||
private Project project;
|
||||
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
@JoinColumn(nullable=false)
|
||||
private User user;
|
||||
|
||||
@Column(nullable=false, length=MAX_ACTION_LEN)
|
||||
private String action;
|
||||
|
||||
@Column(nullable = false)
|
||||
private Date date = new Date();
|
||||
|
||||
@Column(length=MAX_CONTENT_LEN)
|
||||
private String oldContent;
|
||||
|
||||
@Column(length=MAX_CONTENT_LEN)
|
||||
private String newContent;
|
||||
|
||||
@Nullable
|
||||
public Project getProject() {
|
||||
return project;
|
||||
}
|
||||
|
||||
public void setProject(@Nullable Project project) {
|
||||
this.project = project;
|
||||
}
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
public void setUser(@Nullable User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public void setAction(String action) {
|
||||
if (action.length() > MAX_ACTION_LEN)
|
||||
throw new IllegalArgumentException("Audit action is too long: " + action);
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getOldContent() {
|
||||
return oldContent;
|
||||
}
|
||||
|
||||
public void setOldContent(@Nullable String oldContent) {
|
||||
if (oldContent != null && oldContent.length() > MAX_CONTENT_LEN)
|
||||
throw new IllegalArgumentException("Audit content is too long: " + oldContent);
|
||||
this.oldContent = oldContent;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getNewContent() {
|
||||
return newContent;
|
||||
}
|
||||
|
||||
public void setNewContent(@Nullable String newContent) {
|
||||
if (newContent != null && newContent.length() > MAX_CONTENT_LEN)
|
||||
throw new IllegalArgumentException("Audit content is too long: " + newContent);
|
||||
this.newContent = newContent;
|
||||
}
|
||||
|
||||
}
|
||||
@ -11,6 +11,8 @@ import javax.persistence.UniqueConstraint;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
import io.onedev.server.rest.annotation.Immutable;
|
||||
|
||||
@Entity
|
||||
@Table(
|
||||
indexes={@Index(columnList="o_project_id"), @Index(columnList="o_role_id")},
|
||||
@ -27,6 +29,7 @@ public class BaseAuthorization extends AbstractEntity {
|
||||
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
@JoinColumn(nullable=false)
|
||||
@Immutable
|
||||
private Project project;
|
||||
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
|
||||
@ -896,7 +896,6 @@ public class Build extends ProjectBelonging
|
||||
return commitsCache.get(sincePrevStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuildFacade getFacade() {
|
||||
return new BuildFacade(getId(), getProject().getId(), getNumber(), getCommitHash());
|
||||
}
|
||||
|
||||
@ -103,7 +103,6 @@ public class EmailAddress extends AbstractEntity {
|
||||
return getVerificationCode() == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmailAddressFacade getFacade() {
|
||||
return new EmailAddressFacade(getId(), getOwner().getId(), getValue(),
|
||||
isPrimary(), isGit(), isOpen(), getVerificationCode());
|
||||
|
||||
@ -15,8 +15,9 @@ import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import io.onedev.server.model.support.BaseGpgKey;
|
||||
import io.onedev.server.annotation.Editable;
|
||||
import io.onedev.server.model.support.BaseGpgKey;
|
||||
import io.onedev.server.rest.annotation.Immutable;
|
||||
|
||||
@Editable
|
||||
@Entity
|
||||
@ -38,6 +39,7 @@ public class GpgKey extends BaseGpgKey {
|
||||
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
@JoinColumn(nullable=false)
|
||||
@Immutable
|
||||
private User owner;
|
||||
|
||||
public long getKeyId() {
|
||||
|
||||
@ -1,5 +1,20 @@
|
||||
package io.onedev.server.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
import org.apache.shiro.authz.Permission;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import io.onedev.server.annotation.Editable;
|
||||
import io.onedev.server.annotation.ShowCondition;
|
||||
import io.onedev.server.security.permission.BasePermission;
|
||||
@ -9,19 +24,6 @@ import io.onedev.server.security.permission.SystemAdministration;
|
||||
import io.onedev.server.util.EditContext;
|
||||
import io.onedev.server.util.facade.GroupFacade;
|
||||
import io.onedev.server.util.facade.UserFacade;
|
||||
import org.apache.shiro.authz.Permission;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
@Entity
|
||||
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
|
||||
@ -92,7 +94,7 @@ public class Group extends AbstractEntity implements BasePermission {
|
||||
return !(boolean) EditContext.get().getInputValue("administrator");
|
||||
}
|
||||
|
||||
@Editable(order=300, name="Can Create Root Projects", description="Whether or not to allow creating root projects (project without parent)")
|
||||
@Editable(order=350, name="Can Create Root Projects", description="Whether or not to allow creating root projects (project without parent)")
|
||||
@ShowCondition("isAdministratorDisabled")
|
||||
public boolean isCreateRootProjects() {
|
||||
return createRootProjects;
|
||||
@ -145,7 +147,6 @@ public class Group extends AbstractEntity implements BasePermission {
|
||||
return members;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GroupFacade getFacade() {
|
||||
return new GroupFacade(getId(), getName());
|
||||
}
|
||||
|
||||
@ -929,7 +929,6 @@ public class Issue extends ProjectBelonging implements AttachmentStorageSupport
|
||||
return observables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IssueFacade getFacade() {
|
||||
return new IssueFacade(getId(), getProject().getId(), getNumber());
|
||||
}
|
||||
|
||||
@ -81,7 +81,6 @@ public class IssueComment extends EntityComment {
|
||||
this.revisions = revisions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IssueCommentFacade getFacade() {
|
||||
return new IssueCommentFacade(getId(), getIssue().getId(), getContent());
|
||||
}
|
||||
|
||||
@ -1,13 +1,28 @@
|
||||
package io.onedev.server.model;
|
||||
|
||||
import io.onedev.server.rest.annotation.Immutable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.*;
|
||||
import java.util.*;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.rest.annotation.Immutable;
|
||||
|
||||
@Entity
|
||||
@Table(
|
||||
@ -39,11 +54,14 @@ public class Iteration extends AbstractEntity {
|
||||
@Column(nullable=false)
|
||||
private String name;
|
||||
|
||||
@Api(description="Description of the iteration. May be null")
|
||||
@Column(length=MAX_DESCRIPTION_LEN)
|
||||
private String description;
|
||||
|
||||
@Api(description="Start of the iteration in epoc day. May be null")
|
||||
private Long startDay;
|
||||
|
||||
@Api(description="Due of the iteration in epoc day. May be null")
|
||||
private Long dueDay;
|
||||
|
||||
private boolean closed;
|
||||
|
||||
@ -1,17 +1,24 @@
|
||||
package io.onedev.server.model;
|
||||
|
||||
import static io.onedev.server.model.LabelSpec.PROP_NAME;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
import io.onedev.server.annotation.Color;
|
||||
import io.onedev.server.annotation.Editable;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import static io.onedev.server.model.LabelSpec.PROP_NAME;
|
||||
|
||||
@Entity
|
||||
@Table(indexes={@Index(columnList=PROP_NAME)})
|
||||
|
||||
@ -96,6 +96,14 @@ public class LinkSpec extends AbstractEntity {
|
||||
return opposite?getOpposite().getName():getName();
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
if (opposite != null) {
|
||||
return getName() + " - " + getOpposite().getName();
|
||||
} else {
|
||||
return getName();
|
||||
}
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
@ -162,7 +170,6 @@ public class LinkSpec extends AbstractEntity {
|
||||
return updaters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkSpecFacade getFacade() {
|
||||
return new LinkSpecFacade(getId(), getName(), getOpposite()!=null?getOpposite().getName():null);
|
||||
}
|
||||
|
||||
@ -1,10 +1,16 @@
|
||||
package io.onedev.server.model;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(
|
||||
indexes={@Index(columnList="o_user_id"), @Index(columnList="o_group_id")},
|
||||
@ -42,5 +48,5 @@ public class Membership extends AbstractEntity {
|
||||
public void setGroup(Group group) {
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
package io.onedev.server.model;
|
||||
|
||||
import static com.fasterxml.jackson.annotation.JsonProperty.Access.READ_ONLY;
|
||||
import static io.onedev.commons.utils.match.WildcardUtils.matchPath;
|
||||
import static io.onedev.server.model.Project.PROP_NAME;
|
||||
import static io.onedev.server.search.entity.EntitySort.Direction.DESCENDING;
|
||||
@ -58,8 +57,6 @@ import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Lists;
|
||||
@ -128,7 +125,6 @@ import io.onedev.server.model.support.pack.ProjectPackSetting;
|
||||
import io.onedev.server.model.support.pullrequest.MergeStrategy;
|
||||
import io.onedev.server.model.support.pullrequest.NamedPullRequestQuery;
|
||||
import io.onedev.server.model.support.pullrequest.ProjectPullRequestSetting;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.search.entity.SortField;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import io.onedev.server.util.ComponentContext;
|
||||
@ -251,17 +247,12 @@ public class Project extends AbstractEntity implements LabelSupport<ProjectLabel
|
||||
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
@JoinColumn(nullable=true)
|
||||
@Api(description="Represents the project from which this project is forked. Remove this property if "
|
||||
+ "the project is not a fork when create/update the project. May be null")
|
||||
private Project forkedFrom;
|
||||
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
@JoinColumn
|
||||
@Api(description="Represents the parent project. Remove this property if the project does not " +
|
||||
"have a parent project. May be null")
|
||||
private Project parent;
|
||||
|
||||
@JsonIgnore
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(unique=true, nullable=false)
|
||||
private ProjectLastEventDate lastEventDate;
|
||||
@ -269,21 +260,15 @@ public class Project extends AbstractEntity implements LabelSupport<ProjectLabel
|
||||
@Column(nullable=false)
|
||||
private String name;
|
||||
|
||||
@JsonProperty(access = READ_ONLY)
|
||||
@Column(nullable=false)
|
||||
private String path;
|
||||
|
||||
@JsonIgnore
|
||||
private int pathLen;
|
||||
|
||||
// SQL Server does not allow duplicate null values for unique column. So we use
|
||||
// special prefix to indicate null
|
||||
@JsonIgnore
|
||||
@Column(unique=true)
|
||||
private String key;
|
||||
|
||||
@Column(length=MAX_DESCRIPTION_LEN)
|
||||
@Api(description = "May be null")
|
||||
private String description;
|
||||
|
||||
@OneToMany(mappedBy="project")
|
||||
@ -298,23 +283,19 @@ public class Project extends AbstractEntity implements LabelSupport<ProjectLabel
|
||||
@OneToMany(mappedBy="project", cascade=CascadeType.REMOVE)
|
||||
private Collection<Pack> packs = new ArrayList<>();
|
||||
|
||||
@JsonIgnore
|
||||
@Lob
|
||||
@Column(nullable=false, length=65535)
|
||||
private ArrayList<BranchProtection> branchProtections = new ArrayList<>();
|
||||
|
||||
@JsonIgnore
|
||||
@Lob
|
||||
@Column(nullable=false, length=65535)
|
||||
private ArrayList<TagProtection> tagProtections = new ArrayList<>();
|
||||
|
||||
@JsonIgnore
|
||||
@Lob
|
||||
@Column(nullable=false, length=65535)
|
||||
private LinkedHashMap<String, ContributedProjectSetting> contributedSettings = new LinkedHashMap<>();
|
||||
|
||||
@Column(nullable=false)
|
||||
@JsonProperty(access = READ_ONLY)
|
||||
private Date createDate = new Date();
|
||||
|
||||
@OneToMany(mappedBy="targetProject", cascade=CascadeType.REMOVE)
|
||||
@ -387,6 +368,10 @@ public class Project extends AbstractEntity implements LabelSupport<ProjectLabel
|
||||
@OneToMany(mappedBy="project", cascade=CascadeType.REMOVE)
|
||||
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
|
||||
private Collection<Iteration> iterations = new ArrayList<>();
|
||||
|
||||
@OneToMany(mappedBy="project", cascade=CascadeType.REMOVE)
|
||||
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
|
||||
private Collection<Audit> audits = new ArrayList<>();
|
||||
|
||||
private boolean codeManagement = true;
|
||||
|
||||
@ -409,37 +394,30 @@ public class Project extends AbstractEntity implements LabelSupport<ProjectLabel
|
||||
@Column(unique=true)
|
||||
private String serviceDeskEmailAddress;
|
||||
|
||||
@JsonIgnore
|
||||
@Lob
|
||||
@Column(length=65535, nullable=false)
|
||||
private ProjectIssueSetting issueSetting = new ProjectIssueSetting();
|
||||
|
||||
@JsonIgnore
|
||||
@Lob
|
||||
@Column(length=65535, nullable=false)
|
||||
private ProjectBuildSetting buildSetting = new ProjectBuildSetting();
|
||||
|
||||
@JsonIgnore
|
||||
@Lob
|
||||
@Column(length=65535, nullable=false)
|
||||
private ProjectPullRequestSetting pullRequestSetting = new ProjectPullRequestSetting();
|
||||
|
||||
@JsonIgnore
|
||||
@Lob
|
||||
@Column(length=65535, nullable=false)
|
||||
private ProjectPackSetting packSetting = new ProjectPackSetting();
|
||||
|
||||
@JsonIgnore
|
||||
@Lob
|
||||
@Column(length=65535)
|
||||
private ArrayList<NamedCommitQuery> namedCommitQueries;
|
||||
|
||||
@JsonIgnore
|
||||
@Lob
|
||||
@Column(length=65535)
|
||||
private ArrayList<NamedCodeCommentQuery> namedCodeCommentQueries;
|
||||
|
||||
@JsonIgnore
|
||||
@Lob
|
||||
@Column(length=65535, nullable=false)
|
||||
private ArrayList<WebHook> webHooks = new ArrayList<>();
|
||||
@ -774,7 +752,6 @@ public class Project extends AbstractEntity implements LabelSupport<ProjectLabel
|
||||
return blobCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectFacade getFacade() {
|
||||
return new ProjectFacade(getId(), getName(), getKey(), getPath(), getServiceDeskEmailAddress(),
|
||||
isCodeManagement(), isIssueManagement(), getGitPackConfig(), lastEventDate.getId(),
|
||||
@ -1088,15 +1065,13 @@ public class Project extends AbstractEntity implements LabelSupport<ProjectLabel
|
||||
"the system email address in mail setting definition. Emails sent to this address will be " +
|
||||
"created as issues in this project. The default value takes form of "
|
||||
+ "<tt><system email address name>+<project path>@<system email address domain></tt>")
|
||||
@Nullable
|
||||
@JsonProperty
|
||||
@Email
|
||||
@Pattern(regexp = "[^~]+@.+", message = "character '~' not allowed in name part")
|
||||
public String getServiceDeskEmailAddress() {
|
||||
return serviceDeskEmailAddress;
|
||||
}
|
||||
|
||||
public void setServiceDeskEmailAddress(@Nullable String serviceDeskEmailAddress) {
|
||||
public void setServiceDeskEmailAddress(String serviceDeskEmailAddress) {
|
||||
this.serviceDeskEmailAddress = serviceDeskEmailAddress;
|
||||
}
|
||||
|
||||
@ -2042,4 +2017,18 @@ public class Project extends AbstractEntity implements LabelSupport<ProjectLabel
|
||||
return decodeRepoNameAsPath(replace(text, FAKED_GITHUB_REPO_OWNER + "/", ""));
|
||||
}
|
||||
|
||||
public static Collection<Project> getIndependents(Collection<Project> projects) {
|
||||
Collection<Project> independents = new HashSet<>(projects);
|
||||
for (Iterator<Project> it = independents.iterator(); it.hasNext(); ) {
|
||||
Project independent = it.next();
|
||||
for (Project each : independents) {
|
||||
if (!each.equals(independent) && each.isSelfOrAncestorOf(independent)) {
|
||||
it.remove();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return independents;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -70,7 +70,6 @@ public class PullRequestComment extends EntityComment {
|
||||
this.revisions = revisions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PullRequestCommentFacade getFacade() {
|
||||
return new PullRequestCommentFacade(getId(), getRequest().getId(), getContent());
|
||||
}
|
||||
|
||||
@ -1,6 +1,29 @@
|
||||
package io.onedev.server.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.Lob;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.apache.shiro.authz.Permission;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.annotation.ChoiceProvider;
|
||||
import io.onedev.server.annotation.Editable;
|
||||
@ -8,21 +31,40 @@ import io.onedev.server.annotation.RoleName;
|
||||
import io.onedev.server.annotation.ShowCondition;
|
||||
import io.onedev.server.entitymanager.LinkSpecManager;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.model.support.role.*;
|
||||
import io.onedev.server.security.permission.*;
|
||||
import io.onedev.server.model.support.role.AllIssueFields;
|
||||
import io.onedev.server.model.support.role.CodePrivilege;
|
||||
import io.onedev.server.model.support.role.IssueFieldSet;
|
||||
import io.onedev.server.model.support.role.JobPrivilege;
|
||||
import io.onedev.server.model.support.role.PackPrivilege;
|
||||
import io.onedev.server.security.permission.AccessBuild;
|
||||
import io.onedev.server.security.permission.AccessBuildLog;
|
||||
import io.onedev.server.security.permission.AccessBuildPipeline;
|
||||
import io.onedev.server.security.permission.AccessBuildReports;
|
||||
import io.onedev.server.security.permission.AccessConfidentialIssues;
|
||||
import io.onedev.server.security.permission.AccessProject;
|
||||
import io.onedev.server.security.permission.AccessTimeTracking;
|
||||
import io.onedev.server.security.permission.BasePermission;
|
||||
import io.onedev.server.security.permission.CreateChildren;
|
||||
import io.onedev.server.security.permission.EditIssueField;
|
||||
import io.onedev.server.security.permission.EditIssueLink;
|
||||
import io.onedev.server.security.permission.JobPermission;
|
||||
import io.onedev.server.security.permission.ManageBuilds;
|
||||
import io.onedev.server.security.permission.ManageCodeComments;
|
||||
import io.onedev.server.security.permission.ManageIssues;
|
||||
import io.onedev.server.security.permission.ManageJob;
|
||||
import io.onedev.server.security.permission.ManageProject;
|
||||
import io.onedev.server.security.permission.ManagePullRequests;
|
||||
import io.onedev.server.security.permission.ReadCode;
|
||||
import io.onedev.server.security.permission.ReadPack;
|
||||
import io.onedev.server.security.permission.RunJob;
|
||||
import io.onedev.server.security.permission.ScheduleIssues;
|
||||
import io.onedev.server.security.permission.UploadCache;
|
||||
import io.onedev.server.security.permission.WriteCode;
|
||||
import io.onedev.server.security.permission.WritePack;
|
||||
import io.onedev.server.util.EditContext;
|
||||
import io.onedev.server.util.facade.RoleFacade;
|
||||
import io.onedev.server.util.facade.UserFacade;
|
||||
import io.onedev.server.web.util.WicketUtils;
|
||||
import org.apache.shiro.authz.Permission;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author robin
|
||||
@ -37,6 +79,7 @@ public class Role extends AbstractEntity implements BasePermission {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String PROP_NAME = "name";
|
||||
|
||||
public static final Long OWNER_ID = 1L;
|
||||
|
||||
@Column(nullable=false, unique=true)
|
||||
@ -272,10 +315,7 @@ public class Role extends AbstractEntity implements BasePermission {
|
||||
private static Map<String, String> getIssueLinkDisplayNames() {
|
||||
Map<String, String> choices = new LinkedHashMap<>();
|
||||
for (LinkSpec link: OneDev.getInstance(LinkSpecManager.class).queryAndSort()) {
|
||||
if (link.getOpposite() != null)
|
||||
choices.put(link.getName(), link.getName() + " - " + link.getOpposite().getName());
|
||||
else
|
||||
choices.put(link.getName(), link.getName());
|
||||
choices.put(link.getName(), link.getDisplayName());
|
||||
}
|
||||
return choices;
|
||||
}
|
||||
@ -338,7 +378,6 @@ public class Role extends AbstractEntity implements BasePermission {
|
||||
this.linkAuthorizations = linkAuthorizations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoleFacade getFacade() {
|
||||
return new RoleFacade(getId(), getName());
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ public class Setting extends AbstractEntity {
|
||||
GROOVY_SCRIPTS, PULL_REQUEST, BUILD, PACK, PROJECT, SSH, GPG, SSO_CONNECTORS,
|
||||
EMAIL_TEMPLATES, CONTRIBUTED_SETTINGS, SERVICE_DESK_SETTING,
|
||||
AGENT, PERFORMANCE, BRANDING, CLUSTER_SETTING, SUBSCRIPTION_DATA, ALERT,
|
||||
SYSTEM_UUID
|
||||
SYSTEM_UUID, AUDIT
|
||||
};
|
||||
|
||||
@Column(nullable=false, unique=true)
|
||||
|
||||
@ -1,26 +1,36 @@
|
||||
package io.onedev.server.model;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import io.onedev.commons.utils.StringUtils;
|
||||
import io.onedev.server.annotation.ClassValidating;
|
||||
import io.onedev.server.annotation.Editable;
|
||||
import io.onedev.server.annotation.Multiline;
|
||||
import io.onedev.server.annotation.OmitName;
|
||||
import io.onedev.server.ssh.SshKeyUtils;
|
||||
import io.onedev.server.validation.Validatable;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
|
||||
import org.apache.sshd.common.config.keys.KeyUtils;
|
||||
import org.apache.sshd.common.digest.BuiltinDigests;
|
||||
import org.hibernate.annotations.Cache;
|
||||
import org.hibernate.annotations.CacheConcurrencyStrategy;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.*;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
import io.onedev.commons.utils.StringUtils;
|
||||
import io.onedev.server.annotation.ClassValidating;
|
||||
import io.onedev.server.annotation.Editable;
|
||||
import io.onedev.server.annotation.Multiline;
|
||||
import io.onedev.server.annotation.OmitName;
|
||||
import io.onedev.server.rest.annotation.Immutable;
|
||||
import io.onedev.server.ssh.SshKeyUtils;
|
||||
import io.onedev.server.validation.Validatable;
|
||||
|
||||
@Editable
|
||||
@Entity
|
||||
@ -44,6 +54,7 @@ public class SshKey extends AbstractEntity implements Validatable {
|
||||
|
||||
@ManyToOne(fetch=FetchType.LAZY)
|
||||
@JoinColumn(nullable=false)
|
||||
@Immutable
|
||||
private User owner;
|
||||
|
||||
@Editable(name="OpenSSH Public Key", placeholder="OpenSSH public key begins with 'ssh-rsa', "
|
||||
@ -93,7 +104,7 @@ public class SshKey extends AbstractEntity implements Validatable {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void fingerprint() {
|
||||
public void generateFingerprint() {
|
||||
try {
|
||||
PublicKey pubEntry = SshKeyUtils.decodeSshPublicKey(content);
|
||||
fingerprint = KeyUtils.getFingerPrint(BuiltinDigests.sha256, pubEntry);
|
||||
|
||||
@ -1076,7 +1076,6 @@ public class User extends AbstractEntity implements AuthenticationInfo {
|
||||
return publicEmailAddress.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserFacade getFacade() {
|
||||
return new UserFacade(getId(), getName(), getFullName(), isServiceAccount(), isDisabled());
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@ public class CodeAnalysisSetting implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Api(description = "May be null")
|
||||
@Api(description = "<code>null</code> to inherit from parent project, or all files if no parent")
|
||||
private String analysisFiles;
|
||||
|
||||
@Editable(order=100, name="Files to Be Analyzed", placeholder="Inherit from parent", rootPlaceholder ="All files", description="OneDev analyzes repository files for code search, "
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
package io.onedev.server.model.support;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
import io.onedev.server.model.AbstractEntity;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.util.facade.ProjectBelongingFacade;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
|
||||
@MappedSuperclass
|
||||
public abstract class ProjectBelonging extends AbstractEntity {
|
||||
@ -12,15 +11,5 @@ public abstract class ProjectBelonging extends AbstractEntity {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public abstract Project getProject();
|
||||
|
||||
@Override
|
||||
public ProjectBelongingFacade getOldVersion() {
|
||||
return (ProjectBelongingFacade) super.getOldVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProjectBelongingFacade getFacade() {
|
||||
return new ProjectBelongingFacade(getId(), getProject().getId());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
package io.onedev.server.model.support.administration;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
|
||||
import io.onedev.server.annotation.Editable;
|
||||
import io.onedev.server.annotation.OmitName;
|
||||
|
||||
@Editable
|
||||
public class AuditSetting implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String PROP_PRESERVE_DAYS = "preserveDays";
|
||||
|
||||
private int preserveDays = 365;
|
||||
|
||||
@Editable(order = 100, name="Preserve Days", description = "Audit log will be preserved for the specified number of days. " +
|
||||
"This setting applies to all audit events, including system level and project level")
|
||||
@OmitName
|
||||
@Min(value = 7, message = "At least 7 days should be specified")
|
||||
public int getPreserveDays() {
|
||||
return preserveDays;
|
||||
}
|
||||
|
||||
public void setPreserveDays(int preserveDays) {
|
||||
this.preserveDays = preserveDays;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,19 @@
|
||||
package io.onedev.server.model.support.administration;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.ServerConfig;
|
||||
import io.onedev.server.annotation.ClassValidating;
|
||||
@ -13,16 +26,6 @@ import io.onedev.server.git.location.SystemGit;
|
||||
import io.onedev.server.util.EditContext;
|
||||
import io.onedev.server.validation.Validatable;
|
||||
import io.onedev.server.web.util.WicketUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
@Editable
|
||||
@ClassValidating
|
||||
@ -47,7 +50,7 @@ public class SystemSetting implements Serializable, Validatable {
|
||||
private GitLocation gitLocation = new SystemGit();
|
||||
|
||||
private CurlLocation curlLocation = new SystemCurl();
|
||||
|
||||
|
||||
private boolean disableAutoUpdateCheck;
|
||||
|
||||
private boolean disableDashboard;
|
||||
|
||||
@ -12,16 +12,16 @@ public class GitPackConfig implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Api(description = "May be null", example = "0")
|
||||
@Api(description = "<code>null</code> for default setting", example = "0")
|
||||
private String windowMemory;
|
||||
|
||||
@Api(description = "May be null", example="1g")
|
||||
@Api(description = "<code>null</code> for default setting", example="1g")
|
||||
private String packSizeLimit;
|
||||
|
||||
@Api(description = "May be null", example="0")
|
||||
@Api(description = "<code>null</code> for default setting", example="0")
|
||||
private String threads;
|
||||
|
||||
@Api(description = "May be null", example="10")
|
||||
@Api(description = "<code>null</code> for default setting", example="10")
|
||||
private String window;
|
||||
|
||||
@Editable(order = 100, placeholder = "Use default", description = "Optionally specify value of git config " +
|
||||
|
||||
@ -1,6 +1,25 @@
|
||||
package io.onedev.server.model.support.issue;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.unbescape.html.HtmlEscape;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.thoughtworks.xstream.annotations.XStreamOmitField;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.annotation.ChoiceProvider;
|
||||
import io.onedev.server.annotation.Editable;
|
||||
@ -19,15 +38,12 @@ import io.onedev.server.model.support.issue.field.spec.userchoicefield.UserChoic
|
||||
import io.onedev.server.search.entity.issue.IssueQueryUpdater;
|
||||
import io.onedev.server.util.EditContext;
|
||||
import io.onedev.server.util.usage.Usage;
|
||||
import io.onedev.server.web.component.issue.workflowreconcile.*;
|
||||
import io.onedev.server.web.component.issue.workflowreconcile.ReconcileUtils;
|
||||
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.component.issue.workflowreconcile.UndefinedStateResolution;
|
||||
import io.onedev.server.web.component.stringchoice.StringChoiceProvider;
|
||||
import org.unbescape.html.HtmlEscape;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
@Editable
|
||||
public class BoardSpec implements Serializable {
|
||||
@ -52,6 +68,8 @@ public class BoardSpec implements Serializable {
|
||||
|
||||
private List<String> displayLinks = new ArrayList<>();
|
||||
|
||||
@XStreamOmitField
|
||||
@JsonIgnore
|
||||
private List<String> editColumns;
|
||||
|
||||
@Editable(order=100)
|
||||
|
||||
@ -1,18 +1,30 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import io.onedev.server.entitymanager.AccessTokenAuthorizationManager;
|
||||
import io.onedev.server.model.AccessTokenAuthorization;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import static io.onedev.server.security.SecurityUtils.canManageProject;
|
||||
import static io.onedev.server.security.SecurityUtils.getAuthUser;
|
||||
import static io.onedev.server.security.SecurityUtils.isAdministrator;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import static io.onedev.server.security.SecurityUtils.*;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AccessTokenAuthorizationManager;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.model.AccessTokenAuthorization;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
|
||||
@Api(order=9500, description = "This resource manages project authorizations of access tokens. Note that " +
|
||||
"project authorizations will not take effect if option <tt>hasOwnerPermissions</tt> is enabled " +
|
||||
@ -25,15 +37,18 @@ public class AccessTokenAuthorizationResource {
|
||||
|
||||
private final AccessTokenAuthorizationManager accessTokenAuthorizationManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public AccessTokenAuthorizationResource(AccessTokenAuthorizationManager accessTokenAuthorizationManager) {
|
||||
public AccessTokenAuthorizationResource(AccessTokenAuthorizationManager accessTokenAuthorizationManager, AuditManager auditManager) {
|
||||
this.accessTokenAuthorizationManager = accessTokenAuthorizationManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100, description = "Get access token authorization of specified id")
|
||||
@Path("/{authorizationId}")
|
||||
@GET
|
||||
public AccessTokenAuthorization get(@PathParam("authorizationId") Long authorizationId) {
|
||||
public AccessTokenAuthorization getAuthorization(@PathParam("authorizationId") Long authorizationId) {
|
||||
var authorization = accessTokenAuthorizationManager.load(authorizationId);
|
||||
var owner = authorization.getToken().getOwner();
|
||||
if (!isAdministrator() && !owner.equals(getAuthUser()))
|
||||
@ -43,38 +58,53 @@ public class AccessTokenAuthorizationResource {
|
||||
|
||||
@Api(order=200, description="Create access token authorization. Access token owner should have permission to manage authorized project")
|
||||
@POST
|
||||
public Long create(@NotNull AccessTokenAuthorization authorization) {
|
||||
public Long createAuthorization(@NotNull AccessTokenAuthorization authorization) {
|
||||
var owner = authorization.getToken().getOwner();
|
||||
if (!isAdministrator() && !owner.equals(getAuthUser())
|
||||
|| !canManageProject(owner.asSubject(), authorization.getProject())) {
|
||||
if (!isAdministrator() && !owner.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
if (!canManageProject(owner.asSubject(), authorization.getProject()))
|
||||
throw new BadRequestException("Access token owner should have permission to manage authorized project");
|
||||
|
||||
accessTokenAuthorizationManager.createOrUpdate(authorization);
|
||||
if (!getAuthUser().equals(owner)) {
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(authorization).toXML();
|
||||
auditManager.audit(null, "created access token authorization for account \"" + owner.getName() + "\" via RESTful API", null, newAuditContent);
|
||||
}
|
||||
return authorization.getId();
|
||||
}
|
||||
|
||||
@Api(order=250, description="Update access authorization of specified id. Access token owner should have permission to manage authorized project")
|
||||
@Path("/{authorizationId}")
|
||||
@POST
|
||||
public Response update(@PathParam("authorizationId") Long authorizationId, @NotNull AccessTokenAuthorization authorization) {
|
||||
public Response updateAuthorization(@PathParam("authorizationId") Long authorizationId, @NotNull AccessTokenAuthorization authorization) {
|
||||
var owner = authorization.getToken().getOwner();
|
||||
if (!isAdministrator() && !owner.equals(getAuthUser())
|
||||
|| !canManageProject(owner.asSubject(), authorization.getProject())) {
|
||||
if (!isAdministrator() && !owner.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
}
|
||||
if (!canManageProject(owner.asSubject(), authorization.getProject()))
|
||||
throw new BadRequestException("Access token owner should have permission to manage authorized project");
|
||||
|
||||
accessTokenAuthorizationManager.createOrUpdate(authorization);
|
||||
if (!getAuthUser().equals(owner)) {
|
||||
var oldAuditContent = authorization.getOldVersion().toXML();
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(authorization).toXML();
|
||||
auditManager.audit(null, "changed access token authorization for account \"" + owner.getName() + "\" via RESTful API", oldAuditContent, newAuditContent);
|
||||
}
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@Api(order=300, description = "Delete access token authorization of specified id")
|
||||
@Path("/{authorizationId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("authorizationId") Long authorizationId) {
|
||||
public Response deleteAuthorization(@PathParam("authorizationId") Long authorizationId) {
|
||||
var authorization = accessTokenAuthorizationManager.load(authorizationId);
|
||||
var owner = authorization.getToken().getOwner();
|
||||
if (!isAdministrator() && !owner.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
accessTokenAuthorizationManager.delete(authorization);
|
||||
if (!getAuthUser().equals(owner)) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(authorization).toXML();
|
||||
auditManager.audit(null, "deleted access token authorization for account \"" + owner.getName() + "\" via RESTful API", oldAuditContent, null);
|
||||
}
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -1,23 +1,34 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.entitymanager.AccessTokenManager;
|
||||
import io.onedev.server.model.AccessToken;
|
||||
import io.onedev.server.model.AccessTokenAuthorization;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import static io.onedev.server.security.SecurityUtils.getAuthUser;
|
||||
import static io.onedev.server.security.SecurityUtils.isAdministrator;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.Collection;
|
||||
|
||||
import static io.onedev.server.security.SecurityUtils.getAuthUser;
|
||||
import static io.onedev.server.security.SecurityUtils.isAdministrator;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AccessTokenManager;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.model.AccessToken;
|
||||
import io.onedev.server.model.AccessTokenAuthorization;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
|
||||
@Api(order=5030)
|
||||
@Path("/access-tokens")
|
||||
@ -27,16 +38,19 @@ import static io.onedev.server.security.SecurityUtils.isAdministrator;
|
||||
public class AccessTokenResource {
|
||||
|
||||
private final AccessTokenManager accessTokenManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public AccessTokenResource(AccessTokenManager accessTokenManager) {
|
||||
public AccessTokenResource(AccessTokenManager accessTokenManager, AuditManager auditManager) {
|
||||
this.accessTokenManager = accessTokenManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{accessTokenId}")
|
||||
@GET
|
||||
public AccessToken get(@PathParam("accessTokenId") Long accessTokenId) {
|
||||
public AccessToken getToken(@PathParam("accessTokenId") Long accessTokenId) {
|
||||
var accessToken = accessTokenManager.load(accessTokenId);
|
||||
if (!isAdministrator() && !accessToken.getOwner().equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
@ -55,7 +69,7 @@ public class AccessTokenResource {
|
||||
|
||||
@Api(order=200, description="Create access token")
|
||||
@POST
|
||||
public Long create(@NotNull @Valid AccessToken accessToken) {
|
||||
public Long createToken(@NotNull @Valid AccessToken accessToken) {
|
||||
var owner = accessToken.getOwner();
|
||||
if (!isAdministrator() && !owner.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
@ -64,35 +78,55 @@ public class AccessTokenResource {
|
||||
|
||||
if (accessTokenManager.findByOwnerAndName(owner, accessToken.getName()) != null)
|
||||
throw new ExplicitException("Name already used by another access token of the owner");
|
||||
|
||||
|
||||
accessTokenManager.createOrUpdate(accessToken);
|
||||
|
||||
if (!getAuthUser().equals(owner)) {
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(accessToken.getFacade()).toXML();
|
||||
auditManager.audit(null, "created access token \"" + accessToken.getName() + "\" for account \"" + owner.getName() + "\" via RESTful API",
|
||||
null, newAuditContent);
|
||||
}
|
||||
|
||||
return accessToken.getId();
|
||||
}
|
||||
|
||||
@Api(order=250, description="Update access token")
|
||||
@Path("/{accessTokenId}")
|
||||
@POST
|
||||
public Response update(@PathParam("accessTokenId") Long accessTokenId, @NotNull @Valid AccessToken accessToken) {
|
||||
public Response updateToken(@PathParam("accessTokenId") Long accessTokenId, @NotNull @Valid AccessToken accessToken) {
|
||||
var owner = accessToken.getOwner();
|
||||
if (!isAdministrator() && !owner.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
|
||||
var accessTokenWithSameName = accessTokenManager.findByOwnerAndName(owner, accessToken.getName());
|
||||
if (accessTokenWithSameName != null && !accessTokenWithSameName.equals(accessToken))
|
||||
throw new ExplicitException("Name already used by another access token of the owner");
|
||||
throw new BadRequestException("Name already used by another access token of the owner");
|
||||
|
||||
accessTokenManager.createOrUpdate(accessToken);
|
||||
|
||||
if (!getAuthUser().equals(owner)) {
|
||||
var oldAuditContent = accessToken.getOldVersion().toXML();
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(accessToken).toXML();
|
||||
auditManager.audit(null, "changed access token \"" + accessToken.getName() + "\" for account \"" + owner.getName() + "\" via RESTful API",
|
||||
oldAuditContent, newAuditContent);
|
||||
}
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@Api(order=300)
|
||||
@Path("/{accessTokenId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("accessTokenId") Long accessTokenId) {
|
||||
public Response deleteToken(@PathParam("accessTokenId") Long accessTokenId) {
|
||||
var accessToken = accessTokenManager.load(accessTokenId);
|
||||
if (!isAdministrator() && !accessToken.getOwner().equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
accessTokenManager.delete(accessToken);
|
||||
|
||||
if (!getAuthUser().equals(accessToken.getOwner())) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(accessToken.getFacade()).toXML();
|
||||
auditManager.audit(null, "deleted access token \"" + accessToken.getName() + "\" for account \"" + accessToken.getOwner().getName() + "\" via RESTful API",
|
||||
oldAuditContent, null);
|
||||
}
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -18,11 +18,13 @@ import javax.ws.rs.core.Response;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AgentAttributeManager;
|
||||
import io.onedev.server.entitymanager.AgentManager;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.model.Agent;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.rest.InvalidParamException;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.search.entity.agent.AgentQuery;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
|
||||
@ -37,16 +39,19 @@ public class AgentResource {
|
||||
|
||||
private final AgentAttributeManager agentAttributeManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public AgentResource(AgentManager agentManager, AgentAttributeManager agentAttributeManager) {
|
||||
public AgentResource(AgentManager agentManager, AgentAttributeManager agentAttributeManager, AuditManager auditManager) {
|
||||
this.agentManager = agentManager;
|
||||
this.agentAttributeManager = agentAttributeManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{agentId}")
|
||||
@GET
|
||||
public Agent getBasicInfo(@PathParam("agentId") Long agentId) {
|
||||
public Agent getAgent(@PathParam("agentId") Long agentId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
return agentManager.load(agentId);
|
||||
@ -63,7 +68,7 @@ public class AgentResource {
|
||||
|
||||
@Api(order=300)
|
||||
@GET
|
||||
public List<Agent> queryBasicInfo(
|
||||
public List<Agent> queryAgents(
|
||||
@QueryParam("query") @Api(description="Syntax of this query is the same as in <a href='/~administration/agents'>agent management page</a>", example="\"Name\" is \"agentName\"") String query,
|
||||
@QueryParam("offset") @Api(example="0") int offset,
|
||||
@QueryParam("count") @Api(example="100") int count) {
|
||||
@ -89,8 +94,12 @@ public class AgentResource {
|
||||
Agent agent = agentManager.load(agentId);
|
||||
if (!agent.isOnline())
|
||||
throw new ExplicitException("Unable to update attributes as agent is offline");
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(agent.getAttributeMap()).toXML();
|
||||
agentAttributeManager.syncAttributes(agent, attributes);
|
||||
agentManager.attributesUpdated(agent);
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(agent.getAttributeMap()).toXML();
|
||||
auditManager.audit(null, "changed attributes of agent \"" + agent.getName() + "\" via RESTful API",
|
||||
oldAuditContent, newAuditContent);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -1,23 +1,33 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import io.onedev.server.entitymanager.AgentManager;
|
||||
import io.onedev.server.entitymanager.AgentTokenManager;
|
||||
import io.onedev.server.model.Agent;
|
||||
import io.onedev.server.model.AgentToken;
|
||||
import io.onedev.server.persistence.dao.EntityCriteria;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.rest.InvalidParamException;
|
||||
import io.onedev.server.rest.resource.support.RestConstants;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
|
||||
import io.onedev.server.entitymanager.AgentManager;
|
||||
import io.onedev.server.entitymanager.AgentTokenManager;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.model.Agent;
|
||||
import io.onedev.server.model.AgentToken;
|
||||
import io.onedev.server.persistence.dao.EntityCriteria;
|
||||
import io.onedev.server.rest.InvalidParamException;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.rest.resource.support.RestConstants;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
|
||||
@Api(order=10100)
|
||||
@Path("/agent-tokens")
|
||||
@ -30,22 +40,25 @@ public class AgentTokenResource {
|
||||
|
||||
private final AgentManager agentManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public AgentTokenResource(AgentTokenManager tokenManager, AgentManager agentManager) {
|
||||
public AgentTokenResource(AgentTokenManager tokenManager, AgentManager agentManager, AuditManager auditManager) {
|
||||
this.tokenManager = tokenManager;
|
||||
this.agentManager = agentManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{tokenId}")
|
||||
@GET
|
||||
public AgentToken getBasicInfo(@PathParam("tokenId") Long tokenId) {
|
||||
public AgentToken getToken(@PathParam("tokenId") Long tokenId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
return tokenManager.load(tokenId);
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Api(order=100, description="Get agent using specified token")
|
||||
@Path("/{tokenId}/agent")
|
||||
@GET
|
||||
public Agent getAgent(@PathParam("tokenId") Long tokenId) {
|
||||
@ -57,7 +70,7 @@ public class AgentTokenResource {
|
||||
|
||||
@Api(order=200)
|
||||
@GET
|
||||
public List<AgentToken> queryBasicInfo(@QueryParam("value") String value,
|
||||
public List<AgentToken> queryTokens(@QueryParam("value") String value,
|
||||
@QueryParam("offset") @Api(example="0") int offset,
|
||||
@QueryParam("count") @Api(example="100") int count) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
@ -76,21 +89,23 @@ public class AgentTokenResource {
|
||||
|
||||
@Api(order=500, description="Create new token")
|
||||
@POST
|
||||
public Long create() {
|
||||
public Long createToken() {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
AgentToken token = new AgentToken();
|
||||
tokenManager.createOrUpdate(token);
|
||||
auditManager.audit(null, "created agent token via RESTful API", null, null);
|
||||
return token.getId();
|
||||
}
|
||||
|
||||
@Api(order=600)
|
||||
@Path("/{tokenId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("tokenId") Long tokenId) {
|
||||
public Response deleteToken(@PathParam("tokenId") Long tokenId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
tokenManager.delete(tokenManager.load(tokenId));
|
||||
auditManager.audit(null, "deleted agent token via RESTful API", null, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ public class ArtifactResource {
|
||||
|
||||
private final BuildManager buildManager;
|
||||
|
||||
private final ClusterManager clusterManager;
|
||||
private final ClusterManager clusterManager;
|
||||
|
||||
@Inject
|
||||
public ArtifactResource(ProjectManager projectManager, BuildManager buildManager,
|
||||
|
||||
@ -15,6 +15,8 @@ import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.BaseAuthorizationManager;
|
||||
import io.onedev.server.model.BaseAuthorization;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
@ -29,15 +31,18 @@ public class BaseAuthorizationResource {
|
||||
|
||||
private final BaseAuthorizationManager authorizationManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public BaseAuthorizationResource(BaseAuthorizationManager authorizationManager) {
|
||||
public BaseAuthorizationResource(BaseAuthorizationManager authorizationManager, AuditManager auditManager) {
|
||||
this.authorizationManager = authorizationManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100, description = "Get base authorization of specified id")
|
||||
@Path("/{authorizationId}")
|
||||
@GET
|
||||
public BaseAuthorization get(@PathParam("authorizationId") Long authorizationId) {
|
||||
public BaseAuthorization getAuthorization(@PathParam("authorizationId") Long authorizationId) {
|
||||
var authorization = authorizationManager.load(authorizationId);
|
||||
if (!SecurityUtils.canManageProject(authorization.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
@ -46,21 +51,25 @@ public class BaseAuthorizationResource {
|
||||
|
||||
@Api(order=200, description="Create base authorization")
|
||||
@POST
|
||||
public Long create(@NotNull BaseAuthorization authorization) {
|
||||
public Long createAuthorization(@NotNull BaseAuthorization authorization) {
|
||||
if (!SecurityUtils.canManageProject(authorization.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
authorizationManager.create(authorization);
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(authorization).toXML();
|
||||
auditManager.audit(authorization.getProject(), "created base authorization via RESTful API", null, newAuditContent);
|
||||
return authorization.getId();
|
||||
}
|
||||
|
||||
@Api(order=300, description = "Delete base authorization of specified id")
|
||||
@Path("/{authorizationId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("authorizationId") Long authorizationId) {
|
||||
public Response deleteAuthorization(@PathParam("authorizationId") Long authorizationId) {
|
||||
var authorization = authorizationManager.load(authorizationId);
|
||||
if (!SecurityUtils.canManageProject(authorization.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
authorizationManager.delete(authorization);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(authorization).toXML();
|
||||
auditManager.audit(authorization.getProject(), "deleted base authorization via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ public class BuildLabelResource {
|
||||
|
||||
@Api(order=200, description="Create build label")
|
||||
@POST
|
||||
public Long create(@NotNull BuildLabel buildLabel) {
|
||||
public Long createLabel(@NotNull BuildLabel buildLabel) {
|
||||
if (!SecurityUtils.canManageBuild(buildLabel.getBuild()))
|
||||
throw new UnauthorizedException();
|
||||
buildLabelManager.create(buildLabel);
|
||||
@ -39,7 +39,7 @@ public class BuildLabelResource {
|
||||
@Api(order=300)
|
||||
@Path("/{buildLabelId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("buildLabelId") Long buildLabelId) {
|
||||
public Response deleteLabel(@PathParam("buildLabelId") Long buildLabelId) {
|
||||
BuildLabel buildLabel = buildLabelManager.load(buildLabelId);
|
||||
if (!SecurityUtils.canManageBuild(buildLabel.getBuild()))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
@ -17,18 +17,20 @@ import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import io.onedev.server.model.BuildLabel;
|
||||
import org.apache.commons.lang3.SerializationUtils;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.server.buildspec.param.spec.ParamSpec;
|
||||
import io.onedev.server.buildspecmodel.inputspec.SecretInput;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.BuildManager;
|
||||
import io.onedev.server.model.Build;
|
||||
import io.onedev.server.model.BuildDependence;
|
||||
import io.onedev.server.model.BuildLabel;
|
||||
import io.onedev.server.model.BuildParam;
|
||||
import io.onedev.server.buildspecmodel.inputspec.SecretInput;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.rest.InvalidParamException;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.rest.resource.support.RestConstants;
|
||||
import io.onedev.server.search.entity.build.BuildQuery;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
@ -44,15 +46,18 @@ public class BuildResource {
|
||||
|
||||
private final BuildManager buildManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public BuildResource(BuildManager buildManager) {
|
||||
public BuildResource(BuildManager buildManager, AuditManager auditManager) {
|
||||
this.buildManager = buildManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{buildId}")
|
||||
@GET
|
||||
public Build getBasicInfo(@PathParam("buildId") Long buildId) {
|
||||
public Build getBuild(@PathParam("buildId") Long buildId) {
|
||||
Build build = buildManager.load(buildId);
|
||||
if (!SecurityUtils.canAccessBuild(build))
|
||||
throw new UnauthorizedException();
|
||||
@ -118,7 +123,7 @@ public class BuildResource {
|
||||
|
||||
@Api(order=600)
|
||||
@GET
|
||||
public List<Build> queryBasicInfo(
|
||||
public List<Build> queryBuilds(
|
||||
@QueryParam("query") @Api(description="Syntax of this query is the same as in <a href='/~builds'>builds page</a>", example="\"Job\" is \"Release\"") String query,
|
||||
@QueryParam("offset") @Api(example="0") int offset,
|
||||
@QueryParam("count") @Api(example="100") int count) {
|
||||
@ -139,11 +144,13 @@ public class BuildResource {
|
||||
@Api(order=700)
|
||||
@Path("/{buildId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("buildId") Long buildId) {
|
||||
public Response deleteBuild(@PathParam("buildId") Long buildId) {
|
||||
Build build = buildManager.load(buildId);
|
||||
if (!SecurityUtils.canManageBuild(build))
|
||||
throw new UnauthorizedException();
|
||||
buildManager.delete(build);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(build).toXML();
|
||||
auditManager.audit(build.getProject(), "deleted build \"" + build.getReference().toString(build.getProject()) + "\" via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -1,16 +1,24 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.CodeCommentManager;
|
||||
import io.onedev.server.model.CodeComment;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
@Api(order=4700)
|
||||
@Path("/code-comments")
|
||||
@ -21,15 +29,18 @@ public class CodeCommentResource {
|
||||
|
||||
private final CodeCommentManager commentManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public CodeCommentResource(CodeCommentManager commentManager) {
|
||||
public CodeCommentResource(CodeCommentManager commentManager, AuditManager auditManager) {
|
||||
this.commentManager = commentManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{commentId}")
|
||||
@GET
|
||||
public CodeComment get(@PathParam("commentId") Long commentId) {
|
||||
public CodeComment getComment(@PathParam("commentId") Long commentId) {
|
||||
var comment = commentManager.load(commentId);
|
||||
if (!SecurityUtils.canReadCode(comment.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
@ -39,11 +50,13 @@ public class CodeCommentResource {
|
||||
@Api(order=200)
|
||||
@Path("/{commentId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("commentId") Long commentId) {
|
||||
public Response deleteComment(@PathParam("commentId") Long commentId) {
|
||||
var comment = commentManager.load(commentId);
|
||||
if (!SecurityUtils.canModifyOrDelete(comment))
|
||||
throw new UnauthorizedException();
|
||||
commentManager.delete(comment);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(comment).toXML();
|
||||
auditManager.audit(comment.getProject(), "deleted code comment on file \"" + comment.getMark().getPath() + "\" via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -1,22 +1,30 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.entitymanager.EmailAddressManager;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.model.EmailAddress;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import static io.onedev.server.security.SecurityUtils.getAuthUser;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import static io.onedev.server.security.SecurityUtils.getAuthUser;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.EmailAddressManager;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.model.EmailAddress;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
|
||||
@Api(order=5010)
|
||||
@Path("/email-addresses")
|
||||
@ -29,16 +37,19 @@ public class EmailAddressResource {
|
||||
|
||||
private final SettingManager settingManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public EmailAddressResource(EmailAddressManager emailAddressManager, SettingManager settingManager) {
|
||||
public EmailAddressResource(EmailAddressManager emailAddressManager, SettingManager settingManager, AuditManager auditManager) {
|
||||
this.emailAddressManager = emailAddressManager;
|
||||
this.settingManager = settingManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{emailAddressId}")
|
||||
@GET
|
||||
public EmailAddress get(@PathParam("emailAddressId") Long emailAddressId) {
|
||||
public EmailAddress getEmailAddress(@PathParam("emailAddressId") Long emailAddressId) {
|
||||
EmailAddress emailAddress = emailAddressManager.load(emailAddressId);
|
||||
if (!SecurityUtils.isAdministrator() && !emailAddress.getOwner().equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
@ -48,7 +59,7 @@ public class EmailAddressResource {
|
||||
@Api(order=150)
|
||||
@Path("/{emailAddressId}/verified")
|
||||
@GET
|
||||
public boolean getVerified(@PathParam("emailAddressId") Long emailAddressId) {
|
||||
public boolean isEmailAddressVerified(@PathParam("emailAddressId") Long emailAddressId) {
|
||||
EmailAddress emailAddress = emailAddressManager.load(emailAddressId);
|
||||
if (!SecurityUtils.isAdministrator() && !emailAddress.getOwner().equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
@ -57,7 +68,7 @@ public class EmailAddressResource {
|
||||
|
||||
@Api(order=200, description="Create new email address")
|
||||
@POST
|
||||
public Long create(@NotNull @Valid EmailAddress emailAddress) {
|
||||
public Long createEmailAddress(@NotNull @Valid EmailAddress emailAddress) {
|
||||
var owner = emailAddress.getOwner();
|
||||
if (!SecurityUtils.isAdministrator() && !owner.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
@ -72,9 +83,46 @@ public class EmailAddressResource {
|
||||
emailAddress.setVerificationCode(null);
|
||||
|
||||
emailAddressManager.create(emailAddress);
|
||||
|
||||
if (!getAuthUser().equals(owner))
|
||||
auditManager.audit(null, "added email address \"" + emailAddress.getValue() + "\" for account \"" + owner.getName() + "\" via RESTful API", null, null);
|
||||
return emailAddress.getId();
|
||||
}
|
||||
|
||||
@Api(order=220, description="Set as public email address")
|
||||
@Path("/public")
|
||||
@POST
|
||||
public Long setAsPublic(@NotNull Long emailAddressId) {
|
||||
var emailAddress = emailAddressManager.load(emailAddressId);
|
||||
var owner = emailAddress.getOwner();
|
||||
if (!SecurityUtils.isAdministrator() && !owner.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
emailAddressManager.setAsPublic(emailAddress);
|
||||
|
||||
if (!getAuthUser().equals(owner))
|
||||
auditManager.audit(null, "set email address \"" + emailAddress.getValue() + "\" as public for account \"" + owner.getName() + "\" via RESTful API", null, null);
|
||||
|
||||
return emailAddressId;
|
||||
}
|
||||
|
||||
@Api(order=230, description="Set as private email address")
|
||||
@Path("/private")
|
||||
@POST
|
||||
public Long setAsPrivate(@NotNull Long emailAddressId) {
|
||||
var emailAddress = emailAddressManager.load(emailAddressId);
|
||||
var owner = emailAddress.getOwner();
|
||||
if (!SecurityUtils.isAdministrator() && !owner.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
emailAddressManager.setAsPrivate(emailAddress);
|
||||
|
||||
if (!getAuthUser().equals(owner))
|
||||
auditManager.audit(null, "set email address \"" + emailAddress.getValue() + "\" as private for account \"" + owner.getName() + "\" via RESTful API", null, null);
|
||||
|
||||
return emailAddressId;
|
||||
}
|
||||
|
||||
@Api(order=250, description="Set as primary email address")
|
||||
@Path("/primary")
|
||||
@POST
|
||||
@ -88,6 +136,9 @@ public class EmailAddressResource {
|
||||
throw new ExplicitException("Can not set primary email address for externally authenticated user");
|
||||
|
||||
emailAddressManager.setAsPrimary(emailAddress);
|
||||
|
||||
if (!getAuthUser().equals(owner))
|
||||
auditManager.audit(null, "set email address \"" + emailAddress.getValue() + "\" as primary for account \"" + owner.getName() + "\" via RESTful API", null, null);
|
||||
|
||||
return emailAddressId;
|
||||
}
|
||||
@ -102,6 +153,9 @@ public class EmailAddressResource {
|
||||
|
||||
emailAddressManager.useForGitOperations(emailAddress);
|
||||
|
||||
if (!getAuthUser().equals(emailAddress.getOwner()))
|
||||
auditManager.audit(null, "specified email address \"" + emailAddress.getValue() + "\" for git operations for account \"" + emailAddress.getOwner().getName() + "\" via RESTful API", null, null);
|
||||
|
||||
return emailAddressId;
|
||||
}
|
||||
|
||||
@ -126,7 +180,7 @@ public class EmailAddressResource {
|
||||
@Api(order=300)
|
||||
@Path("/{emailAddressId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("emailAddressId") Long emailAddressId) {
|
||||
public Response deleteEmailAddress(@PathParam("emailAddressId") Long emailAddressId) {
|
||||
var emailAddress = emailAddressManager.load(emailAddressId);
|
||||
if (!SecurityUtils.isAdministrator() && !emailAddress.getOwner().equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
@ -138,6 +192,10 @@ public class EmailAddressResource {
|
||||
if (emailAddress.getOwner().getEmailAddresses().size() == 1)
|
||||
throw new ExplicitException("At least one email address should be present for a user");
|
||||
emailAddressManager.delete(emailAddress);
|
||||
|
||||
if (!getAuthUser().equals(emailAddress.getOwner()))
|
||||
auditManager.audit(null, "deleted email address \"" + emailAddress.getValue() + "\" for account \"" + emailAddress.getOwner().getName() + "\" via RESTful API", null, null);
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -15,6 +15,8 @@ import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.GroupAuthorizationManager;
|
||||
import io.onedev.server.model.GroupAuthorization;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
@ -29,15 +31,18 @@ public class GroupAuthorizationResource {
|
||||
|
||||
private final GroupAuthorizationManager authorizationManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public GroupAuthorizationResource(GroupAuthorizationManager authorizationManager) {
|
||||
public GroupAuthorizationResource(GroupAuthorizationManager authorizationManager, AuditManager auditManager) {
|
||||
this.authorizationManager = authorizationManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100, description = "Get group authorization of specified id")
|
||||
@Path("/{authorizationId}")
|
||||
@GET
|
||||
public GroupAuthorization get(@PathParam("authorizationId") Long authorizationId) {
|
||||
public GroupAuthorization getAuthorization(@PathParam("authorizationId") Long authorizationId) {
|
||||
var authorization = authorizationManager.load(authorizationId);
|
||||
if (!SecurityUtils.canManageProject(authorization.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
@ -46,21 +51,25 @@ public class GroupAuthorizationResource {
|
||||
|
||||
@Api(order=200, description="Create new group authorization")
|
||||
@POST
|
||||
public Long create(@NotNull GroupAuthorization authorization) {
|
||||
public Long createAuthorization(@NotNull GroupAuthorization authorization) {
|
||||
if (!SecurityUtils.canManageProject(authorization.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
authorizationManager.createOrUpdate(authorization);
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(authorization).toXML();
|
||||
auditManager.audit(authorization.getProject(), "created group authorization via RESTful API", null, newAuditContent);
|
||||
return authorization.getId();
|
||||
}
|
||||
|
||||
@Api(order=300, description = "Delete group authorization of specified id")
|
||||
@Path("/{authorizationId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("authorizationId") Long authorizationId) {
|
||||
public Response deleteAuthorization(@PathParam("authorizationId") Long authorizationId) {
|
||||
var authorization = authorizationManager.load(authorizationId);
|
||||
if (!SecurityUtils.canManageProject(authorization.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
authorizationManager.delete(authorization);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(authorization).toXML();
|
||||
auditManager.audit(authorization.getProject(), "deleted group authorization via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,15 @@ import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.NotFoundException;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
@ -14,6 +22,8 @@ import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.hibernate.criterion.MatchMode;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.GroupManager;
|
||||
import io.onedev.server.model.Group;
|
||||
import io.onedev.server.model.GroupAuthorization;
|
||||
@ -21,7 +31,6 @@ import io.onedev.server.model.Membership;
|
||||
import io.onedev.server.persistence.dao.EntityCriteria;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import io.onedev.server.util.facade.GroupFacade;
|
||||
|
||||
@Api(order=6000)
|
||||
@Path("/groups")
|
||||
@ -32,15 +41,18 @@ public class GroupResource {
|
||||
|
||||
private final GroupManager groupManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public GroupResource(GroupManager groupManager) {
|
||||
public GroupResource(GroupManager groupManager, AuditManager auditManager) {
|
||||
this.groupManager = groupManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{groupId}")
|
||||
@GET
|
||||
public Group getBasicInfo(@PathParam("groupId") Long groupId) {
|
||||
public Group getGroup(@PathParam("groupId") Long groupId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
return groupManager.load(groupId);
|
||||
@ -66,7 +78,7 @@ public class GroupResource {
|
||||
|
||||
@Api(order=400)
|
||||
@GET
|
||||
public List<Group> queryBasicInfo(@QueryParam("name") String name, @QueryParam("offset") @Api(example="0") int offset,
|
||||
public List<Group> queryGroups(@QueryParam("name") String name, @QueryParam("offset") @Api(example="0") int offset,
|
||||
@QueryParam("count") @Api(example="100") int count) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
@ -81,7 +93,7 @@ public class GroupResource {
|
||||
@Api(order=450)
|
||||
@Path("/ids/{name}")
|
||||
@GET
|
||||
public Long getId(@PathParam("name") @Api(description = "Group name") String name) {
|
||||
public Long getGroupId(@PathParam("name") @Api(description = "Group name") String name) {
|
||||
var group = groupManager.find(name);
|
||||
if (group != null)
|
||||
return group.getId();
|
||||
@ -91,35 +103,42 @@ public class GroupResource {
|
||||
|
||||
@Api(order=500, description="Create new group")
|
||||
@POST
|
||||
public Long create(@NotNull Group group) {
|
||||
public Long createGroup(@NotNull Group group) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
|
||||
groupManager.create(group);
|
||||
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(group).toXML();
|
||||
auditManager.audit(null, "created group \"" + group.getName() + "\" via RESTful API", null, newAuditContent);
|
||||
return group.getId();
|
||||
}
|
||||
|
||||
@Api(order=550, description="Update group of specified id")
|
||||
@Path("/{groupId}")
|
||||
@POST
|
||||
public Response update(@PathParam("groupId") Long groupId, @NotNull Group group) {
|
||||
public Response updateGroup(@PathParam("groupId") Long groupId, @NotNull Group group) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
if (group.getOldVersion() != null)
|
||||
groupManager.update(group, ((GroupFacade) group.getOldVersion()).getName());
|
||||
else
|
||||
groupManager.update(group, null);
|
||||
var oldName = group.getOldVersion().getRootElement().elementText(Group.PROP_NAME);
|
||||
groupManager.update(group, oldName);
|
||||
|
||||
var oldAuditContent = group.getOldVersion().toXML();
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(group).toXML();
|
||||
auditManager.audit(null, "changed group \"" + group.getName() + "\" via RESTful API", oldAuditContent, newAuditContent);
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@Api(order=600)
|
||||
@Path("/{groupId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("groupId") Long groupId) {
|
||||
public Response deleteGroup(@PathParam("groupId") Long groupId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
groupManager.delete(groupManager.load(groupId));
|
||||
var group = groupManager.load(groupId);
|
||||
groupManager.delete(group);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(group).toXML();
|
||||
auditManager.audit(null, "deleted group \"" + group.getName() + "\" via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -47,7 +47,7 @@ public class IssueCommentResource {
|
||||
@Api(order=100)
|
||||
@Path("/{commentId}")
|
||||
@GET
|
||||
public IssueComment get(@PathParam("commentId") Long commentId) {
|
||||
public IssueComment getComment(@PathParam("commentId") Long commentId) {
|
||||
IssueComment comment = commentManager.load(commentId);
|
||||
if (!SecurityUtils.canAccessProject(comment.getIssue().getProject()))
|
||||
throw new UnauthorizedException();
|
||||
@ -56,7 +56,7 @@ public class IssueCommentResource {
|
||||
|
||||
@Api(order=200, description="Create new issue comment")
|
||||
@POST
|
||||
public Long create(@NotNull IssueComment comment) {
|
||||
public Long createComment(@NotNull IssueComment comment) {
|
||||
if (!canAccessIssue(comment.getIssue())
|
||||
|| !isAdministrator() && !comment.getUser().equals(getUser())) {
|
||||
throw new UnauthorizedException();
|
||||
@ -68,7 +68,7 @@ public class IssueCommentResource {
|
||||
@Api(order=250, description="Update issue comment of specified id")
|
||||
@Path("/{commentId}")
|
||||
@POST
|
||||
public Response update(@PathParam("commentId") Long commentId, @NotNull String content) {
|
||||
public Response updateComment(@PathParam("commentId") Long commentId, @NotNull String content) {
|
||||
var comment = commentManager.load(commentId);
|
||||
if (!canModifyOrDelete(comment))
|
||||
throw new UnauthorizedException();
|
||||
@ -91,7 +91,7 @@ public class IssueCommentResource {
|
||||
@Api(order=300)
|
||||
@Path("/{commentId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("commentId") Long commentId) {
|
||||
public Response deleteComment(@PathParam("commentId") Long commentId) {
|
||||
IssueComment comment = commentManager.load(commentId);
|
||||
if (!canModifyOrDelete(comment))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
@ -32,7 +32,7 @@ public class IssueLinkResource {
|
||||
@Api(order=100)
|
||||
@Path("/{linkId}")
|
||||
@GET
|
||||
public IssueLink get(@PathParam("linkId") Long linkId) {
|
||||
public IssueLink getLink(@PathParam("linkId") Long linkId) {
|
||||
var link = linkManager.load(linkId);
|
||||
if (!canAccessIssue(link.getTarget()) && !canAccessIssue(link.getSource()))
|
||||
throw new UnauthorizedException();
|
||||
@ -41,7 +41,7 @@ public class IssueLinkResource {
|
||||
|
||||
@Api(order=200, description="Create new issue link")
|
||||
@POST
|
||||
public Long create(@NotNull IssueLink link) {
|
||||
public Long createLink(@NotNull IssueLink link) {
|
||||
if (!canEditIssueLink(link.getSource().getProject(), link.getSpec())
|
||||
&& !canEditIssueLink(link.getTarget().getProject(), link.getSpec())) {
|
||||
throw new UnauthorizedException();
|
||||
@ -76,7 +76,7 @@ public class IssueLinkResource {
|
||||
@Api(order=300)
|
||||
@Path("/{linkId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("linkId") Long linkId) {
|
||||
public Response deleteLink(@PathParam("linkId") Long linkId) {
|
||||
var link = linkManager.load(linkId);
|
||||
if (!canEditIssueLink(link.getSource().getProject(), link.getSpec())
|
||||
&& !canEditIssueLink(link.getTarget().getProject(), link.getSpec())) {
|
||||
|
||||
@ -1,10 +1,57 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.BadRequestException;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.*;
|
||||
import io.onedev.server.model.*;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.IssueChangeManager;
|
||||
import io.onedev.server.entitymanager.IssueManager;
|
||||
import io.onedev.server.entitymanager.IterationManager;
|
||||
import io.onedev.server.entitymanager.ProjectManager;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.model.Issue;
|
||||
import io.onedev.server.model.IssueChange;
|
||||
import io.onedev.server.model.IssueComment;
|
||||
import io.onedev.server.model.IssueLink;
|
||||
import io.onedev.server.model.IssueSchedule;
|
||||
import io.onedev.server.model.IssueVote;
|
||||
import io.onedev.server.model.IssueWatch;
|
||||
import io.onedev.server.model.IssueWork;
|
||||
import io.onedev.server.model.Iteration;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.model.support.issue.transitionspec.ManualSpec;
|
||||
import io.onedev.server.rest.InvalidParamException;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
@ -16,18 +63,6 @@ import io.onedev.server.security.SecurityUtils;
|
||||
import io.onedev.server.util.ProjectScopedCommit;
|
||||
import io.onedev.server.web.page.help.ApiHelpUtils;
|
||||
import io.onedev.server.web.page.help.ValueInfo;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
@Api(order=2000, description="In most cases, issue resource is operated with issue id, which is different from issue number. "
|
||||
+ "To get issue id of a particular issue number, use the <a href='/~help/api/io.onedev.server.rest.IssueResource/queryBasicInfo'>Query Basic Info</a> operation with query for "
|
||||
@ -49,23 +84,26 @@ public class IssueResource {
|
||||
private final ProjectManager projectManager;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public IssueResource(SettingManager settingManager, IssueManager issueManager,
|
||||
IssueChangeManager issueChangeManager, IterationManager iterationManager,
|
||||
ProjectManager projectManager, ObjectMapper objectMapper) {
|
||||
ProjectManager projectManager, ObjectMapper objectMapper, AuditManager auditManager) {
|
||||
this.settingManager = settingManager;
|
||||
this.issueManager = issueManager;
|
||||
this.issueChangeManager = issueChangeManager;
|
||||
this.iterationManager = iterationManager;
|
||||
this.projectManager = projectManager;
|
||||
this.objectMapper = objectMapper;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{issueId}")
|
||||
@GET
|
||||
public Issue getBasicInfo(@PathParam("issueId") Long issueId) {
|
||||
public Issue getIssue(@PathParam("issueId") Long issueId) {
|
||||
Issue issue = issueManager.load(issueId);
|
||||
if (!SecurityUtils.canAccessIssue(issue))
|
||||
throw new UnauthorizedException();
|
||||
@ -196,7 +234,7 @@ public class IssueResource {
|
||||
|
||||
@Api(order=900, exampleProvider = "getIssuesExample")
|
||||
@GET
|
||||
public List<Map<String, Object>> query(
|
||||
public List<Map<String, Object>> queryIssues(
|
||||
@QueryParam("query") @Api(description="Syntax of this query is the same as in <a href='/~issues'>issues page</a>", example="\"State\" is \"Open\"") String query,
|
||||
@QueryParam("withFields") @Api(description = "Whether or not to include issue fields. Default to false", example="true") Boolean withFields,
|
||||
@QueryParam("offset") @Api(example="0") int offset,
|
||||
@ -235,7 +273,7 @@ public class IssueResource {
|
||||
|
||||
@Api(order=1000)
|
||||
@POST
|
||||
public Long create(@NotNull @Valid IssueOpenData data) {
|
||||
public Long createIssue(@NotNull @Valid IssueOpenData data) {
|
||||
User user = SecurityUtils.getUser();
|
||||
|
||||
Project project = projectManager.load(data.getProjectId());
|
||||
@ -384,11 +422,13 @@ public class IssueResource {
|
||||
@Api(order=1600)
|
||||
@Path("/{issueId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("issueId") Long issueId) {
|
||||
public Response deleteIssue(@PathParam("issueId") Long issueId) {
|
||||
Issue issue = issueManager.load(issueId);
|
||||
if (!SecurityUtils.canManageIssues(issue.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
issueManager.delete(issue);
|
||||
issueManager.delete(issue);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(issue).toXML();
|
||||
auditManager.audit(issue.getProject(), "deleted issue \"" + issue.getReference().toString(issue.getProject()) + "\" via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -32,7 +32,7 @@ public class IssueVoteResource {
|
||||
@Api(order=100)
|
||||
@Path("/{voteId}")
|
||||
@GET
|
||||
public IssueVote get(@PathParam("voteId") Long voteId) {
|
||||
public IssueVote getVote(@PathParam("voteId") Long voteId) {
|
||||
IssueVote vote = voteManager.load(voteId);
|
||||
if (!SecurityUtils.canAccessIssue(vote.getIssue()))
|
||||
throw new UnauthorizedException();
|
||||
@ -41,7 +41,7 @@ public class IssueVoteResource {
|
||||
|
||||
@Api(order=200, description="Create new issue vote")
|
||||
@POST
|
||||
public Long create(@NotNull IssueVote vote) {
|
||||
public Long createVote(@NotNull IssueVote vote) {
|
||||
if (!SecurityUtils.canAccessIssue(vote.getIssue())
|
||||
|| !SecurityUtils.isAdministrator() && !vote.getUser().equals(SecurityUtils.getAuthUser())) {
|
||||
throw new UnauthorizedException();
|
||||
@ -53,7 +53,7 @@ public class IssueVoteResource {
|
||||
@Api(order=300)
|
||||
@Path("/{voteId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("voteId") Long voteId) {
|
||||
public Response deleteVote(@PathParam("voteId") Long voteId) {
|
||||
IssueVote vote = voteManager.load(voteId);
|
||||
if (!canModifyOrDelete(vote))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
@ -32,7 +32,7 @@ public class IssueWatchResource {
|
||||
@Api(order=100)
|
||||
@Path("/{watchId}")
|
||||
@GET
|
||||
public IssueWatch get(@PathParam("watchId") Long watchId) {
|
||||
public IssueWatch getWatch(@PathParam("watchId") Long watchId) {
|
||||
IssueWatch watch = watchManager.load(watchId);
|
||||
if (!SecurityUtils.canAccessIssue(watch.getIssue()))
|
||||
throw new UnauthorizedException();
|
||||
@ -41,7 +41,7 @@ public class IssueWatchResource {
|
||||
|
||||
@Api(order=200, description="Create new issue watch")
|
||||
@POST
|
||||
public Long create(@NotNull IssueWatch watch) {
|
||||
public Long createWatch(@NotNull IssueWatch watch) {
|
||||
if (!SecurityUtils.canAccessIssue(watch.getIssue())
|
||||
|| !SecurityUtils.isAdministrator() && !watch.getUser().equals(SecurityUtils.getAuthUser())) {
|
||||
throw new UnauthorizedException();
|
||||
@ -53,7 +53,7 @@ public class IssueWatchResource {
|
||||
@Api(order=250, description="Update issue watch of specified id")
|
||||
@Path("/{watchId}")
|
||||
@POST
|
||||
public Response update(@PathParam("watchId") Long watchId, @NotNull IssueWatch watch) {
|
||||
public Response updateWatch(@PathParam("watchId") Long watchId, @NotNull IssueWatch watch) {
|
||||
if (!canModifyOrDelete(watch))
|
||||
throw new UnauthorizedException();
|
||||
watchManager.createOrUpdate(watch);
|
||||
@ -63,7 +63,7 @@ public class IssueWatchResource {
|
||||
@Api(order=300)
|
||||
@Path("/{watchId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("watchId") Long watchId) {
|
||||
public Response deleteWatch(@PathParam("watchId") Long watchId) {
|
||||
IssueWatch watch = watchManager.load(watchId);
|
||||
if (!canModifyOrDelete(watch))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
@ -43,7 +43,7 @@ public class IssueWorkResource {
|
||||
@Api(order=100)
|
||||
@Path("/{workId}")
|
||||
@GET
|
||||
public IssueWork get(@PathParam("workId") Long workId) {
|
||||
public IssueWork getWork(@PathParam("workId") Long workId) {
|
||||
if (!subscriptionManager.isSubscriptionActive())
|
||||
throw new UnsupportedOperationException("This feature requires an active subscription");
|
||||
IssueWork work = workManager.load(workId);
|
||||
@ -54,7 +54,7 @@ public class IssueWorkResource {
|
||||
|
||||
@Api(order=200, description="Log new issue work")
|
||||
@POST
|
||||
public Long create(@NotNull IssueWork work) {
|
||||
public Long createWork(@NotNull IssueWork work) {
|
||||
if (!subscriptionManager.isSubscriptionActive())
|
||||
throw new UnsupportedOperationException("This feature requires an active subscription");
|
||||
if (!work.getIssue().getProject().isTimeTracking())
|
||||
@ -72,7 +72,7 @@ public class IssueWorkResource {
|
||||
@Api(order=250, description="Update issue work of specified id")
|
||||
@Path("/{workId}")
|
||||
@POST
|
||||
public Response update(@PathParam("workId") Long workId, @NotNull IssueWork work) {
|
||||
public Response updateWork(@PathParam("workId") Long workId, @NotNull IssueWork work) {
|
||||
if (!canModifyOrDelete(work))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
@ -84,7 +84,7 @@ public class IssueWorkResource {
|
||||
@Api(order=300)
|
||||
@Path("/{workId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("workId") Long workId) {
|
||||
public Response deleteWork(@PathParam("workId") Long workId) {
|
||||
var work = workManager.load(workId);
|
||||
if (!canModifyOrDelete(work))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
@ -15,6 +15,8 @@ import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.IterationManager;
|
||||
import io.onedev.server.model.Iteration;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
@ -29,15 +31,18 @@ public class IterationResource {
|
||||
|
||||
private final IterationManager iterationManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public IterationResource(IterationManager iterationManager) {
|
||||
public IterationResource(IterationManager iterationManager, AuditManager auditManager) {
|
||||
this.iterationManager = iterationManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{iterationId}")
|
||||
@GET
|
||||
public Iteration get(@PathParam("iterationId") Long iterationId) {
|
||||
public Iteration getIteration(@PathParam("iterationId") Long iterationId) {
|
||||
Iteration iteration = iterationManager.load(iterationId);
|
||||
if (!SecurityUtils.canAccessProject(iteration.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
@ -46,31 +51,38 @@ public class IterationResource {
|
||||
|
||||
@Api(order=200, description="Create new iteration")
|
||||
@POST
|
||||
public Long create(@NotNull Iteration iteration) {
|
||||
public Long createIteration(@NotNull Iteration iteration) {
|
||||
if (!SecurityUtils.canManageIssues(iteration.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
iterationManager.createOrUpdate(iteration);
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(iteration).toXML();
|
||||
auditManager.audit(iteration.getProject(), "created iteration \"" + iteration.getName() + "\" via RESTful API", null, newAuditContent);
|
||||
return iteration.getId();
|
||||
}
|
||||
|
||||
@Api(order=250, description="Update iteration of specified id")
|
||||
@Path("/{iterationId}")
|
||||
@POST
|
||||
public Long update(@PathParam("iterationId") Long iterationId, @NotNull Iteration iteration) {
|
||||
public Long updateIteration(@PathParam("iterationId") Long iterationId, @NotNull Iteration iteration) {
|
||||
if (!SecurityUtils.canManageIssues(iteration.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
iterationManager.createOrUpdate(iteration);
|
||||
var oldAuditContent = iteration.getOldVersion().toXML();
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(iteration).toXML();
|
||||
auditManager.audit(iteration.getProject(), "changed iteration \"" + iteration.getName() + "\" via RESTful API", oldAuditContent, newAuditContent);
|
||||
return iteration.getId();
|
||||
}
|
||||
|
||||
@Api(order=300)
|
||||
@Path("/{iterationId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("iterationId") Long iterationId) {
|
||||
public Response deleteIteration(@PathParam("iterationId") Long iterationId) {
|
||||
Iteration iteration = iterationManager.load(iterationId);
|
||||
if (!SecurityUtils.canManageIssues(iteration.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
iterationManager.delete(iteration);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(iteration).toXML();
|
||||
auditManager.audit(iteration.getProject(), "deleted iteration \"" + iteration.getName() + "\" via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -1,21 +1,32 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.hibernate.criterion.MatchMode;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.LabelSpecManager;
|
||||
import io.onedev.server.model.LabelSpec;
|
||||
import io.onedev.server.persistence.dao.EntityCriteria;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.hibernate.criterion.MatchMode;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.List;
|
||||
|
||||
@Api(order=10200)
|
||||
@Path("/label-specs")
|
||||
@ -26,15 +37,18 @@ public class LabelSpecResource {
|
||||
|
||||
private final LabelSpecManager labelSpecManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public LabelSpecResource(LabelSpecManager labelSpecManager) {
|
||||
public LabelSpecResource(LabelSpecManager labelSpecManager, AuditManager auditManager) {
|
||||
this.labelSpecManager = labelSpecManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{labelSpecId}")
|
||||
@GET
|
||||
public LabelSpec get(@PathParam("labelSpecId") Long labelSpecId) {
|
||||
public LabelSpec getSpec(@PathParam("labelSpecId") Long labelSpecId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
return labelSpecManager.load(labelSpecId);
|
||||
@ -42,7 +56,7 @@ public class LabelSpecResource {
|
||||
|
||||
@Api(order=400)
|
||||
@GET
|
||||
public List<LabelSpec> query(@QueryParam("name") String name,
|
||||
public List<LabelSpec> querySpecs(@QueryParam("name") String name,
|
||||
@QueryParam("offset") @Api(example="0") int offset,
|
||||
@QueryParam("count") @Api(example="100") int count) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
@ -57,31 +71,39 @@ public class LabelSpecResource {
|
||||
|
||||
@Api(order=500, description="Create new label spec")
|
||||
@POST
|
||||
public Long create(@NotNull LabelSpec labelSpec) {
|
||||
public Long createSpec(@NotNull LabelSpec labelSpec) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
|
||||
labelSpecManager.createOrUpdate(labelSpec);
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(labelSpec).toXML();
|
||||
auditManager.audit(null, "created label spec \"" + labelSpec.getName() + "\" via RESTful API", null, newAuditContent);
|
||||
return labelSpec.getId();
|
||||
}
|
||||
|
||||
@Api(order=550, description="Update label spec of specified id")
|
||||
@Path("/{labelSpecId}")
|
||||
@POST
|
||||
public Response update(@PathParam("labelSpecId") Long labelSpecId, @NotNull LabelSpec labelSpec) {
|
||||
public Response updateSpec(@PathParam("labelSpecId") Long labelSpecId, @NotNull LabelSpec labelSpec) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
labelSpecManager.createOrUpdate(labelSpec);
|
||||
var oldAuditContent = labelSpec.getOldVersion().toXML();
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(labelSpec).toXML();
|
||||
auditManager.audit(null, "changed label spec \"" + labelSpec.getName() + "\" via RESTful API", oldAuditContent, newAuditContent);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@Api(order=600)
|
||||
@Path("/{labelSpecId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("labelSpecId") Long labelSpecId) {
|
||||
public Response deleteSpec(@PathParam("labelSpecId") Long labelSpecId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
labelSpecManager.delete(labelSpecManager.load(labelSpecId));
|
||||
var labelSpec = labelSpecManager.load(labelSpecId);
|
||||
labelSpecManager.delete(labelSpec);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(labelSpec).toXML();
|
||||
auditManager.audit(null, "deleted label spec \"" + labelSpec.getName() + "\" via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -15,6 +15,8 @@ import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.MembershipManager;
|
||||
import io.onedev.server.model.Membership;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
@ -29,15 +31,18 @@ public class MembershipResource {
|
||||
|
||||
private final MembershipManager membershipManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public MembershipResource(MembershipManager membershipManager) {
|
||||
public MembershipResource(MembershipManager membershipManager, AuditManager auditManager) {
|
||||
this.membershipManager = membershipManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{membershipId}")
|
||||
@GET
|
||||
public Membership get(@PathParam("membershipId") Long membershipId) {
|
||||
public Membership getMembership(@PathParam("membershipId") Long membershipId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
return membershipManager.load(membershipId);
|
||||
@ -45,20 +50,25 @@ public class MembershipResource {
|
||||
|
||||
@Api(order=200, description="Create new membership")
|
||||
@POST
|
||||
public Long create(@NotNull Membership membership) {
|
||||
public Long createMembership(@NotNull Membership membership) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
membershipManager.create(membership);
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(membership).toXML();
|
||||
auditManager.audit(null, "created membership via RESTful API", null, newAuditContent);
|
||||
return membership.getId();
|
||||
}
|
||||
|
||||
@Api(order=300)
|
||||
@Path("/{membershipId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("membershipId") Long membershipId) {
|
||||
public Response deleteMembership(@PathParam("membershipId") Long membershipId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
membershipManager.delete(membershipManager.load(membershipId));
|
||||
var membership = membershipManager.load(membershipId);
|
||||
membershipManager.delete(membership);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(membership).toXML();
|
||||
auditManager.audit(null, "deleted membership via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ public class PackLabelResource {
|
||||
|
||||
@Api(order=200, description="Create package label")
|
||||
@POST
|
||||
public Long create(@NotNull PackLabel packLabel) {
|
||||
public Long createLabel(@NotNull PackLabel packLabel) {
|
||||
if (!SecurityUtils.canWritePack(packLabel.getPack().getProject()))
|
||||
throw new UnauthorizedException();
|
||||
packLabelManager.create(packLabel);
|
||||
@ -39,7 +39,7 @@ public class PackLabelResource {
|
||||
@Api(order=300)
|
||||
@Path("/{packLabelId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("packLabelId") Long packLabelId) {
|
||||
public Response deleteLabel(@PathParam("packLabelId") Long packLabelId) {
|
||||
PackLabel buildLabel = packLabelManager.load(packLabelId);
|
||||
if (!SecurityUtils.canWritePack(buildLabel.getPack().getProject()))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
@ -1,5 +1,26 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.PackManager;
|
||||
import io.onedev.server.model.Pack;
|
||||
import io.onedev.server.model.PackBlob;
|
||||
@ -10,17 +31,6 @@ import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.rest.resource.support.RestConstants;
|
||||
import io.onedev.server.search.entity.pack.PackQuery;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
@Api(order=4300, name="Package")
|
||||
@Path("/packages")
|
||||
@ -31,15 +41,18 @@ public class PackResource {
|
||||
|
||||
private final PackManager packManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public PackResource(PackManager packManager) {
|
||||
public PackResource(PackManager packManager, AuditManager auditManager) {
|
||||
this.packManager = packManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{packId}")
|
||||
@GET
|
||||
public Pack getBasicInfo(@PathParam("packId") Long packId) {
|
||||
public Pack getPack(@PathParam("packId") Long packId) {
|
||||
Pack pack = packManager.load(packId);
|
||||
if (!SecurityUtils.canReadPack(pack.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
@ -68,7 +81,7 @@ public class PackResource {
|
||||
|
||||
@Api(order=600)
|
||||
@GET
|
||||
public List<Pack> queryBasicInfo(
|
||||
public List<Pack> queryPacks(
|
||||
@QueryParam("query") @Api(description="Syntax of this query is the same as in <a href='/~packages'>packages page</a>", example="\"Type\" is \"Container Image\"") String query,
|
||||
@QueryParam("offset") @Api(example="0") int offset,
|
||||
@QueryParam("count") @Api(example="100") int count) {
|
||||
@ -89,11 +102,13 @@ public class PackResource {
|
||||
@Api(order=700)
|
||||
@Path("/{packId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("packId") Long packId) {
|
||||
public Response deletePack(@PathParam("packId") Long packId) {
|
||||
Pack pack = packManager.load(packId);
|
||||
if (!SecurityUtils.canWritePack(pack.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
packManager.delete(pack);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(pack).toXML();
|
||||
auditManager.audit(pack.getProject(), "deleted package \"" + pack.getReference(false) + "\" via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +1,25 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import io.onedev.server.entitymanager.ProjectLabelManager;
|
||||
import io.onedev.server.model.ProjectLabel;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.ProjectLabelManager;
|
||||
import io.onedev.server.model.ProjectLabel;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
|
||||
@Api(order=10300)
|
||||
@Path("/project-labels")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ -22,28 +29,33 @@ public class ProjectLabelResource {
|
||||
|
||||
private final ProjectLabelManager projectLabelManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public ProjectLabelResource(ProjectLabelManager projectLabelManager) {
|
||||
public ProjectLabelResource(ProjectLabelManager projectLabelManager, AuditManager auditManager) {
|
||||
this.projectLabelManager = projectLabelManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=200, description="Create project label")
|
||||
@Api(order=200, description="Add project label")
|
||||
@POST
|
||||
public Long create(@NotNull ProjectLabel projectLabel) {
|
||||
public Long addLabel(@NotNull ProjectLabel projectLabel) {
|
||||
if (!SecurityUtils.canManageProject(projectLabel.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
projectLabelManager.create(projectLabel);
|
||||
auditManager.audit(projectLabel.getProject(), "added label \"" + projectLabel.getSpec().getName() + "\" via RESTful API", null, null);
|
||||
return projectLabel.getId();
|
||||
}
|
||||
|
||||
@Api(order=300)
|
||||
@Path("/{projectLabelId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("projectLabelId") Long projectLabelId) {
|
||||
public Response removeLabel(@PathParam("projectLabelId") Long projectLabelId) {
|
||||
ProjectLabel projectLabel = projectLabelManager.load(projectLabelId);
|
||||
if (!SecurityUtils.canManageProject(projectLabel.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
projectLabelManager.delete(projectLabel);
|
||||
auditManager.audit(projectLabel.getProject(), "removed label \"" + projectLabel.getSpec().getName() + "\" via RESTful API", null, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
@ -33,7 +34,11 @@ import javax.ws.rs.core.Response;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.IterationManager;
|
||||
import io.onedev.server.entitymanager.ProjectManager;
|
||||
import io.onedev.server.git.GitContribution;
|
||||
@ -44,11 +49,13 @@ import io.onedev.server.model.Iteration;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.ProjectLabel;
|
||||
import io.onedev.server.model.UserAuthorization;
|
||||
import io.onedev.server.model.support.CodeAnalysisSetting;
|
||||
import io.onedev.server.model.support.NamedCodeCommentQuery;
|
||||
import io.onedev.server.model.support.NamedCommitQuery;
|
||||
import io.onedev.server.model.support.WebHook;
|
||||
import io.onedev.server.model.support.build.ProjectBuildSetting;
|
||||
import io.onedev.server.model.support.code.BranchProtection;
|
||||
import io.onedev.server.model.support.code.GitPackConfig;
|
||||
import io.onedev.server.model.support.code.TagProtection;
|
||||
import io.onedev.server.model.support.issue.ProjectIssueSetting;
|
||||
import io.onedev.server.model.support.pack.ProjectPackSetting;
|
||||
@ -56,11 +63,11 @@ import io.onedev.server.model.support.pullrequest.ProjectPullRequestSetting;
|
||||
import io.onedev.server.persistence.dao.EntityCriteria;
|
||||
import io.onedev.server.rest.InvalidParamException;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.rest.annotation.EntityCreate;
|
||||
import io.onedev.server.rest.resource.support.RestConstants;
|
||||
import io.onedev.server.search.entity.project.ProjectQuery;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import io.onedev.server.util.DateUtils;
|
||||
import io.onedev.server.util.facade.ProjectFacade;
|
||||
import io.onedev.server.web.UrlManager;
|
||||
import io.onedev.server.web.page.project.setting.ContributedProjectSetting;
|
||||
import io.onedev.server.xodus.CommitInfoManager;
|
||||
@ -79,24 +86,27 @@ public class ProjectResource {
|
||||
private final CommitInfoManager commitInfoManager;
|
||||
|
||||
private final UrlManager urlManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public ProjectResource(ProjectManager projectManager, IterationManager iterationManager,
|
||||
CommitInfoManager commitInfoManager, UrlManager urlManager) {
|
||||
CommitInfoManager commitInfoManager, UrlManager urlManager, AuditManager auditManager) {
|
||||
this.projectManager = projectManager;
|
||||
this.iterationManager = iterationManager;
|
||||
this.commitInfoManager = commitInfoManager;
|
||||
this.urlManager = urlManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{projectId}")
|
||||
@GET
|
||||
public Project getBasicInfo(@PathParam("projectId") Long projectId) {
|
||||
public ProjectData getProject(@PathParam("projectId") Long projectId) {
|
||||
Project project = projectManager.load(projectId);
|
||||
if (!SecurityUtils.canAccessProject(project))
|
||||
throw new UnauthorizedException();
|
||||
return project;
|
||||
return ProjectData.from(project);
|
||||
}
|
||||
|
||||
@Api(order=150)
|
||||
@ -121,18 +131,7 @@ public class ProjectResource {
|
||||
Project project = projectManager.load(projectId);
|
||||
if (!SecurityUtils.canManageProject(project))
|
||||
throw new UnauthorizedException();
|
||||
ProjectSetting setting = new ProjectSetting();
|
||||
setting.branchProtections = project.getBranchProtections();
|
||||
setting.tagProtections = project.getTagProtections();
|
||||
setting.buildSetting = project.getBuildSetting();
|
||||
setting.packSetting = project.getPackSetting();
|
||||
setting.issueSetting = project.getIssueSetting();
|
||||
setting.namedCodeCommentQueries = project.getNamedCodeCommentQueries();
|
||||
setting.namedCommitQueries = project.getNamedCommitQueries();
|
||||
setting.pullRequestSetting = project.getPullRequestSetting();
|
||||
setting.webHooks = project.getWebHooks();
|
||||
setting.contributedSettings.addAll(project.getContributedSettings().values());
|
||||
return setting;
|
||||
return ProjectSetting.from(project);
|
||||
}
|
||||
|
||||
@Api(order=300)
|
||||
@ -187,7 +186,7 @@ public class ProjectResource {
|
||||
|
||||
@Api(order=700)
|
||||
@GET
|
||||
public List<Project> queryBasicInfo(
|
||||
public List<ProjectData> queryProjects(
|
||||
@QueryParam("query") @Api(description="Syntax of this query is the same as in <a href='/~projects'>projects page</a>", example="\"Name\" is \"projectName\"") String query,
|
||||
@QueryParam("offset") @Api(example="0") int offset,
|
||||
@QueryParam("count") @Api(example="100") int count) {
|
||||
@ -202,7 +201,9 @@ public class ProjectResource {
|
||||
throw new InvalidParamException("Error parsing query", e);
|
||||
}
|
||||
|
||||
return projectManager.query(parsedQuery, false, offset, count);
|
||||
return projectManager.query(parsedQuery, false, offset, count).stream()
|
||||
.map(ProjectData::from)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Api(order=750)
|
||||
@ -268,31 +269,34 @@ public class ProjectResource {
|
||||
|
||||
@Api(order=800, description="Create new project")
|
||||
@POST
|
||||
public Long create(@NotNull @Valid Project project) {
|
||||
Project parent = project.getParent();
|
||||
public Long createProject(@NotNull @Valid ProjectData data) {
|
||||
var project = new Project();
|
||||
data.populate(project, projectManager);
|
||||
|
||||
checkProjectCreationPermission(parent);
|
||||
checkProjectCreationPermission(project.getParent());
|
||||
|
||||
if (parent != null && project.isSelfOrAncestorOf(parent))
|
||||
if (project.getParent() != null && project.isSelfOrAncestorOf(project.getParent()))
|
||||
throw new ExplicitException("Can not use current or descendant project as parent");
|
||||
|
||||
checkProjectNameDuplication(project);
|
||||
|
||||
checkProjectNameDuplication(project);
|
||||
projectManager.create(project);
|
||||
|
||||
|
||||
auditManager.audit(project, "created project via RESTful API", null, VersionedXmlDoc.fromBean(data).toXML());
|
||||
|
||||
return project.getId();
|
||||
}
|
||||
|
||||
@Api(order=850, description="Update projecty basic info of specified id")
|
||||
@Api(order=850, description="Update project")
|
||||
@Path("/{projectId}")
|
||||
@POST
|
||||
public Response updateBasicInfo(@PathParam("projectId") Long projectId, @NotNull @Valid Project project) {
|
||||
Project parent = project.getParent();
|
||||
Long oldParentId;
|
||||
if (project.getOldVersion() != null)
|
||||
oldParentId = ((ProjectFacade) project.getOldVersion()).getParentId();
|
||||
else
|
||||
oldParentId = null;
|
||||
public Response updateProject(@PathParam("projectId") Long projectId, @NotNull @Valid ProjectData data) {
|
||||
Project project = projectManager.load(projectId);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(ProjectData.from(project)).toXML();
|
||||
|
||||
data.populate(project, projectManager);
|
||||
|
||||
Project parent = data.getParentId() != null? projectManager.load(data.getParentId()) : null;
|
||||
Long oldParentId = Project.idOf(project.getParent());
|
||||
|
||||
if (!Objects.equals(oldParentId, Project.idOf(parent)))
|
||||
checkProjectCreationPermission(parent);
|
||||
@ -306,6 +310,8 @@ public class ProjectResource {
|
||||
throw new UnauthorizedException();
|
||||
} else {
|
||||
projectManager.update(project);
|
||||
auditManager.audit(project, "changed project via RESTful API", oldAuditContent,
|
||||
VersionedXmlDoc.fromBean(ProjectData.from(project)).toXML());
|
||||
}
|
||||
|
||||
return Response.ok().build();
|
||||
@ -331,38 +337,33 @@ public class ProjectResource {
|
||||
}
|
||||
}
|
||||
|
||||
@Api(order=900, description="Update project setting")
|
||||
@Api(order=900, description="Update project settings")
|
||||
@Path("/{projectId}/setting")
|
||||
@POST
|
||||
public Response updateSetting(@PathParam("projectId") Long projectId, @NotNull ProjectSetting setting) {
|
||||
Project project = projectManager.load(projectId);
|
||||
if (!SecurityUtils.canManageProject(project))
|
||||
throw new UnauthorizedException();
|
||||
project.setBranchProtections(setting.branchProtections);
|
||||
project.setTagProtections(setting.tagProtections);
|
||||
project.setBuildSetting(setting.buildSetting);
|
||||
project.setPackSetting(setting.packSetting);
|
||||
project.setIssueSetting(setting.issueSetting);
|
||||
project.setNamedCodeCommentQueries(setting.namedCodeCommentQueries);
|
||||
project.setNamedCommitQueries(setting.namedCommitQueries);
|
||||
project.setPullRequestSetting(setting.pullRequestSetting);
|
||||
project.setWebHooks(setting.webHooks);
|
||||
var contributedSettings = new LinkedHashMap<String, ContributedProjectSetting>();
|
||||
for (var contributedSetting: setting.getContributedSettings())
|
||||
contributedSettings.put(contributedSetting.getClass().getName(), contributedSetting);
|
||||
project.setContributedSettings(contributedSettings);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(ProjectSetting.from(project)).toXML();
|
||||
setting.populate(project);
|
||||
projectManager.update(project);
|
||||
auditManager.audit(project, "changed project settings via RESTful API", oldAuditContent, VersionedXmlDoc.fromBean(setting).toXML());
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@Api(order=1000)
|
||||
@Path("/{projectId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("projectId") Long projectId) {
|
||||
public Response deleteProject(@PathParam("projectId") Long projectId) {
|
||||
Project project = projectManager.load(projectId);
|
||||
if (!SecurityUtils.canManageProject(project))
|
||||
throw new UnauthorizedException();
|
||||
projectManager.delete(project);
|
||||
if (project.getParent() != null)
|
||||
auditManager.audit(project.getParent(), "deleted child project \"" + project.getName() + "\" via RESTful API", VersionedXmlDoc.fromBean(ProjectData.from(project)).toXML(), null);
|
||||
else
|
||||
auditManager.audit(null, "deleted root project \"" + project.getName() + "\" via RESTful API", VersionedXmlDoc.fromBean(ProjectData.from(project)).toXML(), null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -391,6 +392,215 @@ public class ProjectResource {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EntityCreate(Project.class)
|
||||
public static class ProjectData implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Api(order = 100, description="Represents the parent project of this project. Remove this property if "
|
||||
+ "the project is a root project when create/update the project. May be null")
|
||||
private Long parentId;
|
||||
|
||||
@Api(order = 150, description="Represents the project from which this project is forked. Remove this property if "
|
||||
+ "the project is not a fork when create/update the project. May be null")
|
||||
private Long forkedFromId;
|
||||
|
||||
@Api(order = 300)
|
||||
private String name;
|
||||
|
||||
@Api(order = 400, description="May be null")
|
||||
private String key;
|
||||
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
@Api(order = 450)
|
||||
private String path;
|
||||
|
||||
@Api(order = 500, description="May be null")
|
||||
private String description;
|
||||
|
||||
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
|
||||
@Api(order = 550)
|
||||
private Date createDate;
|
||||
|
||||
@Api(order = 600)
|
||||
private boolean codeManagement = true;
|
||||
|
||||
@Api(order = 650)
|
||||
private boolean packManagement = true;
|
||||
|
||||
@Api(order = 700)
|
||||
private boolean issueManagement = true;
|
||||
|
||||
@Api(order = 750)
|
||||
private boolean timeTracking = false;
|
||||
|
||||
@Api(order = 800, description = "May be null")
|
||||
private String serviceDeskEmailAddress;
|
||||
|
||||
@Api(order = 850)
|
||||
private GitPackConfig gitPackConfig;
|
||||
|
||||
@Api(order = 900)
|
||||
private CodeAnalysisSetting codeAnalysisSetting;
|
||||
|
||||
public Long getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(Long parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public Long getForkedFromId() {
|
||||
return forkedFromId;
|
||||
}
|
||||
|
||||
public void setForkedFromId(Long forkedFromId) {
|
||||
this.forkedFromId = forkedFromId;
|
||||
}
|
||||
|
||||
@NotEmpty
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Date getCreateDate() {
|
||||
return createDate;
|
||||
}
|
||||
|
||||
public void setCreateDate(Date createDate) {
|
||||
this.createDate = createDate;
|
||||
}
|
||||
|
||||
public boolean isCodeManagement() {
|
||||
return codeManagement;
|
||||
}
|
||||
|
||||
public void setCodeManagement(boolean codeManagement) {
|
||||
this.codeManagement = codeManagement;
|
||||
}
|
||||
|
||||
public boolean isPackManagement() {
|
||||
return packManagement;
|
||||
}
|
||||
|
||||
public void setPackManagement(boolean packManagement) {
|
||||
this.packManagement = packManagement;
|
||||
}
|
||||
|
||||
public boolean isIssueManagement() {
|
||||
return issueManagement;
|
||||
}
|
||||
|
||||
public void setIssueManagement(boolean issueManagement) {
|
||||
this.issueManagement = issueManagement;
|
||||
}
|
||||
|
||||
public boolean isTimeTracking() {
|
||||
return timeTracking;
|
||||
}
|
||||
|
||||
public void setTimeTracking(boolean timeTracking) {
|
||||
this.timeTracking = timeTracking;
|
||||
}
|
||||
|
||||
public String getServiceDeskEmailAddress() {
|
||||
return serviceDeskEmailAddress;
|
||||
}
|
||||
|
||||
public void setServiceDeskEmailAddress(String serviceDeskEmailAddress) {
|
||||
this.serviceDeskEmailAddress = serviceDeskEmailAddress;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public GitPackConfig getGitPackConfig() {
|
||||
return gitPackConfig;
|
||||
}
|
||||
|
||||
public void setGitPackConfig(GitPackConfig gitPackConfig) {
|
||||
this.gitPackConfig = gitPackConfig;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CodeAnalysisSetting getCodeAnalysisSetting() {
|
||||
return codeAnalysisSetting;
|
||||
}
|
||||
|
||||
public void setCodeAnalysisSetting(CodeAnalysisSetting codeAnalysisSetting) {
|
||||
this.codeAnalysisSetting = codeAnalysisSetting;
|
||||
}
|
||||
|
||||
public void populate(Project project, ProjectManager projectManager) {
|
||||
if (parentId != null)
|
||||
project.setParent(projectManager.load(getParentId()));
|
||||
else
|
||||
project.setParent(null);
|
||||
if (forkedFromId != null)
|
||||
project.setForkedFrom(projectManager.load(getForkedFromId()));
|
||||
else
|
||||
project.setForkedFrom(null);
|
||||
project.setName(getName());
|
||||
project.setKey(getKey());
|
||||
project.setDescription(getDescription());
|
||||
project.setCodeManagement(isCodeManagement());
|
||||
project.setPackManagement(isPackManagement());
|
||||
project.setIssueManagement(isIssueManagement());
|
||||
project.setTimeTracking(isTimeTracking());
|
||||
project.setServiceDeskEmailAddress(getServiceDeskEmailAddress());
|
||||
project.setGitPackConfig(getGitPackConfig());
|
||||
project.setCodeAnalysisSetting(getCodeAnalysisSetting());
|
||||
}
|
||||
|
||||
public static ProjectData from(Project project) {
|
||||
ProjectData data = new ProjectData();
|
||||
data.setParentId(Project.idOf(project.getParent()));
|
||||
data.setForkedFromId(Project.idOf(project.getForkedFrom()));
|
||||
data.setName(project.getName());
|
||||
data.setKey(project.getKey());
|
||||
data.setPath(project.getPath());
|
||||
data.setDescription(project.getDescription());
|
||||
data.setCreateDate(project.getCreateDate());
|
||||
data.setCodeManagement(project.isCodeManagement());
|
||||
data.setPackManagement(project.isPackManagement());
|
||||
data.setIssueManagement(project.isIssueManagement());
|
||||
data.setTimeTracking(project.isTimeTracking());
|
||||
data.setServiceDeskEmailAddress(project.getServiceDeskEmailAddress());
|
||||
data.setGitPackConfig(project.getGitPackConfig());
|
||||
data.setCodeAnalysisSetting(project.getCodeAnalysisSetting());
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ProjectSetting implements Serializable {
|
||||
|
||||
@ -496,6 +706,38 @@ public class ProjectResource {
|
||||
this.contributedSettings = contributedSettings;
|
||||
}
|
||||
|
||||
public void populate(Project project) {
|
||||
project.setBranchProtections(getBranchProtections());
|
||||
project.setTagProtections(getTagProtections());
|
||||
project.setBuildSetting(getBuildSetting());
|
||||
project.setPackSetting(getPackSetting());
|
||||
project.setIssueSetting(getIssueSetting());
|
||||
project.setNamedCodeCommentQueries(getNamedCodeCommentQueries());
|
||||
project.setNamedCommitQueries(getNamedCommitQueries());
|
||||
project.setPullRequestSetting(getPullRequestSetting());
|
||||
project.setWebHooks(getWebHooks());
|
||||
var contributedSettings = new LinkedHashMap<String, ContributedProjectSetting>();
|
||||
for (var contributedSetting: getContributedSettings())
|
||||
contributedSettings.put(contributedSetting.getClass().getName(), contributedSetting);
|
||||
project.setContributedSettings(contributedSettings);
|
||||
}
|
||||
|
||||
public static ProjectSetting from(Project project) {
|
||||
ProjectSetting setting = new ProjectSetting();
|
||||
setting.setBranchProtections(project.getBranchProtections());
|
||||
setting.setTagProtections(project.getTagProtections());
|
||||
setting.setBuildSetting(project.getBuildSetting());
|
||||
setting.setPackSetting(project.getPackSetting());
|
||||
setting.setIssueSetting(project.getIssueSetting());
|
||||
setting.setNamedCodeCommentQueries(project.getNamedCodeCommentQueries());
|
||||
setting.setNamedCommitQueries(project.getNamedCommitQueries());
|
||||
setting.setPullRequestSetting(project.getPullRequestSetting());
|
||||
setting.setWebHooks(project.getWebHooks());
|
||||
setting.getContributedSettings().addAll(project.getContributedSettings().values());
|
||||
|
||||
return setting;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,11 +1,51 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import static io.onedev.server.model.support.pullrequest.MergeStrategy.SQUASH_SOURCE_BRANCH_COMMITS;
|
||||
import static javax.ws.rs.core.Response.Status.NOT_ACCEPTABLE;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.PullRequestChangeManager;
|
||||
import io.onedev.server.entitymanager.PullRequestManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.git.service.GitService;
|
||||
import io.onedev.server.model.*;
|
||||
import io.onedev.server.model.Build;
|
||||
import io.onedev.server.model.PullRequest;
|
||||
import io.onedev.server.model.PullRequestAssignment;
|
||||
import io.onedev.server.model.PullRequestChange;
|
||||
import io.onedev.server.model.PullRequestComment;
|
||||
import io.onedev.server.model.PullRequestLabel;
|
||||
import io.onedev.server.model.PullRequestReview;
|
||||
import io.onedev.server.model.PullRequestReview.Status;
|
||||
import io.onedev.server.model.PullRequestUpdate;
|
||||
import io.onedev.server.model.PullRequestWatch;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.model.support.pullrequest.AutoMerge;
|
||||
import io.onedev.server.model.support.pullrequest.MergePreview;
|
||||
import io.onedev.server.model.support.pullrequest.MergeStrategy;
|
||||
@ -16,26 +56,6 @@ import io.onedev.server.rest.resource.support.RestConstants;
|
||||
import io.onedev.server.search.entity.pullrequest.PullRequestQuery;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import io.onedev.server.util.ProjectAndBranch;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static io.onedev.server.model.support.pullrequest.MergeStrategy.SQUASH_SOURCE_BRANCH_COMMITS;
|
||||
import static javax.ws.rs.core.Response.Status.NOT_ACCEPTABLE;
|
||||
|
||||
@Api(order=3000, description="In most cases, pull request resource is operated with pull request id, which is different from pull request number. "
|
||||
+ "To get pull request id of a particular pull request number, use the <a href='/~help/api/io.onedev.server.rest.PullRequestResource/queryBasicInfo'>Query Basic Info</a> operation with query for "
|
||||
@ -53,21 +73,24 @@ public class PullRequestResource {
|
||||
private final UserManager userManager;
|
||||
|
||||
private final GitService gitService;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public PullRequestResource(PullRequestManager pullRequestManager,
|
||||
PullRequestChangeManager pullRequestChangeManager,
|
||||
UserManager userManager, GitService gitService) {
|
||||
UserManager userManager, GitService gitService, AuditManager auditManager) {
|
||||
this.pullRequestManager = pullRequestManager;
|
||||
this.pullRequestChangeManager = pullRequestChangeManager;
|
||||
this.userManager = userManager;
|
||||
this.gitService = gitService;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{requestId}")
|
||||
@GET
|
||||
public PullRequest getBasicInfo(@PathParam("requestId") Long requestId) {
|
||||
public PullRequest getPullRequest(@PathParam("requestId") Long requestId) {
|
||||
PullRequest pullRequest = pullRequestManager.load(requestId);
|
||||
if (!SecurityUtils.canReadCode(pullRequest.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
@ -178,7 +201,7 @@ public class PullRequestResource {
|
||||
|
||||
@Api(order=1100)
|
||||
@GET
|
||||
public List<PullRequest> queryBasicInfo(
|
||||
public List<PullRequest> queryPullRequests(
|
||||
@QueryParam("query") @Api(description="Syntax of this query is the same as in <a href='/~pulls'>pull requests page</a>", example="to be reviewed by me") String query,
|
||||
@QueryParam("offset") @Api(example="0") int offset,
|
||||
@QueryParam("count") @Api(example="100") int count) {
|
||||
@ -198,7 +221,7 @@ public class PullRequestResource {
|
||||
|
||||
@Api(order=1200)
|
||||
@POST
|
||||
public Response create(@NotNull PullRequestOpenData data) {
|
||||
public Response createPullRequest(@NotNull PullRequestOpenData data) {
|
||||
User user = SecurityUtils.getUser();
|
||||
|
||||
ProjectAndBranch target = new ProjectAndBranch(data.getTargetProjectId(), data.getTargetBranch());
|
||||
@ -381,7 +404,7 @@ public class PullRequestResource {
|
||||
@Api(order=1600)
|
||||
@Path("/{requestId}/reopen")
|
||||
@POST
|
||||
public Response reopen(@PathParam("requestId") Long requestId, String note) {
|
||||
public Response reopenPullRequest(@PathParam("requestId") Long requestId, String note) {
|
||||
PullRequest request = pullRequestManager.load(requestId);
|
||||
if (!SecurityUtils.canModifyPullRequest(request))
|
||||
throw new UnauthorizedException();
|
||||
@ -396,7 +419,7 @@ public class PullRequestResource {
|
||||
@Api(order=1700)
|
||||
@Path("/{requestId}/discard")
|
||||
@POST
|
||||
public Response discard(@PathParam("requestId") Long requestId, String note) {
|
||||
public Response discardPullRequest(@PathParam("requestId") Long requestId, String note) {
|
||||
PullRequest request = pullRequestManager.load(requestId);
|
||||
if (!SecurityUtils.canModifyPullRequest(request))
|
||||
throw new UnauthorizedException();
|
||||
@ -410,7 +433,7 @@ public class PullRequestResource {
|
||||
@Api(order=1800)
|
||||
@Path("/{requestId}/merge")
|
||||
@POST
|
||||
public Response merge(@PathParam("requestId") Long requestId, String note) {
|
||||
public Response mergePullRequest(@PathParam("requestId") Long requestId, String note) {
|
||||
PullRequest request = pullRequestManager.load(requestId);
|
||||
var user = SecurityUtils.getUser();
|
||||
if (!SecurityUtils.canWriteCode(user.asSubject(), request.getProject()))
|
||||
@ -471,11 +494,13 @@ public class PullRequestResource {
|
||||
@Api(order=2100)
|
||||
@Path("/{requestId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("requestId") Long requestId) {
|
||||
public Response deletePullRequest(@PathParam("requestId") Long requestId) {
|
||||
PullRequest pullRequest = pullRequestManager.load(requestId);
|
||||
if (!SecurityUtils.canManagePullRequests(pullRequest.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
pullRequestManager.delete(pullRequest);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(pullRequest).toXML();
|
||||
pullRequestManager.delete(pullRequest);
|
||||
auditManager.audit(pullRequest.getProject(), "deleted pull request via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -1,30 +1,35 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.NotFoundException;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import io.onedev.server.entitymanager.LinkSpecManager;
|
||||
import io.onedev.server.model.LinkSpec;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.hibernate.criterion.MatchMode;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.RoleManager;
|
||||
import io.onedev.server.model.Role;
|
||||
import io.onedev.server.persistence.dao.EntityCriteria;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.rest.InvalidParamException;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.rest.resource.support.RestConstants;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import io.onedev.server.util.facade.RoleFacade;
|
||||
|
||||
@Api(order=7000)
|
||||
@Path("/roles")
|
||||
@ -35,26 +40,26 @@ public class RoleResource {
|
||||
|
||||
private final RoleManager roleManager;
|
||||
|
||||
private final LinkSpecManager linkSpecManager;
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public RoleResource(RoleManager roleManager, LinkSpecManager linkSpecManager) {
|
||||
public RoleResource(RoleManager roleManager, AuditManager auditManager) {
|
||||
this.roleManager = roleManager;
|
||||
this.linkSpecManager = linkSpecManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{roleId}")
|
||||
@GET
|
||||
public Role get(@PathParam("roleId") Long roleId) {
|
||||
public Role getRole(@PathParam("roleId") Long roleId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
return roleManager.load(roleId);
|
||||
}
|
||||
}
|
||||
|
||||
@Api(order=200)
|
||||
@GET
|
||||
public List<Role> query(@QueryParam("name") String name, @QueryParam("offset") @Api(example="0") int offset,
|
||||
public List<Role> queryRoles(@QueryParam("name") String name, @QueryParam("offset") @Api(example="0") int offset,
|
||||
@QueryParam("count") @Api(example="100") int count) {
|
||||
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
@ -67,50 +72,47 @@ public class RoleResource {
|
||||
if (name != null)
|
||||
criteria.add(Restrictions.ilike("name", name.replace('*', '%'), MatchMode.EXACT));
|
||||
|
||||
return roleManager.query(criteria, offset, count);
|
||||
return roleManager.query(name, offset, count);
|
||||
}
|
||||
|
||||
@Api(order=250)
|
||||
@Path("/ids/{name}")
|
||||
@GET
|
||||
public Long getId(@PathParam("name") String name) {
|
||||
public Long getRoleId(@PathParam("name") String name) {
|
||||
var role = roleManager.find(name);
|
||||
if (role != null)
|
||||
return role.getId();
|
||||
else
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
|
||||
@Api(order=300, description="Create new role")
|
||||
@POST
|
||||
public Long create(@NotNull Role role) {
|
||||
public Long createRole(@NotNull Role role) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
|
||||
Collection<LinkSpec> authorizedLinks = new ArrayList<>();
|
||||
for (String linkName: role.getEditableIssueLinks())
|
||||
authorizedLinks.add(linkSpecManager.find(linkName));
|
||||
|
||||
roleManager.create(role, authorizedLinks);
|
||||
|
||||
|
||||
roleManager.create(role, null);
|
||||
var auditContent = VersionedXmlDoc.fromBean(role).toXML();
|
||||
auditManager.audit(null, "created role \"" + role.getName() + "\" via RESTful API", null, auditContent);
|
||||
|
||||
return role.getId();
|
||||
}
|
||||
|
||||
@Api(order=350, description="Update role of specified id")
|
||||
@Path("/{roleId}")
|
||||
@POST
|
||||
public Response update(@PathParam("roleId") Long roleId, @NotNull Role role) {
|
||||
public Response updateRole(@PathParam("roleId") Long roleId, @NotNull Role role) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
|
||||
Collection<LinkSpec> authorizedLinks = new ArrayList<>();
|
||||
for (String linkName: role.getEditableIssueLinks())
|
||||
authorizedLinks.add(linkSpecManager.find(linkName));
|
||||
var oldAuditContent = role.getOldVersion().toXML();
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(role).toXML();
|
||||
|
||||
if (role.getOldVersion() != null)
|
||||
roleManager.update(role, authorizedLinks, ((RoleFacade) role.getOldVersion()).getName());
|
||||
else
|
||||
roleManager.update(role, authorizedLinks, null);
|
||||
var oldName = role.getOldVersion().getRootElement().elementText(Role.PROP_NAME);
|
||||
roleManager.update(role, null, oldName);
|
||||
|
||||
auditManager.audit(null, "changed role \"" + role.getName() + "\" via RESTful API", oldAuditContent, newAuditContent);
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
@ -118,11 +120,14 @@ public class RoleResource {
|
||||
@Api(order=400)
|
||||
@Path("/{roleId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("roleId") Long roleId) {
|
||||
public Response deleteRole(@PathParam("roleId") Long roleId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
roleManager.delete(roleManager.load(roleId));
|
||||
var role = roleManager.load(roleId);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(role).toXML();
|
||||
roleManager.delete(role);
|
||||
auditManager.audit(null, "deleted role \"" + role.getName() + "\" via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,26 +1,47 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.model.support.administration.mailservice.MailService;
|
||||
import io.onedev.server.model.support.administration.*;
|
||||
import io.onedev.server.model.support.administration.authenticator.Authenticator;
|
||||
import io.onedev.server.model.support.administration.emailtemplates.EmailTemplates;
|
||||
import io.onedev.server.model.support.administration.jobexecutor.JobExecutor;
|
||||
import io.onedev.server.model.support.administration.sso.SsoConnector;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.rest.InvalidParamException;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import io.onedev.server.web.page.layout.ContributedAdministrationSetting;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.SettingManager;
|
||||
import io.onedev.server.model.support.administration.BackupSetting;
|
||||
import io.onedev.server.model.support.administration.GlobalBuildSetting;
|
||||
import io.onedev.server.model.support.administration.GlobalIssueSetting;
|
||||
import io.onedev.server.model.support.administration.GlobalProjectSetting;
|
||||
import io.onedev.server.model.support.administration.GlobalPullRequestSetting;
|
||||
import io.onedev.server.model.support.administration.GroovyScript;
|
||||
import io.onedev.server.model.support.administration.SecuritySetting;
|
||||
import io.onedev.server.model.support.administration.ServiceDeskSetting;
|
||||
import io.onedev.server.model.support.administration.SshSetting;
|
||||
import io.onedev.server.model.support.administration.SystemSetting;
|
||||
import io.onedev.server.model.support.administration.authenticator.Authenticator;
|
||||
import io.onedev.server.model.support.administration.emailtemplates.EmailTemplates;
|
||||
import io.onedev.server.model.support.administration.jobexecutor.JobExecutor;
|
||||
import io.onedev.server.model.support.administration.mailservice.MailService;
|
||||
import io.onedev.server.model.support.administration.sso.SsoConnector;
|
||||
import io.onedev.server.rest.InvalidParamException;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import io.onedev.server.web.page.layout.ContributedAdministrationSetting;
|
||||
|
||||
@Api(order=10000)
|
||||
@Path("/settings")
|
||||
@ -30,10 +51,13 @@ import java.util.*;
|
||||
public class SettingResource {
|
||||
|
||||
private final SettingManager settingManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public SettingResource(SettingManager settingManager) {
|
||||
public SettingResource(SettingManager settingManager, AuditManager auditManager) {
|
||||
this.settingManager = settingManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@ -189,8 +213,10 @@ public class SettingResource {
|
||||
String ingressUrl = OneDev.getInstance().getIngressUrl();
|
||||
if (ingressUrl != null && !ingressUrl.equals(systemSetting.getServerUrl()))
|
||||
throw new InvalidParamException("Server URL can only be \"" + ingressUrl + "\"");
|
||||
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getSystemSetting()).toXML();
|
||||
settingManager.saveSystemSetting(systemSetting);
|
||||
auditManager.audit(null, "changed system setting via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(systemSetting).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -200,7 +226,10 @@ public class SettingResource {
|
||||
public Response setAuthenticator(Authenticator authenticator) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getAuthenticator()).toXML();
|
||||
settingManager.saveAuthenticator(authenticator);
|
||||
auditManager.audit(null, "changed authenticator via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(authenticator).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -210,7 +239,10 @@ public class SettingResource {
|
||||
public Response setBackupSetting(BackupSetting backupSetting) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getBackupSetting()).toXML();
|
||||
settingManager.saveBackupSetting(backupSetting);
|
||||
auditManager.audit(null, "changed backup settings via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(backupSetting).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -220,7 +252,10 @@ public class SettingResource {
|
||||
public Response setBuildSetting(@NotNull GlobalBuildSetting buildSetting) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getBuildSetting()).toXML();
|
||||
settingManager.saveBuildSetting(buildSetting);
|
||||
auditManager.audit(null, "changed build settings via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(buildSetting).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -230,7 +265,10 @@ public class SettingResource {
|
||||
public Response setGroovyScripts(@NotNull List<GroovyScript> groovyScripts) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getGroovyScripts()).toXML();
|
||||
settingManager.saveGroovyScripts(groovyScripts);
|
||||
auditManager.audit(null, "changed groovy scripts via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(groovyScripts).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -240,8 +278,11 @@ public class SettingResource {
|
||||
public Response setIssueSetting(@NotNull GlobalIssueSetting issueSetting) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getIssueSetting()).toXML();
|
||||
issueSetting.setReconciled(false);
|
||||
settingManager.saveIssueSetting(issueSetting);
|
||||
auditManager.audit(null, "changed issue settings via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(issueSetting).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -251,7 +292,10 @@ public class SettingResource {
|
||||
public Response setJobExecutors(@NotNull List<JobExecutor> jobExecutors) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getJobExecutors()).toXML();
|
||||
settingManager.saveJobExecutors(jobExecutors);
|
||||
auditManager.audit(null, "changed job executors via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(jobExecutors).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -261,7 +305,10 @@ public class SettingResource {
|
||||
public Response setMailService(MailService mailService) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getMailService()).toXML();
|
||||
settingManager.saveMailService(mailService);
|
||||
auditManager.audit(null, "changed mail service via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(mailService).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -271,7 +318,10 @@ public class SettingResource {
|
||||
public Response setServiceDeskSetting(ServiceDeskSetting serviceDeskSetting) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getServiceDeskSetting()).toXML();
|
||||
settingManager.saveServiceDeskSetting(serviceDeskSetting);
|
||||
auditManager.audit(null, "changed service desk settings via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(serviceDeskSetting).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -281,7 +331,10 @@ public class SettingResource {
|
||||
public Response setNotificationTemplateSetting(EmailTemplates emailTemplates) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getEmailTemplates()).toXML();
|
||||
settingManager.saveEmailTemplates(emailTemplates);
|
||||
auditManager.audit(null, "changed notification template via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(emailTemplates).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -291,7 +344,10 @@ public class SettingResource {
|
||||
public Response setProjectSetting(@NotNull GlobalProjectSetting projectSetting) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getProjectSetting()).toXML();
|
||||
settingManager.saveProjectSetting(projectSetting);
|
||||
auditManager.audit(null, "changed project settings via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(projectSetting).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -301,7 +357,10 @@ public class SettingResource {
|
||||
public Response setPullRequestSetting(@NotNull GlobalPullRequestSetting pullRequestSetting) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getPullRequestSetting()).toXML();
|
||||
settingManager.savePullRequestSetting(pullRequestSetting);
|
||||
auditManager.audit(null, "changed pull request settings via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(pullRequestSetting).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -311,7 +370,10 @@ public class SettingResource {
|
||||
public Response setSecuritySetting(@NotNull SecuritySetting securitySetting) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getSecuritySetting()).toXML();
|
||||
settingManager.saveSecuritySetting(securitySetting);
|
||||
auditManager.audit(null, "changed security settings via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(securitySetting).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -321,7 +383,10 @@ public class SettingResource {
|
||||
public Response setSshSetting(@NotNull SshSetting sshSetting) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getSshSetting()).toXML();
|
||||
settingManager.saveSshSetting(sshSetting);
|
||||
auditManager.audit(null, "changed ssh settings via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(sshSetting).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -331,20 +396,34 @@ public class SettingResource {
|
||||
public Response setSsoConnectors(@NotNull List<SsoConnector> ssoConnectors) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(settingManager.getSsoConnectors()).toXML();
|
||||
settingManager.saveSsoConnectors(ssoConnectors);
|
||||
auditManager.audit(null, "changed sso connectors via RESTful API",
|
||||
oldAuditContent, VersionedXmlDoc.fromBean(ssoConnectors).toXML());
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
private String getAuditContent(Map<String, ContributedAdministrationSetting> contributedSettings) {
|
||||
var list = new ArrayList<ContributedAdministrationSetting>();
|
||||
for (var entry: contributedSettings.entrySet())
|
||||
list.add(entry.getValue());
|
||||
Collections.sort(list, (a, b) -> {return a.getClass().getName().compareTo(b.getClass().getName());});
|
||||
return VersionedXmlDoc.fromBean(list).toXML();
|
||||
}
|
||||
|
||||
@Api(order=2800)
|
||||
@Path("/contributed-settings")
|
||||
@POST
|
||||
public Response setContributedSettings(@NotNull List<ContributedAdministrationSetting> contributedSettings) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
var oldAuditContent = getAuditContent(settingManager.getContributedSettings());
|
||||
var settingMap = new HashMap<String, ContributedAdministrationSetting>();
|
||||
for (var setting: contributedSettings)
|
||||
settingMap.put(setting.getClass().getName(), setting);
|
||||
settingManager.saveContributedSettings(settingMap);
|
||||
auditManager.audit(null, "changed contributed settings via RESTful API",
|
||||
oldAuditContent, getAuditContent(settingMap));
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import static io.onedev.server.security.SecurityUtils.getAuthUser;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -16,6 +18,8 @@ import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.SshKeyManager;
|
||||
import io.onedev.server.model.SshKey;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
@ -30,42 +34,53 @@ public class SshKeyResource {
|
||||
|
||||
private final SshKeyManager sshKeyManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public SshKeyResource(SshKeyManager sshKeyManager) {
|
||||
public SshKeyResource(SshKeyManager sshKeyManager, AuditManager auditManager) {
|
||||
this.sshKeyManager = sshKeyManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100)
|
||||
@Path("/{sshKeyId}")
|
||||
@GET
|
||||
public SshKey get(@PathParam("sshKeyId") Long sshKeyId) {
|
||||
public SshKey getKey(@PathParam("sshKeyId") Long sshKeyId) {
|
||||
SshKey sshKey = sshKeyManager.load(sshKeyId);
|
||||
if (!SecurityUtils.isAdministrator() && !sshKey.getOwner().equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !sshKey.getOwner().equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return sshKey;
|
||||
}
|
||||
|
||||
@Api(order=150, description="Create new ssh key")
|
||||
@POST
|
||||
public Long create(SshKey sshKey) {
|
||||
if (!SecurityUtils.isAdministrator() && !sshKey.getOwner().equals(SecurityUtils.getAuthUser()))
|
||||
public Long createKey(SshKey sshKey) {
|
||||
if (!SecurityUtils.isAdministrator() && !sshKey.getOwner().equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
sshKey.setCreatedAt(new Date());
|
||||
sshKey.fingerprint();
|
||||
sshKey.generateFingerprint();
|
||||
|
||||
sshKeyManager.create(sshKey);
|
||||
if (!getAuthUser().equals(sshKey.getOwner())) {
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(sshKey).toXML();
|
||||
auditManager.audit(null, "created ssh key for account \"" + sshKey.getOwner().getName() + "\" via RESTful API", null, newAuditContent);
|
||||
}
|
||||
return sshKey.getId();
|
||||
}
|
||||
|
||||
@Api(order=200)
|
||||
@Path("/{sshKeyId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("sshKeyId") Long sshKeyId) {
|
||||
public Response deleteKey(@PathParam("sshKeyId") Long sshKeyId) {
|
||||
SshKey sshKey = sshKeyManager.load(sshKeyId);
|
||||
if (!SecurityUtils.isAdministrator() && !sshKey.getOwner().equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !sshKey.getOwner().equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
sshKeyManager.delete(sshKey);
|
||||
if (!getAuthUser().equals(sshKey.getOwner())) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(sshKey).toXML();
|
||||
auditManager.audit(null, "deleted ssh key for account \"" + sshKey.getOwner().getName() + "\" via RESTful API", oldAuditContent, null);
|
||||
}
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +1,27 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import io.onedev.server.entitymanager.UserAuthorizationManager;
|
||||
import io.onedev.server.model.UserAuthorization;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.ws.rs.*;
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.PathParam;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.UserAuthorizationManager;
|
||||
import io.onedev.server.model.UserAuthorization;
|
||||
import io.onedev.server.rest.annotation.Api;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
|
||||
@Api(order=8000)
|
||||
@Path("/user-authorizations")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@ -22,15 +31,18 @@ public class UserAuthorizationResource {
|
||||
|
||||
private final UserAuthorizationManager authorizationManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public UserAuthorizationResource(UserAuthorizationManager authorizationManager) {
|
||||
public UserAuthorizationResource(UserAuthorizationManager authorizationManager, AuditManager auditManager) {
|
||||
this.authorizationManager = authorizationManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
@Api(order=100, description = "Get user authorization of specified id")
|
||||
@Path("/{authorizationId}")
|
||||
@GET
|
||||
public UserAuthorization get(@PathParam("authorizationId") Long authorizationId) {
|
||||
public UserAuthorization getAuthorization(@PathParam("authorizationId") Long authorizationId) {
|
||||
UserAuthorization authorization = authorizationManager.load(authorizationId);
|
||||
if (!SecurityUtils.canManageProject(authorization.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
@ -39,21 +51,25 @@ public class UserAuthorizationResource {
|
||||
|
||||
@Api(order=200, description="Create user authorization")
|
||||
@POST
|
||||
public Long create(@NotNull UserAuthorization authorization) {
|
||||
public Long createAuthorization(@NotNull UserAuthorization authorization) {
|
||||
if (!SecurityUtils.canManageProject(authorization.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
authorizationManager.createOrUpdate(authorization);
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(authorization).toXML();
|
||||
auditManager.audit(null, "created user authorization via RESTful API", null, newAuditContent);
|
||||
return authorization.getId();
|
||||
}
|
||||
|
||||
@Api(order=300, description = "Delete user authorization of specified id")
|
||||
@Path("/{authorizationId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("authorizationId") Long authorizationId) {
|
||||
public Response deleteAuthorization(@PathParam("authorizationId") Long authorizationId) {
|
||||
UserAuthorization authorization = authorizationManager.load(authorizationId);
|
||||
if (!SecurityUtils.canManageProject(authorization.getProject()))
|
||||
throw new UnauthorizedException();
|
||||
authorizationManager.delete(authorization);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(authorization).toXML();
|
||||
auditManager.audit(null, "deleted user authorization via RESTful API", oldAuditContent, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package io.onedev.server.rest.resource;
|
||||
|
||||
import static io.onedev.server.security.SecurityUtils.getAuthUser;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import java.io.Serializable;
|
||||
@ -30,11 +31,12 @@ import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
|
||||
import org.apache.shiro.authc.credential.PasswordService;
|
||||
import org.apache.shiro.authz.UnauthenticatedException;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.annotation.UserName;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.EmailAddressManager;
|
||||
import io.onedev.server.entitymanager.SshKeyManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
@ -76,45 +78,48 @@ public class UserResource {
|
||||
private final PasswordService passwordService;
|
||||
|
||||
private final EmailAddressManager emailAddressManager;
|
||||
|
||||
private final AuditManager auditManager;
|
||||
|
||||
@Inject
|
||||
public UserResource(UserManager userManager, SshKeyManager sshKeyManager,
|
||||
PasswordService passwordService, EmailAddressManager emailAddressManager) {
|
||||
PasswordService passwordService, EmailAddressManager emailAddressManager, AuditManager auditManager) {
|
||||
this.userManager = userManager;
|
||||
this.sshKeyManager = sshKeyManager;
|
||||
this.passwordService = passwordService;
|
||||
this.emailAddressManager = emailAddressManager;
|
||||
this.auditManager = auditManager;
|
||||
}
|
||||
|
||||
private BasicSetting getBasicSetting(User user) {
|
||||
var basicSetting = new BasicSetting();
|
||||
basicSetting.setDisabled(user.isDisabled());
|
||||
basicSetting.setServiceAccount(user.isServiceAccount());
|
||||
basicSetting.setName(user.getName());
|
||||
basicSetting.setFullName(user.getFullName());
|
||||
private UserData getData(User user) {
|
||||
var data = new UserData();
|
||||
data.setDisabled(user.isDisabled());
|
||||
data.setServiceAccount(user.isServiceAccount());
|
||||
data.setName(user.getName());
|
||||
data.setFullName(user.getFullName());
|
||||
if (!user.isServiceAccount())
|
||||
basicSetting.setNotifyOwnEvents(user.isNotifyOwnEvents());
|
||||
return basicSetting;
|
||||
data.setNotifyOwnEvents(user.isNotifyOwnEvents());
|
||||
return data;
|
||||
}
|
||||
|
||||
@Api(order=100, name="Get Basic Settings")
|
||||
@Api(order=100)
|
||||
@Path("/{userId}")
|
||||
@GET
|
||||
public BasicSetting getBasicSetting(@PathParam("userId") Long userId) {
|
||||
public UserData getUser(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return getBasicSetting(user);
|
||||
return getData(user);
|
||||
}
|
||||
|
||||
@Api(order=200, name="Get Basic Settings of Current User")
|
||||
@Api(order=200)
|
||||
@Path("/me")
|
||||
@GET
|
||||
public BasicSetting getMyBasicSetting() {
|
||||
User user = SecurityUtils.getAuthUser();
|
||||
public UserData getMe() {
|
||||
User user = getAuthUser();
|
||||
if (user == null)
|
||||
throw new UnauthorizedException();
|
||||
return getBasicSetting(user);
|
||||
return getData(user);
|
||||
}
|
||||
|
||||
@Api(order=250)
|
||||
@ -122,7 +127,7 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<AccessToken> getAccessTokens(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getAccessTokens();
|
||||
}
|
||||
@ -132,7 +137,7 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<EmailAddress> getEmailAddresses(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getEmailAddresses();
|
||||
}
|
||||
@ -160,7 +165,7 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<PullRequestReview> getPullRequestReviews(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getPullRequestReviews();
|
||||
}
|
||||
@ -170,7 +175,7 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<IssueVote> getIssueVotes(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getIssueVotes();
|
||||
}
|
||||
@ -180,7 +185,7 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<IssueWatch> getIssueWatches(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getIssueWatches();
|
||||
}
|
||||
@ -190,7 +195,7 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<BuildQueryPersonalization> getProjectBuildQueryPersonalizations(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getBuildQueryPersonalizations();
|
||||
}
|
||||
@ -200,7 +205,7 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<CodeCommentQueryPersonalization> getProjectCodeCommentQueryPersonalizations(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getCodeCommentQueryPersonalizations();
|
||||
}
|
||||
@ -210,7 +215,7 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<CommitQueryPersonalization> getProjectCommitQueryPersonalizations(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getCommitQueryPersonalizations();
|
||||
}
|
||||
@ -220,7 +225,7 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<IssueQueryPersonalization> getProjecIssueQueryPersonalizations(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getIssueQueryPersonalizations();
|
||||
}
|
||||
@ -230,7 +235,7 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<PullRequestQueryPersonalization> getProjecPullRequestQueryPersonalizations(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getPullRequestQueryPersonalizations();
|
||||
}
|
||||
@ -240,7 +245,7 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<PullRequestAssignment> getPullRequestAssignments(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getPullRequestAssignments();
|
||||
}
|
||||
@ -250,7 +255,7 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<PullRequestWatch> getPullRequestWatches(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getPullRequestWatches();
|
||||
}
|
||||
@ -260,18 +265,12 @@ public class UserResource {
|
||||
@GET
|
||||
public Collection<SshKey> getSshKeys(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return user.getSshKeys();
|
||||
}
|
||||
|
||||
@Api(order=1700)
|
||||
@Path("/{userId}/queries-and-watches")
|
||||
@GET
|
||||
public QueriesAndWatches getQueriesAndWatches(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
private QueriesAndWatches getQueriesAndWatches(User user) {
|
||||
QueriesAndWatches queriesAndWatches = new QueriesAndWatches();
|
||||
queriesAndWatches.buildQuerySubscriptions = user.getBuildQuerySubscriptions();
|
||||
queriesAndWatches.issueQueryWatches = user.getIssueQueryWatches();
|
||||
@ -281,24 +280,34 @@ public class UserResource {
|
||||
queriesAndWatches.projectQueries = user.getProjectQueries();
|
||||
queriesAndWatches.pullRequestQueries = user.getPullRequestQueries();
|
||||
return queriesAndWatches;
|
||||
}
|
||||
|
||||
@Api(order=1700)
|
||||
@Path("/{userId}/queries-and-watches")
|
||||
@GET
|
||||
public QueriesAndWatches getQueriesAndWatches(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
return getQueriesAndWatches(user);
|
||||
}
|
||||
|
||||
@Api(order=1800, name="Query Basic Settings")
|
||||
@Api(order=1800)
|
||||
@GET
|
||||
public List<BasicSetting> queryBasicSetting(
|
||||
public List<UserData> queryUsers(
|
||||
@QueryParam("term") @Api(description="Any string in login name, full name or email address") String term,
|
||||
@QueryParam("offset") @Api(example="0") int offset,
|
||||
@QueryParam("count") @Api(example="100") int count) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
|
||||
return userManager.query(term, offset, count).stream().map(this::getBasicSetting).collect(toList());
|
||||
return userManager.query(term, offset, count).stream().map(this::getData).collect(toList());
|
||||
}
|
||||
|
||||
@Api(order=1850)
|
||||
@Path("/ids/{name}")
|
||||
@GET
|
||||
public Long getId(@PathParam("name") @Api(description = "Login name of user") String name) {
|
||||
public Long getUserId(@PathParam("name") @Api(description = "Login name of user") String name) {
|
||||
var user = userManager.findByName(name);
|
||||
if (user != null)
|
||||
return user.getId();
|
||||
@ -308,87 +317,105 @@ public class UserResource {
|
||||
|
||||
@Api(order=1900, description="Create new user")
|
||||
@POST
|
||||
public Long create(@NotNull @Valid UserCreateData data) {
|
||||
if (SecurityUtils.isAdministrator()) {
|
||||
if (userManager.findByName(data.getName()) != null)
|
||||
throw new ExplicitException("Login name is already used by another user");
|
||||
if (!data.isServiceAccount() && emailAddressManager.findByValue(data.getEmailAddress()) != null)
|
||||
throw new ExplicitException("Email address is already used by another user");
|
||||
|
||||
User user = new User();
|
||||
user.setServiceAccount(data.isServiceAccount());
|
||||
user.setName(data.getName());
|
||||
user.setFullName(data.getFullName());
|
||||
if (data.isServiceAccount()) {
|
||||
userManager.create(user);
|
||||
} else {
|
||||
user.setNotifyOwnEvents(data.isNotifyOwnEvents());
|
||||
user.setPassword(passwordService.encryptPassword(data.getPassword()));
|
||||
userManager.create(user);
|
||||
EmailAddress emailAddress = new EmailAddress();
|
||||
emailAddress.setGit(true);
|
||||
emailAddress.setPrimary(true);
|
||||
emailAddress.setOwner(user);
|
||||
emailAddress.setValue(data.getEmailAddress());
|
||||
emailAddress.setVerificationCode(null);
|
||||
emailAddressManager.create(emailAddress);
|
||||
}
|
||||
return user.getId();
|
||||
public Long createUser(@NotNull @Valid UserCreateData data) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
|
||||
if (userManager.findByName(data.getName()) != null)
|
||||
throw new ExplicitException("Login name is already used by another user");
|
||||
if (!data.isServiceAccount() && emailAddressManager.findByValue(data.getEmailAddress()) != null)
|
||||
throw new ExplicitException("Email address is already used by another user");
|
||||
|
||||
User user = new User();
|
||||
user.setServiceAccount(data.isServiceAccount());
|
||||
user.setName(data.getName());
|
||||
user.setFullName(data.getFullName());
|
||||
if (data.isServiceAccount()) {
|
||||
userManager.create(user);
|
||||
} else {
|
||||
throw new UnauthenticatedException();
|
||||
user.setNotifyOwnEvents(data.isNotifyOwnEvents());
|
||||
user.setPassword(passwordService.encryptPassword(data.getPassword()));
|
||||
userManager.create(user);
|
||||
EmailAddress emailAddress = new EmailAddress();
|
||||
emailAddress.setGit(true);
|
||||
emailAddress.setPrimary(true);
|
||||
emailAddress.setOwner(user);
|
||||
emailAddress.setValue(data.getEmailAddress());
|
||||
emailAddress.setVerificationCode(null);
|
||||
emailAddressManager.create(emailAddress);
|
||||
}
|
||||
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(user).toXML();
|
||||
auditManager.audit(null, "created account \"" + user.getName() + "\" via RESTful API", null, newAuditContent);
|
||||
|
||||
return user.getId();
|
||||
}
|
||||
|
||||
@Api(order=1950, name="Update Basic Settings")
|
||||
@Api(order=1950, name="Update user")
|
||||
@Path("/{userId}")
|
||||
@POST
|
||||
public Response updateBasicSetting(@PathParam("userId") Long userId, @NotNull @Valid BasicSettingUpdateData data) {
|
||||
public Response updateUser(@PathParam("userId") Long userId, @NotNull @Valid UserUpdateData data) {
|
||||
User user = userManager.load(userId);
|
||||
if (SecurityUtils.isAdministrator() || user.equals(SecurityUtils.getAuthUser())) {
|
||||
User existingUser = userManager.findByName(data.getName());
|
||||
if (existingUser != null && !existingUser.equals(user))
|
||||
throw new ExplicitException("Login name is already used by another user");
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
|
||||
String oldName = user.getName();
|
||||
user.setName(data.getName());
|
||||
user.setFullName(data.getFullName());
|
||||
if (!user.isServiceAccount())
|
||||
user.setNotifyOwnEvents(data.isNotifyOwnEvents());
|
||||
userManager.update(user, oldName);
|
||||
return Response.ok().build();
|
||||
} else {
|
||||
throw new UnauthenticatedException();
|
||||
User existingUser = userManager.findByName(data.getName());
|
||||
if (existingUser != null && !existingUser.equals(user))
|
||||
throw new ExplicitException("Login name is already used by another user");
|
||||
|
||||
var oldData = new UserUpdateData();
|
||||
oldData.setName(user.getName());
|
||||
oldData.setFullName(user.getFullName());
|
||||
oldData.setNotifyOwnEvents(user.isNotifyOwnEvents());
|
||||
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(oldData).toXML();
|
||||
|
||||
String oldName = user.getName();
|
||||
user.setName(data.getName());
|
||||
user.setFullName(data.getFullName());
|
||||
if (!user.isServiceAccount())
|
||||
user.setNotifyOwnEvents(data.isNotifyOwnEvents());
|
||||
userManager.update(user, oldName);
|
||||
|
||||
if (!getAuthUser().equals(user)) {
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(data).toXML();
|
||||
auditManager.audit(null, "changed account \"" + user.getName() + "\" via RESTful API", oldAuditContent, newAuditContent);
|
||||
}
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@Api(order=1960, description="Disable user")
|
||||
@Path("/{userId}/disable")
|
||||
@POST
|
||||
public Response disable(@PathParam("userId") Long userId) {
|
||||
if (SecurityUtils.isAdministrator()) {
|
||||
if (userId <= User.ROOT_ID)
|
||||
throw new BadRequestException("Should only disable normal users");
|
||||
var user = userManager.load(userId);
|
||||
userManager.disable(user);
|
||||
return Response.ok().build();
|
||||
} else {
|
||||
throw new UnauthenticatedException();
|
||||
}
|
||||
public Response disableUser(@PathParam("userId") Long userId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
|
||||
if (userId <= User.ROOT_ID)
|
||||
throw new BadRequestException("Should only disable normal users");
|
||||
var user = userManager.load(userId);
|
||||
userManager.disable(user);
|
||||
|
||||
auditManager.audit(null, "disabled account \"" + user.getName() + "\" via RESTful API", null, null);
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@Api(order=1970, description="Enable user")
|
||||
@Path("/{userId}/enable")
|
||||
@POST
|
||||
public Response enable(@PathParam("userId") Long userId) {
|
||||
if (SecurityUtils.isAdministrator()) {
|
||||
if (userId <= User.ROOT_ID)
|
||||
throw new BadRequestException("Should only enable normal users");
|
||||
var user = userManager.load(userId);
|
||||
userManager.enable(user);
|
||||
return Response.ok().build();
|
||||
} else {
|
||||
throw new UnauthenticatedException();
|
||||
}
|
||||
public Response enableUser(@PathParam("userId") Long userId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
if (userId <= User.ROOT_ID)
|
||||
throw new BadRequestException("Should only enable normal users");
|
||||
var user = userManager.load(userId);
|
||||
userManager.enable(user);
|
||||
|
||||
auditManager.audit(null, "enabled account \"" + user.getName() + "\" via RESTful API", null, null);
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@Api(order=2000)
|
||||
@ -399,12 +426,14 @@ public class UserResource {
|
||||
if (SecurityUtils.isAdministrator()) {
|
||||
user.setPassword(passwordService.encryptPassword(password));
|
||||
userManager.update(user, null);
|
||||
if (!getAuthUser().equals(user))
|
||||
auditManager.audit(null, "changed password of account \"" + user.getName() + "\" via RESTful API", null, null);
|
||||
return Response.ok().build();
|
||||
} else if (user.isDisabled()) {
|
||||
throw new ExplicitException("Can not set password for disabled user");
|
||||
} else if (user.isServiceAccount()) {
|
||||
throw new ExplicitException("Can not set password for service account");
|
||||
} else if (user.equals(SecurityUtils.getAuthUser())) {
|
||||
} else if (user.equals(getAuthUser())) {
|
||||
if (user.getPassword() == null) {
|
||||
throw new ExplicitException("The user is currently authenticated via external system, "
|
||||
+ "please change password there instead");
|
||||
@ -422,16 +451,18 @@ public class UserResource {
|
||||
@Path("/{userId}/two-factor-authentication")
|
||||
@DELETE
|
||||
public Response resetTwoFactorAuthentication(@PathParam("userId") Long userId) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator()) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
} else if (user.isDisabled()) {
|
||||
|
||||
User user = userManager.load(userId);
|
||||
if (user.isDisabled()) {
|
||||
throw new ExplicitException("Can not reset two factor authentication for disabled user");
|
||||
} else if (user.isServiceAccount()) {
|
||||
throw new ExplicitException("Can not reset two factor authentication for service account");
|
||||
} else {
|
||||
user.setTwoFactorAuthentication(null);
|
||||
userManager.update(user, null);
|
||||
auditManager.audit(null, "reset two factor authentication of account \"" + user.getName() + "\" via RESTful API", null, null);
|
||||
return Response.ok().build();
|
||||
}
|
||||
}
|
||||
@ -441,12 +472,16 @@ public class UserResource {
|
||||
@POST
|
||||
public Response setQueriesAndWatches(@PathParam("userId") Long userId, @NotNull QueriesAndWatches queriesAndWatches) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
else if (user.isDisabled())
|
||||
|
||||
if (user.isDisabled())
|
||||
throw new ExplicitException("Can not set queries and watches for disabled user");
|
||||
else if (user.isServiceAccount())
|
||||
throw new ExplicitException("Can not set queries and watches for service account");
|
||||
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(getQueriesAndWatches(user)).toXML();
|
||||
|
||||
user.setBuildQuerySubscriptions(queriesAndWatches.buildQuerySubscriptions);
|
||||
user.setIssueQueryWatches(queriesAndWatches.issueQueryWatches);
|
||||
user.setPullRequestQueryWatches(queriesAndWatches.pullRequestQueryWatches);
|
||||
@ -456,6 +491,12 @@ public class UserResource {
|
||||
user.setProjectQueries(queriesAndWatches.projectQueries);
|
||||
user.setPullRequestQueries(queriesAndWatches.pullRequestQueries);
|
||||
userManager.update(user, null);
|
||||
|
||||
if (!getAuthUser().equals(user)) {
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(queriesAndWatches).toXML();
|
||||
auditManager.audit(null, "changed queries and watches of account \"" + user.getName() + "\" via RESTful API", oldAuditContent, newAuditContent);
|
||||
}
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
@ -464,37 +505,109 @@ public class UserResource {
|
||||
@POST
|
||||
public Long addSshKey(@PathParam("userId") Long userId, @NotNull String content) {
|
||||
User user = userManager.load(userId);
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(SecurityUtils.getAuthUser()))
|
||||
if (!SecurityUtils.isAdministrator() && !user.equals(getAuthUser()))
|
||||
throw new UnauthorizedException();
|
||||
else if (user.isDisabled())
|
||||
|
||||
if (user.isDisabled())
|
||||
throw new ExplicitException("Can not add ssh key for disabled user");
|
||||
|
||||
SshKey sshKey = new SshKey();
|
||||
sshKey.setContent(content);
|
||||
sshKey.setCreatedAt(new Date());
|
||||
sshKey.setOwner(user);
|
||||
sshKey.fingerprint();
|
||||
sshKey.generateFingerprint();
|
||||
|
||||
sshKeyManager.create(sshKey);
|
||||
|
||||
if (!getAuthUser().equals(user)) {
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(sshKey).toXML();
|
||||
auditManager.audit(null, "added ssh key to account \"" + user.getName() + "\" via RESTful API", null, newAuditContent);
|
||||
}
|
||||
|
||||
return sshKey.getId();
|
||||
}
|
||||
|
||||
@Api(order=2300)
|
||||
@Path("/{userId}")
|
||||
@DELETE
|
||||
public Response delete(@PathParam("userId") Long userId) {
|
||||
public Response deleteUser(@PathParam("userId") Long userId) {
|
||||
if (!SecurityUtils.isAdministrator())
|
||||
throw new UnauthorizedException();
|
||||
|
||||
User user = userManager.load(userId);
|
||||
if (user.isRoot())
|
||||
throw new ExplicitException("Root user can not be deleted");
|
||||
else if (user.equals(SecurityUtils.getAuthUser()))
|
||||
else if (user.equals(getAuthUser()))
|
||||
throw new ExplicitException("Can not delete yourself");
|
||||
else
|
||||
userManager.delete(user);
|
||||
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(getData(user)).toXML();
|
||||
auditManager.audit(null, "deleted account \"" + user.getName() + "\" via RESTful API", oldAuditContent, null);
|
||||
|
||||
return Response.ok().build();
|
||||
}
|
||||
|
||||
public static class UserData implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Api(order=10, description="Whether or not the user is disabled")
|
||||
private boolean disabled;
|
||||
|
||||
@Api(order=50, description="Whether or not the user is a service account")
|
||||
private boolean serviceAccount;
|
||||
|
||||
@Api(order=100, description="Login name of the user")
|
||||
private String name;
|
||||
|
||||
@Api(order=200)
|
||||
private String fullName;
|
||||
|
||||
@Api(order=300, description = "Whether or not to notify user on own events. Only meaningful for non service account")
|
||||
private boolean notifyOwnEvents;
|
||||
|
||||
public boolean isDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
|
||||
public void setDisabled(boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
public boolean isServiceAccount() {
|
||||
return serviceAccount;
|
||||
}
|
||||
|
||||
public void setServiceAccount(boolean serviceAccount) {
|
||||
this.serviceAccount = serviceAccount;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
public void setFullName(String fullName) {
|
||||
this.fullName = fullName;
|
||||
}
|
||||
|
||||
public boolean isNotifyOwnEvents() {
|
||||
return notifyOwnEvents;
|
||||
}
|
||||
|
||||
public void setNotifyOwnEvents(boolean notifyOwnEvents) {
|
||||
this.notifyOwnEvents = notifyOwnEvents;
|
||||
}
|
||||
}
|
||||
|
||||
@EntityCreate(User.class)
|
||||
public static class UserCreateData implements Serializable {
|
||||
|
||||
@ -577,66 +690,7 @@ public class UserResource {
|
||||
}
|
||||
}
|
||||
|
||||
public static class BasicSetting implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Api(order=10, description="Whether or not the user is disabled")
|
||||
private boolean disabled;
|
||||
|
||||
@Api(order=50, description="Whether or not the user is a service account")
|
||||
private boolean serviceAccount;
|
||||
|
||||
@Api(order=100, description="Login name of the user")
|
||||
private String name;
|
||||
|
||||
@Api(order=200)
|
||||
private String fullName;
|
||||
|
||||
@Api(order=300, description = "Whether or not to notify user on own events. Only meaningful for non service account")
|
||||
private boolean notifyOwnEvents;
|
||||
|
||||
public boolean isDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
|
||||
public void setDisabled(boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
public boolean isServiceAccount() {
|
||||
return serviceAccount;
|
||||
}
|
||||
|
||||
public void setServiceAccount(boolean serviceAccount) {
|
||||
this.serviceAccount = serviceAccount;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
|
||||
public void setFullName(String fullName) {
|
||||
this.fullName = fullName;
|
||||
}
|
||||
|
||||
public boolean isNotifyOwnEvents() {
|
||||
return notifyOwnEvents;
|
||||
}
|
||||
|
||||
public void setNotifyOwnEvents(boolean notifyOwnEvents) {
|
||||
this.notifyOwnEvents = notifyOwnEvents;
|
||||
}
|
||||
}
|
||||
|
||||
public static class BasicSettingUpdateData implements Serializable {
|
||||
public static class UserUpdateData implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
package io.onedev.server.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.From;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.support.ProjectBelonging;
|
||||
@ -42,4 +48,16 @@ public class ProjectScope {
|
||||
}
|
||||
}
|
||||
|
||||
public Predicate buildPredicates(CriteriaBuilder builder, From<Project, Project> root) {
|
||||
List<Predicate> predicates = new ArrayList<>();
|
||||
predicates.add(builder.equal(root, getProject()));
|
||||
if (isInherited()) {
|
||||
for (var ancestor: getProject().getAncestors())
|
||||
predicates.add(builder.equal(root, ancestor));
|
||||
}
|
||||
if (isRecursive())
|
||||
predicates.add(builder.like(root.get(Project.PROP_PATH), getProject().getPath() + "/%"));
|
||||
return builder.or(predicates.toArray(new Predicate[0]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,5 +1,10 @@
|
||||
package io.onedev.server.util.jackson.hibernate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Stack;
|
||||
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
@ -8,13 +13,11 @@ import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.deser.BeanDeserializer;
|
||||
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.model.AbstractEntity;
|
||||
import io.onedev.server.persistence.dao.Dao;
|
||||
import io.onedev.server.rest.annotation.Immutable;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Stack;
|
||||
|
||||
public class EntityDeserializer extends BeanDeserializer {
|
||||
|
||||
@ -52,7 +55,7 @@ public class EntityDeserializer extends BeanDeserializer {
|
||||
&& paramsStack.get().peek()[0] instanceof Long) {
|
||||
Long entityId = (Long) paramsStack.get().peek()[0];
|
||||
AbstractEntity entity = dao.load(entityClass, entityId);
|
||||
entity.setOldVersion(entity.getFacade());
|
||||
entity.setOldVersion(VersionedXmlDoc.fromBean(entity));
|
||||
|
||||
Object bean;
|
||||
if (entity instanceof HibernateProxy)
|
||||
|
||||
@ -0,0 +1,7 @@
|
||||
package io.onedev.server.util.xstream;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
public class ObjectMap extends LinkedHashMap<String, Object> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package io.onedev.server.util.xstream;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.thoughtworks.xstream.converters.Converter;
|
||||
import com.thoughtworks.xstream.converters.MarshallingContext;
|
||||
import com.thoughtworks.xstream.converters.UnmarshallingContext;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
|
||||
public class ObjectMapperConverter implements Converter {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean canConvert(Class type) {
|
||||
return type == ObjectMap.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) {
|
||||
ObjectMap map = (ObjectMap) source;
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
if (entry.getValue() != null) {
|
||||
writer.startNode(entry.getKey());
|
||||
context.convertAnother(entry.getValue());
|
||||
writer.endNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1750603967318" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11693" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M411.605333 180.394667c-26.581333 20.096-48.469333 54.144-48.469333 115.114666 0 60.885333 21.162667 96.938667 42.709333 123.477334a417.024 417.024 0 0 0 20.992 23.722666c4.693333 5.12 9.813333 10.538667 14.208 15.658667 9.557333 11.093333 26.666667 31.914667 26.666667 59.605333v4.138667c0 16.938667 0.042667 36.565333-3.754667 51.413333-2.346667 9.386667-7.509333 22.570667-19.882666 32.853334-12.885333 10.666667-27.477333 13.226667-38.613334 13.226666H213.418667L213.333333 725.333333h597.333334v-105.770666h-191.317334c-4.693333 0-18.005333 0-30.933333-7.509334a53.845333 53.845333 0 0 1-24.746667-34.005333 126.805333 126.805333 0 0 1-3.157333-27.008c-0.298667-8.746667-0.298667-19.626667-0.298667-32.426667v-0.64c0-28.330667 14.208-49.408 25.856-63.701333 5.845333-7.168 12.458667-14.208 18.261334-20.437333l0.298666-0.298667c6.186667-6.656 11.946667-12.842667 17.706667-19.626667 21.205333-25.002667 41.898667-57.898667 41.898667-118.4 0-62.549333-20.48-96.554667-44.458667-115.968-25.6-20.778667-61.824-30.208-100.949333-30.208-39.253333 0-78.677333 9.514667-107.221334 31.061334zM360.149333 112.341333C408.32 75.946667 468.053333 64 518.826667 64c50.901333 0 108.714667 12.032 154.666666 49.194667 47.530667 38.528 76.074667 98.944 76.074667 182.314666 0 85.461333-31.317333 137.173333-62.122667 173.568-7.082667 8.362667-14.08 15.872-20.010666 22.186667l-0.426667 0.512a346.752 346.752 0 0 0-14.805333 16.469333 37.802667 37.802667 0 0 0-6.656 9.984v16h186.453333a64 64 0 0 1 64 64V768a42.666667 42.666667 0 0 1-42.666667 42.666667H170.666667a42.666667 42.666667 0 0 1-42.666667-42.666667l0.085333-169.813333a64 64 0 0 1 64-63.957334H382.293333l0.085334-12.458666a78.72 78.72 0 0 0-6.016-7.722667c-3.285333-3.84-6.912-7.722667-11.434667-12.586667a500.224 500.224 0 0 1-25.301333-28.629333c-30.72-37.802667-61.866667-92.245333-61.866667-177.322667 0.042667-84.906667 32.341333-145.322667 82.389333-183.168zM128 896a42.666667 42.666667 0 0 1 42.666667-42.666667h682.666666a42.666667 42.666667 0 1 1 0 85.333334H170.666667a42.666667 42.666667 0 0 1-42.666667-42.666667z" p-id="11694"></path></svg>
|
||||
|
After Width: | Height: | Size: 2.4 KiB |
@ -0,0 +1,34 @@
|
||||
<wicket:panel>
|
||||
<div class="audit-list no-autofocus">
|
||||
<div class="head align-items-center d-none d-lg-flex">
|
||||
<div class="clearable-wrapper date-range mr-2">
|
||||
<input wicket:id="dateRange" t:placeholder="Filter date range" class="form-control form-control-sm">
|
||||
</div>
|
||||
<input wicket:id="users" type="hidden" t:placeholder="Filter users" class="form-control form-control-sm users mr-2">
|
||||
<div class="clearable-wrapper action mr-2">
|
||||
<input wicket:id="action" t:placeholder="Filter actions" class="form-control form-control-sm">
|
||||
</div>
|
||||
</div>
|
||||
<ul class="body list-unstyled mb-0">
|
||||
<li wicket:id="audits" class="audit"></li>
|
||||
<li wicket:id="more" class="mt-3"><a wicket:id="link" class="btn btn-primary btn-sm"><wicket:t>More</wicket:t></a></li>
|
||||
</ul>
|
||||
<div wicket:id="noAudits" class="alert alert-light mt-4"><wicket:t>No audits</wicket:t></div>
|
||||
</div>
|
||||
<wicket:fragment wicket:id="dateFrag">
|
||||
<h6 class="mt-4 mb-3 d-flex align-items-center font-weight-bold font-size-lg">
|
||||
<wicket:svg href="calendar" class="icon mr-2"/> <span wicket:id="date"></span>
|
||||
</h6>
|
||||
</wicket:fragment>
|
||||
<wicket:fragment wicket:id="auditFrag">
|
||||
<div class="ml-4 mt-2">
|
||||
<span wicket:id="time" class="text-monospace mr-2"></span>
|
||||
<a wicket:id="user"></a>
|
||||
<span wicket:id="action"></span>
|
||||
<a wicket:id="diff" title="Show change detail"><wicket:svg href="diff2" class="icon"/></a>
|
||||
</div>
|
||||
</wicket:fragment>
|
||||
<wicket:fragment wicket:id="diffFrag">
|
||||
<div wicket:id="content" class="p-3 audit-change-detail"></div>
|
||||
</wicket:fragment>
|
||||
</wicket:panel>
|
||||
@ -0,0 +1,283 @@
|
||||
package io.onedev.server.web.component.audit;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.wicket.Component;
|
||||
import org.apache.wicket.ajax.AjaxRequestTarget;
|
||||
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
|
||||
import org.apache.wicket.ajax.markup.html.AjaxLink;
|
||||
import org.apache.wicket.markup.head.CssHeaderItem;
|
||||
import org.apache.wicket.markup.head.IHeaderResponse;
|
||||
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
|
||||
import org.apache.wicket.markup.html.WebMarkupContainer;
|
||||
import org.apache.wicket.markup.html.basic.Label;
|
||||
import org.apache.wicket.markup.html.form.TextField;
|
||||
import org.apache.wicket.markup.html.panel.Fragment;
|
||||
import org.apache.wicket.markup.html.panel.Panel;
|
||||
import org.apache.wicket.markup.repeater.RepeatingView;
|
||||
import org.apache.wicket.model.IModel;
|
||||
import org.apache.wicket.model.LoadableDetachableModel;
|
||||
import org.apache.wicket.model.Model;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.entitymanager.support.AuditQuery;
|
||||
import io.onedev.server.model.Audit;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.util.DateRange;
|
||||
import io.onedev.server.util.DateUtils;
|
||||
import io.onedev.server.util.diff.DiffRenderer;
|
||||
import io.onedev.server.util.diff.DiffUtils;
|
||||
import io.onedev.server.web.asset.diff.DiffResourceReference;
|
||||
import io.onedev.server.web.component.datepicker.DateRangePicker;
|
||||
import io.onedev.server.web.component.floating.FloatingPanel;
|
||||
import io.onedev.server.web.component.link.DropdownLink;
|
||||
import io.onedev.server.web.component.user.choice.UserMultiChoice;
|
||||
import io.onedev.server.web.component.user.ident.Mode;
|
||||
import io.onedev.server.web.component.user.ident.UserIdentPanel;
|
||||
|
||||
public abstract class AuditListPanel extends Panel {
|
||||
|
||||
private static final int PAGE_SIZE = 100;
|
||||
|
||||
private final IModel<List<Audit>> auditsModel = new LoadableDetachableModel<List<Audit>>() {
|
||||
|
||||
@Override
|
||||
protected List<Audit> load() {
|
||||
return getAuditManager().query(getProject(), buildQuery(), currentPage * PAGE_SIZE, PAGE_SIZE);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private final IModel<Integer> countModel = new LoadableDetachableModel<Integer>() {
|
||||
|
||||
@Override
|
||||
protected Integer load() {
|
||||
return getAuditManager().count(getProject(), buildQuery());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private RepeatingView auditsView;
|
||||
|
||||
private int currentPage;
|
||||
|
||||
private LocalDate currentDate;
|
||||
|
||||
private DateRange dateRange;
|
||||
|
||||
private List<String> userNames;
|
||||
|
||||
private String action;
|
||||
|
||||
public AuditListPanel(String id, List<String> userNames, @Nullable DateRange dateRange, @Nullable String action) {
|
||||
super(id);
|
||||
this.userNames = userNames;
|
||||
this.dateRange = dateRange;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
private AuditQuery buildQuery() {
|
||||
Date sinceDate = null;
|
||||
Date untilDate = null;
|
||||
if (dateRange != null) {
|
||||
sinceDate = DateUtils.toDate(dateRange.getFrom().atStartOfDay());
|
||||
untilDate = DateUtils.toDate(dateRange.getTo().atTime(23, 59, 59));
|
||||
}
|
||||
return new AuditQuery(getUsers(), sinceDate, untilDate, action);
|
||||
}
|
||||
|
||||
private void updateAuditList(AjaxRequestTarget target) {
|
||||
var newPanel = new AuditListPanel(getId(), userNames, dateRange, action) {
|
||||
|
||||
@Override
|
||||
protected void onQueryUpdated(AjaxRequestTarget target, @Nullable DateRange dateRange, List<String> userNames, @Nullable String action) {
|
||||
AuditListPanel.this.onQueryUpdated(target, dateRange, userNames, action);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Project getProject() {
|
||||
return AuditListPanel.this.getProject();
|
||||
}
|
||||
|
||||
};
|
||||
replaceWith(newPanel);
|
||||
target.add(newPanel);
|
||||
}
|
||||
|
||||
private List<User> getUsers() {
|
||||
return userNames.stream().map(getUserManager()::findByName).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
super.onInitialize();
|
||||
|
||||
var dateRangePicker = new DateRangePicker("dateRange", Model.of(dateRange));
|
||||
dateRangePicker.add(new AjaxFormComponentUpdatingBehavior("change clear") {
|
||||
|
||||
@Override
|
||||
protected void onUpdate(AjaxRequestTarget target) {
|
||||
dateRange = dateRangePicker.getModelObject();
|
||||
updateAuditList(target);
|
||||
onQueryUpdated(target, dateRange, userNames, action);
|
||||
}
|
||||
|
||||
});
|
||||
add(dateRangePicker);
|
||||
|
||||
var usersChoice = new UserMultiChoice("users", Model.of(getUsers()), Model.ofList(getUserManager().query()));
|
||||
usersChoice.add(new AjaxFormComponentUpdatingBehavior("change") {
|
||||
@Override
|
||||
protected void onUpdate(AjaxRequestTarget target) {
|
||||
userNames = usersChoice.getModelObject().stream().map(User::getName).collect(Collectors.toList());
|
||||
updateAuditList(target);
|
||||
onQueryUpdated(target, dateRange, userNames, action);
|
||||
}
|
||||
});
|
||||
add(usersChoice);
|
||||
|
||||
var actionInput = new TextField<String>("action", Model.of(action));
|
||||
actionInput.add(new AjaxFormComponentUpdatingBehavior("change clear") {
|
||||
@Override
|
||||
protected void onUpdate(AjaxRequestTarget target) {
|
||||
action = actionInput.getModelObject();
|
||||
updateAuditList(target);
|
||||
onQueryUpdated(target, dateRange, userNames, action);
|
||||
}
|
||||
});
|
||||
add(actionInput);
|
||||
|
||||
auditsView = new RepeatingView("audits");
|
||||
for (var audit: auditsModel.getObject()) {
|
||||
for (var row: newAuditRows(auditsView, audit)) {
|
||||
auditsView.add(row);
|
||||
}
|
||||
}
|
||||
|
||||
add(auditsView);
|
||||
|
||||
var moreContainer = new WebMarkupContainer("more") {
|
||||
|
||||
@Override
|
||||
protected void onConfigure() {
|
||||
super.onConfigure();
|
||||
setVisible(PAGE_SIZE * (currentPage + 1) < countModel.getObject());
|
||||
}
|
||||
|
||||
};
|
||||
moreContainer.setOutputMarkupId(true);
|
||||
|
||||
moreContainer.add(new AjaxLink<Void>("link") {
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onClick(AjaxRequestTarget target) {
|
||||
target.add(moreContainer);
|
||||
currentPage++;
|
||||
for (var audit: auditsModel.getObject()) {
|
||||
for (var row: newAuditRows(auditsView, audit)) {
|
||||
var script = String.format("$('#%s').after('<li id=\"%s\"></li>');", auditsView.get(auditsView.size() - 1).getMarkupId(), row.getMarkupId());
|
||||
target.prependJavaScript(script);
|
||||
auditsView.add(row);
|
||||
target.add(row);
|
||||
}
|
||||
}
|
||||
target.focusComponent(null);
|
||||
}
|
||||
|
||||
});
|
||||
add(moreContainer);
|
||||
|
||||
add(new WebMarkupContainer("noAudits") {
|
||||
@Override
|
||||
protected void onConfigure() {
|
||||
super.onConfigure();
|
||||
setVisible(countModel.getObject() == 0);
|
||||
}
|
||||
});
|
||||
|
||||
setOutputMarkupId(true);
|
||||
}
|
||||
|
||||
private UserManager getUserManager() {
|
||||
return OneDev.getInstance(UserManager.class);
|
||||
}
|
||||
|
||||
private AuditManager getAuditManager() {
|
||||
return OneDev.getInstance(AuditManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetach() {
|
||||
auditsModel.detach();
|
||||
countModel.detach();
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderHead(IHeaderResponse response) {
|
||||
super.renderHead(response);
|
||||
response.render(JavaScriptHeaderItem.forReference(new DiffResourceReference()));
|
||||
response.render(CssHeaderItem.forReference(new AuditLogCssResourceReference()));
|
||||
}
|
||||
|
||||
private List<Component> newAuditRows(RepeatingView auditsView, Audit audit) {
|
||||
var rows = new ArrayList<Component>();
|
||||
var auditDate = DateUtils.toLocalDate(audit.getDate());
|
||||
if (currentDate == null || !currentDate.equals(auditDate)) {
|
||||
currentDate = auditDate;
|
||||
var fragment = new Fragment(auditsView.newChildId(), "dateFrag", this);
|
||||
fragment.add(new Label("date", currentDate.format(DateUtils.DATE_FORMATTER)));
|
||||
fragment.setOutputMarkupId(true);
|
||||
rows.add(fragment);
|
||||
}
|
||||
var fragment = new Fragment(auditsView.newChildId(), "auditFrag", this);
|
||||
fragment.add(new Label("time", DateUtils.formatTime(audit.getDate())));
|
||||
fragment.add(new UserIdentPanel("user", audit.getUser(), Mode.AVATAR_AND_NAME));
|
||||
fragment.add(new Label("action", audit.getAction()));
|
||||
var oldContent = audit.getOldContent();
|
||||
var newContent = audit.getNewContent();
|
||||
fragment.add(new DropdownLink("diff") {
|
||||
|
||||
@Override
|
||||
protected Component newContent(String id, FloatingPanel dropdown) {
|
||||
List<String> oldLines = new ArrayList<>();
|
||||
if (oldContent != null)
|
||||
oldLines = Splitter.on('\n').splitToList(oldContent);
|
||||
List<String> newLines = new ArrayList<>();
|
||||
if (newContent != null)
|
||||
newLines = Splitter.on('\n').splitToList(newContent);
|
||||
var fragment = new Fragment(id, "diffFrag", AuditListPanel.this);
|
||||
fragment.add(new Label("content", new DiffRenderer(DiffUtils.diff(oldLines, newLines)).renderDiffs()).setEscapeModelStrings(false));
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigure() {
|
||||
super.onConfigure();
|
||||
setVisible(oldContent != null || newContent != null);
|
||||
}
|
||||
|
||||
});
|
||||
fragment.setOutputMarkupId(true);
|
||||
rows.add(fragment);
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected abstract Project getProject();
|
||||
|
||||
protected abstract void onQueryUpdated(AjaxRequestTarget target, @Nullable DateRange dateRange, List<String> userNames, @Nullable String action);
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
package io.onedev.server.web.component.audit;
|
||||
|
||||
import io.onedev.server.web.page.base.BaseDependentCssResourceReference;
|
||||
|
||||
public class AuditLogCssResourceReference extends BaseDependentCssResourceReference {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public AuditLogCssResourceReference() {
|
||||
super(AuditLogCssResourceReference.class, "audit-list.css");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,68 @@
|
||||
.audit-list>.head>.date-range, .audit-list>.head>.users {
|
||||
width: 30%;
|
||||
}
|
||||
.audit-list>.head>.action {
|
||||
width: 40%;
|
||||
}
|
||||
.audit-list .body {
|
||||
position: relative;
|
||||
padding-left: 20px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.audit-list .body::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 2px;
|
||||
background-color: var(--secondary);
|
||||
}
|
||||
|
||||
.dark-mode .audit-list .body::before {
|
||||
background-color: var(--dark-mode-lighter-dark);
|
||||
}
|
||||
|
||||
.audit-list .body li {
|
||||
position: relative;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.audit-list .body li.audit::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: -24px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--secondary);
|
||||
border: 2px solid #fff;
|
||||
box-shadow: 0 0 0 2px var(--secondary);
|
||||
}
|
||||
|
||||
.dark-mode .audit-list .body li.audit::before {
|
||||
background-color: var(--dark-mode-lighter-dark);
|
||||
border-color: var(--dark-mode-darker);
|
||||
box-shadow: 0 0 0 2px var(--dark-mode-lighter-dark);
|
||||
}
|
||||
|
||||
.audit-list .body li:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.audit-list .body li[wicket\:id="more"]::before {
|
||||
background-color: var(--secondary);
|
||||
box-shadow: 0 0 0 2px var(--secondary);
|
||||
}
|
||||
|
||||
.dark-mode .audit-list .body li[wicket\:id="more"]::before {
|
||||
background-color: var(--dark-mode-lighter-dark);
|
||||
box-shadow: 0 0 0 2px var(--dark-mode-lighter-dark);
|
||||
}
|
||||
|
||||
.audit-change-detail {
|
||||
max-width: 900px;
|
||||
}
|
||||
@ -54,6 +54,8 @@ import com.google.common.collect.Sets;
|
||||
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.BuildManager;
|
||||
import io.onedev.server.entitymanager.BuildParamManager;
|
||||
import io.onedev.server.entitymanager.ProjectManager;
|
||||
@ -65,6 +67,7 @@ import io.onedev.server.model.Build;
|
||||
import io.onedev.server.model.Build.Status;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.model.support.administration.GlobalBuildSetting;
|
||||
import io.onedev.server.persistence.TransactionManager;
|
||||
import io.onedev.server.search.entity.EntityQuery;
|
||||
import io.onedev.server.search.entity.EntitySort;
|
||||
import io.onedev.server.search.entity.EntitySort.Direction;
|
||||
@ -160,6 +163,18 @@ public abstract class BuildListPanel extends Panel {
|
||||
private BuildManager getBuildManager() {
|
||||
return OneDev.getInstance(BuildManager.class);
|
||||
}
|
||||
|
||||
private ProjectManager getProjectManager() {
|
||||
return OneDev.getInstance(ProjectManager.class);
|
||||
}
|
||||
|
||||
private TransactionManager getTransactionManager() {
|
||||
return OneDev.getInstance(TransactionManager.class);
|
||||
}
|
||||
|
||||
private AuditManager getAuditManager() {
|
||||
return OneDev.getInstance(AuditManager.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BuildQuery parse(@Nullable String queryString, BuildQuery baseQuery) {
|
||||
@ -445,10 +460,17 @@ public abstract class BuildListPanel extends Panel {
|
||||
|
||||
@Override
|
||||
protected void onConfirm(AjaxRequestTarget target) {
|
||||
Collection<Build> builds = new ArrayList<>();
|
||||
for (IModel<Build> each: selectionColumn.getSelections())
|
||||
builds.add(each.getObject());
|
||||
OneDev.getInstance(BuildManager.class).delete(builds);
|
||||
getTransactionManager().run(()-> {
|
||||
Collection<Build> builds = new ArrayList<>();
|
||||
for (IModel<Build> each: selectionColumn.getSelections())
|
||||
builds.add(each.getObject());
|
||||
getBuildManager().delete(builds);
|
||||
for (var build: builds) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(build).toXML();
|
||||
getAuditManager().audit(build.getProject(), "deleted build \"" + build.getReference().toString(build.getProject()) + "\"", oldAuditContent, null);
|
||||
}
|
||||
});
|
||||
|
||||
target.add(countLabel);
|
||||
target.add(body);
|
||||
selectionColumn.getSelections().clear();
|
||||
@ -655,11 +677,17 @@ public abstract class BuildListPanel extends Panel {
|
||||
|
||||
@Override
|
||||
protected void onConfirm(AjaxRequestTarget target) {
|
||||
Collection<Build> builds = new ArrayList<>();
|
||||
for (Iterator<Build> it = (Iterator<Build>) dataProvider.iterator(0, buildsTable.getItemCount()); it.hasNext();) {
|
||||
builds.add(it.next());
|
||||
}
|
||||
OneDev.getInstance(BuildManager.class).delete(builds);
|
||||
getTransactionManager().run(()-> {
|
||||
Collection<Build> builds = new ArrayList<>();
|
||||
for (Iterator<Build> it = (Iterator<Build>) dataProvider.iterator(0, buildsTable.getItemCount()); it.hasNext();) {
|
||||
builds.add(it.next());
|
||||
}
|
||||
getBuildManager().delete(builds);
|
||||
for (var build: builds) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(build).toXML();
|
||||
getAuditManager().audit(build.getProject(), "deleted build \"" + build.getReference().toString(build.getProject()) + "\"", oldAuditContent, null);
|
||||
}
|
||||
});
|
||||
dataProvider.detach();
|
||||
target.add(countLabel);
|
||||
target.add(body);
|
||||
@ -763,11 +791,17 @@ public abstract class BuildListPanel extends Panel {
|
||||
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
|
||||
super.onSubmit(target, form);
|
||||
if (getProject() != null) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(getProject().getBuildSetting().getListParams(true)).toXML();
|
||||
getProject().getBuildSetting().setListParams(listParams);
|
||||
OneDev.getInstance(ProjectManager.class).update(getProject());
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(getProject().getBuildSetting().getListParams(true)).toXML();
|
||||
getProjectManager().update(getProject());
|
||||
getAuditManager().audit(getProject(), "changed display params of build list", oldAuditContent, newAuditContent);
|
||||
} else {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(getGlobalBuildSetting().getListParams()).toXML();
|
||||
getGlobalBuildSetting().setListParams(listParams);
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(getGlobalBuildSetting().getListParams()).toXML();
|
||||
OneDev.getInstance(SettingManager.class).saveBuildSetting(getGlobalBuildSetting());
|
||||
getAuditManager().audit(null, "changed display params of build list", oldAuditContent, newAuditContent);
|
||||
}
|
||||
setResponsePage(getPage().getClass(), getPage().getPageParameters());
|
||||
}
|
||||
@ -779,8 +813,11 @@ public abstract class BuildListPanel extends Panel {
|
||||
@Override
|
||||
public void onClick(AjaxRequestTarget target) {
|
||||
modal.close();
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(getProject().getBuildSetting().getListParams(true)).toXML();
|
||||
getProject().getBuildSetting().setListParams(null);
|
||||
OneDev.getInstance(ProjectManager.class).update(getProject());
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(getProject().getBuildSetting().getListParams(true)).toXML();
|
||||
getProjectManager().update(getProject());
|
||||
getAuditManager().audit(getProject(), "changed display params of build list", oldAuditContent, newAuditContent);
|
||||
target.add(body);
|
||||
}
|
||||
|
||||
@ -937,9 +974,8 @@ public abstract class BuildListPanel extends Panel {
|
||||
|
||||
@Override
|
||||
protected List<Project> load() {
|
||||
ProjectManager projectManager = OneDev.getInstance(ProjectManager.class);
|
||||
List<Project> projects = new ArrayList<>(SecurityUtils.getAuthorizedProjects(new JobPermission(null, new RunJob())));
|
||||
projects.sort(projectManager.cloneCache().comparingPath());
|
||||
projects.sort(getProjectManager().cloneCache().comparingPath());
|
||||
return projects;
|
||||
}
|
||||
|
||||
@ -1274,7 +1310,7 @@ public abstract class BuildListPanel extends Panel {
|
||||
new FloatingPanel(target, alignment, true, true, null) {
|
||||
|
||||
private Project getRevisionProject() {
|
||||
return OneDev.getInstance(ProjectManager.class).load(projectId);
|
||||
return getProjectManager().load(projectId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -45,6 +45,8 @@ import com.google.common.collect.Sets;
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.attachment.AttachmentSupport;
|
||||
import io.onedev.server.attachment.ProjectAttachmentSupport;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.CodeCommentManager;
|
||||
import io.onedev.server.entitymanager.CodeCommentReplyManager;
|
||||
import io.onedev.server.entitymanager.CodeCommentStatusChangeManager;
|
||||
@ -357,6 +359,8 @@ public abstract class CodeCommentPanel extends Panel {
|
||||
public void onClick(AjaxRequestTarget target) {
|
||||
onDeleteComment(target, getComment());
|
||||
OneDev.getInstance(CodeCommentManager.class).delete(getComment());
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(getComment()).toXML();
|
||||
OneDev.getInstance(AuditManager.class).audit(getComment().getProject(), "deleted code comment on file \"" + getComment().getMark().getPath() + "\"", oldAuditContent, null);
|
||||
}
|
||||
|
||||
protected void onConfigure() {
|
||||
|
||||
@ -64,15 +64,16 @@ public abstract class CommandPalettePanel extends Panel {
|
||||
|
||||
private static final PatternSet eeUrlPatterns = PatternSet.parse("" +
|
||||
"~dashboards/** ~code-search/** ~administration/settings/storage-setting " +
|
||||
"~administration/cluster ~administration/settings/time-tracking ${project}/~timesheets " +
|
||||
"${project}/~stats/pull-request-duration ${project}/~stats/build-duration ${project}/~stats/build-frequency");
|
||||
"~administration/cluster ~administration/audits ~administration/settings/time-tracking ${project}/~timesheets " +
|
||||
"${project}/~stats/pull-request/duration ${project}/~stats/pull-request/frequency ${project}/~stats/build/duration " +
|
||||
"${project}/~stats/build/frequency ${project}/~stats/issue/state-frequency ${project}/~stats/issue/state-duration " +
|
||||
"${project}/~stats/issue/state-trend ${project}/~audits");
|
||||
|
||||
static {
|
||||
for (IRequestMapper mapper: OneDev.getInstance(WebApplication.class).getRequestMappers())
|
||||
availableUrls.addAll(getMountedPaths(mapper));
|
||||
|
||||
Collections.sort(availableUrls, (Comparator<String[]>) (o1, o2) -> PathUtils.compare(Arrays.asList(o1), Arrays.asList(o2)));
|
||||
|
||||
Collections.sort(availableUrls, (Comparator<String[]>) (o1, o2) -> PathUtils.compare(Arrays.asList(o1), Arrays.asList(o2)));
|
||||
}
|
||||
|
||||
private static List<String[]> getMountedPaths(IRequestMapper mapper) {
|
||||
|
||||
@ -29,32 +29,39 @@ public class DateRangePicker extends TextField<DateRange> {
|
||||
public DateRangePicker(String id, IModel<DateRange> model) {
|
||||
super(id, model);
|
||||
|
||||
setType(DateRange.class);
|
||||
converter = new IConverter<DateRange>() {
|
||||
|
||||
@Override
|
||||
public DateRange convertToObject(String value, Locale locale) throws ConversionException {
|
||||
var errorMessage = _T("Invalid date range, expecting \"yyyy-MM-dd to yyyy-MM-dd\"");
|
||||
if (value.contains(" ")) {
|
||||
try {
|
||||
var fromDate = LocalDate.from(DateUtils.DATE_FORMATTER.parse(StringUtils.substringBefore(value, " ")));
|
||||
var toDate = LocalDate.from(DateUtils.DATE_FORMATTER.parse(StringUtils.substringAfterLast(value, " ")));
|
||||
return new DateRange(fromDate, toDate);
|
||||
} catch (Exception e) {
|
||||
throw new ConversionException(errorMessage);
|
||||
}
|
||||
if (value == null) {
|
||||
return null;
|
||||
} else {
|
||||
try {
|
||||
var date = LocalDate.from(DateUtils.DATE_FORMATTER.parse(value));
|
||||
return new DateRange(date, date);
|
||||
} catch (Exception e) {
|
||||
throw new ConversionException(errorMessage);
|
||||
var errorMessage = _T("Invalid date range, expecting \"yyyy-MM-dd to yyyy-MM-dd\"");
|
||||
if (value.contains(" ")) {
|
||||
try {
|
||||
var fromDate = LocalDate.from(DateUtils.DATE_FORMATTER.parse(StringUtils.substringBefore(value, " ")));
|
||||
var toDate = LocalDate.from(DateUtils.DATE_FORMATTER.parse(StringUtils.substringAfterLast(value, " ")));
|
||||
return new DateRange(fromDate, toDate);
|
||||
} catch (Exception e) {
|
||||
throw new ConversionException(errorMessage);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
var date = LocalDate.from(DateUtils.DATE_FORMATTER.parse(value));
|
||||
return new DateRange(date, date);
|
||||
} catch (Exception e) {
|
||||
throw new ConversionException(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String convertToString(DateRange value, Locale locale) {
|
||||
if (!value.getFrom().equals(value.getTo()))
|
||||
if (value == null)
|
||||
return null;
|
||||
else if (!value.getFrom().equals(value.getTo()))
|
||||
return value.getFrom().format(DateUtils.DATE_FORMATTER) + " to " + value.getTo().format(DateUtils.DATE_FORMATTER);
|
||||
else
|
||||
return value.getFrom().format(DateUtils.DATE_FORMATTER);
|
||||
|
||||
@ -76,6 +76,8 @@ import com.google.common.collect.Sets;
|
||||
import edu.emory.mathcs.backport.java.util.Collections;
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.IssueLinkManager;
|
||||
import io.onedev.server.entitymanager.IssueManager;
|
||||
import io.onedev.server.entitymanager.IssueWatchManager;
|
||||
@ -93,6 +95,7 @@ import io.onedev.server.model.support.issue.field.spec.DateField;
|
||||
import io.onedev.server.model.support.issue.field.spec.FieldSpec;
|
||||
import io.onedev.server.model.support.issue.field.spec.IntegerField;
|
||||
import io.onedev.server.model.support.issue.field.spec.choicefield.ChoiceField;
|
||||
import io.onedev.server.persistence.TransactionManager;
|
||||
import io.onedev.server.search.entity.EntityQuery;
|
||||
import io.onedev.server.search.entity.EntitySort;
|
||||
import io.onedev.server.search.entity.EntitySort.Direction;
|
||||
@ -108,6 +111,7 @@ import io.onedev.server.util.LinkDescriptor;
|
||||
import io.onedev.server.util.ProjectScope;
|
||||
import io.onedev.server.util.facade.ProjectCache;
|
||||
import io.onedev.server.util.watch.WatchStatus;
|
||||
import io.onedev.server.util.xstream.ObjectMap;
|
||||
import io.onedev.server.web.WebConstants;
|
||||
import io.onedev.server.web.ajaxlistener.AttachAjaxIndicatorListener;
|
||||
import io.onedev.server.web.ajaxlistener.AttachAjaxIndicatorListener.AttachMode;
|
||||
@ -191,6 +195,14 @@ public abstract class IssueListPanel extends Panel {
|
||||
private IssueLinkManager getIssueLinkManager() {
|
||||
return OneDev.getInstance(IssueLinkManager.class);
|
||||
}
|
||||
|
||||
private TransactionManager getTransactionManager() {
|
||||
return OneDev.getInstance(TransactionManager.class);
|
||||
}
|
||||
|
||||
private AuditManager getAuditManager() {
|
||||
return OneDev.getInstance(AuditManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetach() {
|
||||
@ -528,6 +540,26 @@ public abstract class IssueListPanel extends Panel {
|
||||
|
||||
add(new ModalLink("fieldsAndLinks") {
|
||||
|
||||
private String getAuditContent(Project project) {
|
||||
var listFields = project.getIssueSetting().getListFields();
|
||||
if (listFields == null)
|
||||
listFields = getGlobalIssueSetting().getListFields();
|
||||
var listLinks = project.getIssueSetting().getListLinks();
|
||||
if (listLinks == null)
|
||||
listLinks = getGlobalIssueSetting().getListLinks();
|
||||
var auditData = new ObjectMap();
|
||||
auditData.put("listFields", listFields);
|
||||
auditData.put("listLinks", listLinks);
|
||||
return VersionedXmlDoc.fromBean(auditData).toXML();
|
||||
}
|
||||
|
||||
private String getAuditContent() {
|
||||
var auditData = new ObjectMap();
|
||||
auditData.put("listFields", getGlobalIssueSetting().getListFields());
|
||||
auditData.put("listLinks", getGlobalIssueSetting().getListLinks());
|
||||
return VersionedXmlDoc.fromBean(auditData).toXML();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Component newContent(String id, ModalPanel modal) {
|
||||
Fragment fragment = new Fragment(id, "fieldsAndLinksFrag", IssueListPanel.this);
|
||||
@ -556,13 +588,19 @@ public abstract class IssueListPanel extends Panel {
|
||||
super.onSubmit(target, form);
|
||||
modal.close();
|
||||
if (getProject() != null) {
|
||||
var oldAuditContent = getAuditContent(getProject());
|
||||
getProject().getIssueSetting().setListFields(bean.getFields());
|
||||
getProject().getIssueSetting().setListLinks(bean.getLinks());
|
||||
OneDev.getInstance(ProjectManager.class).update(getProject());
|
||||
} else {
|
||||
var newAuditContent = getAuditContent(getProject());
|
||||
getProjectManager().update(getProject());
|
||||
getAuditManager().audit(getProject(), "changed display fields/links of issue list", oldAuditContent, newAuditContent);
|
||||
} else {
|
||||
var oldAuditContent = getAuditContent();
|
||||
getGlobalIssueSetting().setListFields(bean.getFields());
|
||||
getGlobalIssueSetting().setListLinks(bean.getLinks());
|
||||
var newAuditContent = getAuditContent();
|
||||
OneDev.getInstance(SettingManager.class).saveIssueSetting(getGlobalIssueSetting());
|
||||
getAuditManager().audit(null, "changed display fields/links of issue list", oldAuditContent, newAuditContent);
|
||||
}
|
||||
target.add(body);
|
||||
onDisplayFieldsAndLinksUpdated(target);
|
||||
@ -575,9 +613,12 @@ public abstract class IssueListPanel extends Panel {
|
||||
@Override
|
||||
public void onClick(AjaxRequestTarget target) {
|
||||
modal.close();
|
||||
var oldAuditContent = getAuditContent();
|
||||
getProject().getIssueSetting().setListFields(null);
|
||||
getProject().getIssueSetting().setListLinks(null);
|
||||
OneDev.getInstance(ProjectManager.class).update(getProject());
|
||||
var newAuditContent = getAuditContent();
|
||||
getProjectManager().update(getProject());
|
||||
getAuditManager().audit(getProject(), "changed display fields/links of issue list", oldAuditContent, newAuditContent);
|
||||
target.add(body);
|
||||
onDisplayFieldsAndLinksUpdated(target);
|
||||
}
|
||||
@ -971,7 +1012,7 @@ public abstract class IssueListPanel extends Panel {
|
||||
Collection<Issue> issues = new ArrayList<>();
|
||||
for (IModel<Issue> each : selectionColumn.getSelections())
|
||||
issues.add(each.getObject());
|
||||
OneDev.getInstance(IssueManager.class).move(issues, getProject(), getTargetProject());
|
||||
getIssueManager().move(issues, getProject(), getTargetProject());
|
||||
setResponsePage(ProjectIssueListPage.class,
|
||||
ProjectIssueListPage.paramsOf(getTargetProject(), getQueryAfterCopyOrMove(), 0));
|
||||
Session.get().success(_T("Issues moved"));
|
||||
@ -1053,7 +1094,7 @@ public abstract class IssueListPanel extends Panel {
|
||||
Collection<Issue> issues = new ArrayList<>();
|
||||
for (IModel<Issue> each : selectionColumn.getSelections())
|
||||
issues.add(each.getObject());
|
||||
OneDev.getInstance(IssueManager.class).copy(issues, getProject(), getTargetProject());
|
||||
getIssueManager().copy(issues, getProject(), getTargetProject());
|
||||
setResponsePage(ProjectIssueListPage.class,
|
||||
ProjectIssueListPage.paramsOf(getTargetProject(), getQueryAfterCopyOrMove(), 0));
|
||||
Session.get().success(_T("Issues copied"));
|
||||
@ -1114,10 +1155,16 @@ public abstract class IssueListPanel extends Panel {
|
||||
|
||||
@Override
|
||||
protected void onConfirm(AjaxRequestTarget target) {
|
||||
Collection<Issue> issues = new ArrayList<>();
|
||||
for (IModel<Issue> each : selectionColumn.getSelections())
|
||||
issues.add(each.getObject());
|
||||
OneDev.getInstance(IssueManager.class).delete(issues, getProject());
|
||||
getTransactionManager().run(()-> {
|
||||
Collection<Issue> issues = new ArrayList<>();
|
||||
for (IModel<Issue> each : selectionColumn.getSelections())
|
||||
issues.add(each.getObject());
|
||||
getIssueManager().delete(issues, getProject());
|
||||
for (var issue: issues) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(issue).toXML();
|
||||
getAuditManager().audit(issue.getProject(), "deleted issue \"" + issue.getReference().toString(issue.getProject()) + "\"", oldAuditContent, null);
|
||||
}
|
||||
});
|
||||
selectionColumn.getSelections().clear();
|
||||
target.add(countLabel);
|
||||
target.add(body);
|
||||
@ -1474,10 +1521,16 @@ public abstract class IssueListPanel extends Panel {
|
||||
|
||||
@Override
|
||||
protected void onConfirm(AjaxRequestTarget target) {
|
||||
Collection<Issue> issues = new ArrayList<>();
|
||||
for (Iterator<Issue> it = (Iterator<Issue>) dataProvider.iterator(0, issuesTable.getItemCount()); it.hasNext(); )
|
||||
issues.add(it.next());
|
||||
OneDev.getInstance(IssueManager.class).delete(issues, getProject());
|
||||
getTransactionManager().run(()-> {
|
||||
Collection<Issue> issues = new ArrayList<>();
|
||||
for (Iterator<Issue> it = (Iterator<Issue>) dataProvider.iterator(0, issuesTable.getItemCount()); it.hasNext(); )
|
||||
issues.add(it.next());
|
||||
getIssueManager().delete(issues, getProject());
|
||||
for (var issue: issues) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(issue).toXML();
|
||||
getAuditManager().audit(issue.getProject(), "deleted issue \"" + issue.getReference().toString(issue.getProject()) + "\"", oldAuditContent, null);
|
||||
}
|
||||
});
|
||||
dataProvider.detach();
|
||||
selectionColumn.getSelections().clear();
|
||||
target.add(countLabel);
|
||||
|
||||
@ -12,6 +12,8 @@ import org.apache.wicket.markup.html.panel.GenericPanel;
|
||||
import org.apache.wicket.model.IModel;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.IterationManager;
|
||||
import io.onedev.server.model.Iteration;
|
||||
import io.onedev.server.web.ajaxlistener.ConfirmClickListener;
|
||||
@ -37,6 +39,7 @@ public abstract class IterationActionsPanel extends GenericPanel<Iteration> {
|
||||
public void onClick(AjaxRequestTarget target) {
|
||||
getIteration().setClosed(false);
|
||||
getIterationManager().createOrUpdate(getIteration());
|
||||
getAuditManager().audit(getIteration().getProject(), "reopened iteration \"" + getIteration().getName() + "\"", null, null);
|
||||
target.add(IterationActionsPanel.this);
|
||||
onUpdated(target);
|
||||
getSession().success(MessageFormat.format(_T("Iteration \"{0}\" reopened"), getIteration().getName()));
|
||||
@ -62,6 +65,7 @@ public abstract class IterationActionsPanel extends GenericPanel<Iteration> {
|
||||
public void onClick(AjaxRequestTarget target) {
|
||||
getIteration().setClosed(true);
|
||||
getIterationManager().createOrUpdate(getIteration());
|
||||
getAuditManager().audit(getIteration().getProject(), "closed iteration \"" + getIteration().getName() + "\"", null, null);
|
||||
target.add(IterationActionsPanel.this);
|
||||
onUpdated(target);
|
||||
getSession().success(MessageFormat.format(_T("Iteration \"{0}\" closed"), getIteration().getName()));
|
||||
@ -84,6 +88,8 @@ public abstract class IterationActionsPanel extends GenericPanel<Iteration> {
|
||||
@Override
|
||||
public void onClick(AjaxRequestTarget target) {
|
||||
getIterationManager().delete(getIteration());
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(getIteration()).toXML();
|
||||
getAuditManager().audit(getIteration().getProject(), "deleted iteration \"" + getIteration().getName() + "\"", oldAuditContent, null);
|
||||
target.add(IterationActionsPanel.this);
|
||||
onDeleted(target);
|
||||
getSession().success(MessageFormat.format(_T("Iteration \"{0}\" deleted"), getIteration().getName()));
|
||||
@ -98,6 +104,10 @@ public abstract class IterationActionsPanel extends GenericPanel<Iteration> {
|
||||
return OneDev.getInstance(IterationManager.class);
|
||||
}
|
||||
|
||||
private AuditManager getAuditManager() {
|
||||
return OneDev.getInstance(AuditManager.class);
|
||||
}
|
||||
|
||||
protected abstract void onDeleted(AjaxRequestTarget target);
|
||||
|
||||
protected abstract void onUpdated(AjaxRequestTarget target);
|
||||
|
||||
@ -47,10 +47,13 @@ import org.apache.wicket.request.cycle.RequestCycle;
|
||||
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.PackManager;
|
||||
import io.onedev.server.model.Pack;
|
||||
import io.onedev.server.model.Project;
|
||||
import io.onedev.server.pack.PackSupport;
|
||||
import io.onedev.server.persistence.TransactionManager;
|
||||
import io.onedev.server.search.entity.EntityQuery;
|
||||
import io.onedev.server.search.entity.EntitySort;
|
||||
import io.onedev.server.search.entity.EntitySort.Direction;
|
||||
@ -126,6 +129,10 @@ public abstract class PackListPanel extends Panel {
|
||||
private PackManager getPackManager() {
|
||||
return OneDev.getInstance(PackManager.class);
|
||||
}
|
||||
|
||||
private TransactionManager getTransactionManager() {
|
||||
return OneDev.getInstance(TransactionManager.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private PackQuery parse(@Nullable String queryString, PackQuery baseQuery) {
|
||||
@ -173,6 +180,10 @@ public abstract class PackListPanel extends Panel {
|
||||
protected QuerySaveSupport getQuerySaveSupport() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private AuditManager getAuditManager() {
|
||||
return OneDev.getInstance(AuditManager.class);
|
||||
}
|
||||
|
||||
private void doQuery(AjaxRequestTarget target) {
|
||||
packsTable.setCurrentPage(0);
|
||||
@ -267,10 +278,16 @@ public abstract class PackListPanel extends Panel {
|
||||
|
||||
@Override
|
||||
protected void onConfirm(AjaxRequestTarget target) {
|
||||
Collection<Pack> packs = new ArrayList<>();
|
||||
for (IModel<Pack> each: selectionColumn.getSelections())
|
||||
packs.add(each.getObject());
|
||||
OneDev.getInstance(PackManager.class).delete(packs);
|
||||
getTransactionManager().run(()-> {
|
||||
Collection<Pack> packs = new ArrayList<>();
|
||||
for (IModel<Pack> each: selectionColumn.getSelections())
|
||||
packs.add(each.getObject());
|
||||
getPackManager().delete(packs);
|
||||
for (var pack: packs) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(pack).toXML();
|
||||
getAuditManager().audit(pack.getProject(), "deleted package \"" + pack.getReference(false) + "\"", oldAuditContent, null);
|
||||
}
|
||||
});
|
||||
target.add(countLabel);
|
||||
target.add(body);
|
||||
selectionColumn.getSelections().clear();
|
||||
@ -331,11 +348,17 @@ public abstract class PackListPanel extends Panel {
|
||||
|
||||
@Override
|
||||
protected void onConfirm(AjaxRequestTarget target) {
|
||||
Collection<Pack> packs = new ArrayList<>();
|
||||
for (Iterator<Pack> it = (Iterator<Pack>) dataProvider.iterator(0, packsTable.getItemCount()); it.hasNext();) {
|
||||
packs.add(it.next());
|
||||
}
|
||||
OneDev.getInstance(PackManager.class).delete(packs);
|
||||
getTransactionManager().run(()-> {
|
||||
Collection<Pack> packs = new ArrayList<>();
|
||||
for (Iterator<Pack> it = (Iterator<Pack>) dataProvider.iterator(0, packsTable.getItemCount()); it.hasNext();) {
|
||||
packs.add(it.next());
|
||||
}
|
||||
getPackManager().delete(packs);
|
||||
for (var pack: packs) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(pack).toXML();
|
||||
getAuditManager().audit(pack.getProject(), "deleted package \"" + pack.getReference(false) + "\"", oldAuditContent, null);
|
||||
}
|
||||
});
|
||||
dataProvider.detach();
|
||||
target.add(countLabel);
|
||||
target.add(body);
|
||||
|
||||
@ -23,6 +23,8 @@ import org.apache.wicket.model.IModel;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.BaseAuthorizationManager;
|
||||
import io.onedev.server.entitymanager.ProjectLabelManager;
|
||||
import io.onedev.server.entitymanager.ProjectManager;
|
||||
@ -122,9 +124,16 @@ public abstract class ForkOptionPanel extends Panel {
|
||||
|
||||
OneDev.getInstance(TransactionManager.class).run(() -> {
|
||||
getProjectManager().create(newProject);
|
||||
getProjectManager().fork(getProject(), newProject);
|
||||
getProjectManager().fork(getProject(), newProject);
|
||||
OneDev.getInstance(BaseAuthorizationManager.class).syncRoles(newProject, defaultRolesBean.getRoles());
|
||||
OneDev.getInstance(ProjectLabelManager.class).sync(newProject, labelsBean.getLabels());
|
||||
|
||||
var auditData = editor.getPropertyValues();
|
||||
auditData.put("parent", parentBean.getParentPath());
|
||||
auditData.put("forkedFrom", getProject().getPath());
|
||||
auditData.put("defaultRoles", defaultRolesBean.getRoleNames());
|
||||
auditData.put("labels", labelsBean.getLabels());
|
||||
OneDev.getInstance(AuditManager.class).audit(newProject, "created project", null, VersionedXmlDoc.fromBean(auditData).toXML());
|
||||
});
|
||||
Session.get().success(_T("Project forked"));
|
||||
setResponsePage(ProjectBlobPage.class, ProjectBlobPage.paramsOf(newProject));
|
||||
|
||||
@ -8,10 +8,12 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
@ -52,6 +54,8 @@ import org.apache.wicket.request.mapper.parameter.PageParameters;
|
||||
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.BuildManager;
|
||||
import io.onedev.server.entitymanager.IssueManager;
|
||||
import io.onedev.server.entitymanager.PackManager;
|
||||
@ -207,6 +211,10 @@ public class ProjectListPanel extends Panel {
|
||||
private ProjectManager getProjectManager() {
|
||||
return OneDev.getInstance(ProjectManager.class);
|
||||
}
|
||||
|
||||
private AuditManager getAuditManager() {
|
||||
return OneDev.getInstance(AuditManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetach() {
|
||||
@ -239,6 +247,16 @@ public class ProjectListPanel extends Panel {
|
||||
target.add(saveQueryLink);
|
||||
}
|
||||
|
||||
private void auditDeletions(Collection<Project> projects) {
|
||||
for (var project: Project.getIndependents(projects)) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(project).toXML();
|
||||
if (project.getParent() != null)
|
||||
getAuditManager().audit(project.getParent(), "deleted child project \"" + project.getName() + "\"", oldAuditContent, null);
|
||||
else
|
||||
getAuditManager().audit(null, "deleted root project \"" + project.getName() + "\"", oldAuditContent, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onInitialize() {
|
||||
super.onInitialize();
|
||||
@ -426,7 +444,17 @@ public class ProjectListPanel extends Panel {
|
||||
Collection<Project> projects = new ArrayList<>();
|
||||
for (IModel<Project> each: selectionColumn.getSelections())
|
||||
projects.add(each.getObject());
|
||||
Map<Long, String> oldAuditContents = new HashMap<>();
|
||||
for (var project: projects) {
|
||||
oldAuditContents.put(project.getId(), project.getParent()!=null? project.getParent().getPath() : null);
|
||||
}
|
||||
getProjectManager().move(projects, getTargetProject());
|
||||
for (var project: projects) {
|
||||
var oldAuditContent = oldAuditContents.get(project.getId());
|
||||
var newAuditContent = project.getParent()!=null? project.getParent().getPath() : null;
|
||||
if (!Objects.equals(oldAuditContent, newAuditContent))
|
||||
getAuditManager().audit(project, "changed parent", oldAuditContent, newAuditContent);
|
||||
}
|
||||
target.add(countLabel);
|
||||
target.add(body);
|
||||
selectionColumn.getSelections().clear();
|
||||
@ -512,7 +540,16 @@ public class ProjectListPanel extends Panel {
|
||||
Collection<Project> projects = new ArrayList<>();
|
||||
for (IModel<Project> each: selectionColumn.getSelections())
|
||||
projects.add(each.getObject());
|
||||
Map<Long, String> oldAuditContents = new HashMap<>();
|
||||
for (var project: projects) {
|
||||
oldAuditContents.put(project.getId(), project.getParent()!=null? project.getParent().getPath() : null);
|
||||
}
|
||||
getProjectManager().move(projects, null);
|
||||
for (var project: projects) {
|
||||
var oldAuditContent = oldAuditContents.get(project.getId());
|
||||
if (oldAuditContent != null)
|
||||
getAuditManager().audit(project, "changed parent", oldAuditContent, null);
|
||||
}
|
||||
target.add(countLabel);
|
||||
target.add(body);
|
||||
selectionColumn.getSelections().clear();
|
||||
@ -592,6 +629,7 @@ public class ProjectListPanel extends Panel {
|
||||
observables.add(project.getDeleteChangeObservable());
|
||||
}
|
||||
getProjectManager().delete(projects);
|
||||
auditDeletions(projects);
|
||||
selectionColumn.getSelections().clear();
|
||||
target.add(countLabel);
|
||||
target.add(body);
|
||||
@ -696,7 +734,17 @@ public class ProjectListPanel extends Panel {
|
||||
Collection<Project> projects = new ArrayList<>();
|
||||
for (Iterator<Project> it = (Iterator<Project>) dataProvider.iterator(0, projectsTable.getItemCount()); it.hasNext();)
|
||||
projects.add(it.next());
|
||||
Map<Long, String> oldAuditContents = new HashMap<>();
|
||||
for (var project: projects) {
|
||||
oldAuditContents.put(project.getId(), project.getParent()!=null? project.getParent().getPath() : null);
|
||||
}
|
||||
getProjectManager().move(projects, getTargetProject());
|
||||
for (var project: projects) {
|
||||
var oldAuditContent = oldAuditContents.get(project.getId());
|
||||
var newAuditContent = project.getParent()!=null? project.getParent().getPath() : null;
|
||||
if (!Objects.equals(oldAuditContent, newAuditContent))
|
||||
getAuditManager().audit(project, "changed parent", oldAuditContent, newAuditContent);
|
||||
}
|
||||
dataProvider.detach();
|
||||
target.add(countLabel);
|
||||
target.add(body);
|
||||
@ -783,7 +831,18 @@ public class ProjectListPanel extends Panel {
|
||||
Collection<Project> projects = new ArrayList<>();
|
||||
for (Iterator<Project> it = (Iterator<Project>) dataProvider.iterator(0, projectsTable.getItemCount()); it.hasNext();)
|
||||
projects.add(it.next());
|
||||
|
||||
var oldAuditContents = new HashMap<Long, String>();
|
||||
for (var project: projects) {
|
||||
oldAuditContents.put(project.getId(), project.getParent()!=null? project.getParent().getPath() : null);
|
||||
}
|
||||
getProjectManager().move(projects, null);
|
||||
for (var project: projects) {
|
||||
var oldAuditContent = oldAuditContents.get(project.getId());
|
||||
if (oldAuditContent != null)
|
||||
getAuditManager().audit(project, "changed parent", oldAuditContent, null);
|
||||
}
|
||||
|
||||
dataProvider.detach();
|
||||
target.add(countLabel);
|
||||
target.add(body);
|
||||
@ -867,6 +926,7 @@ public class ProjectListPanel extends Panel {
|
||||
observables.add(project.getDeleteChangeObservable());
|
||||
}
|
||||
getProjectManager().delete(projects);
|
||||
auditDeletions(projects);
|
||||
dataProvider.detach();
|
||||
selectionColumn.getSelections().clear();
|
||||
target.add(countLabel);
|
||||
|
||||
@ -57,6 +57,8 @@ import com.google.common.collect.Sets;
|
||||
|
||||
import io.onedev.commons.utils.ExplicitException;
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.ProjectManager;
|
||||
import io.onedev.server.entitymanager.PullRequestManager;
|
||||
import io.onedev.server.entitymanager.PullRequestReviewManager;
|
||||
@ -68,6 +70,7 @@ import io.onedev.server.model.PullRequestLabel;
|
||||
import io.onedev.server.model.PullRequestReview;
|
||||
import io.onedev.server.model.PullRequestReview.Status;
|
||||
import io.onedev.server.model.support.LastActivity;
|
||||
import io.onedev.server.persistence.TransactionManager;
|
||||
import io.onedev.server.search.entity.EntityQuery;
|
||||
import io.onedev.server.search.entity.EntitySort;
|
||||
import io.onedev.server.search.entity.EntitySort.Direction;
|
||||
@ -148,6 +151,10 @@ public abstract class PullRequestListPanel extends Panel {
|
||||
private PullRequestManager getPullRequestManager() {
|
||||
return OneDev.getInstance(PullRequestManager.class);
|
||||
}
|
||||
|
||||
private TransactionManager getTransactionManager() {
|
||||
return OneDev.getInstance(TransactionManager.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected PagingHistorySupport getPagingHistorySupport() {
|
||||
@ -415,10 +422,16 @@ public abstract class PullRequestListPanel extends Panel {
|
||||
|
||||
@Override
|
||||
protected void onConfirm(AjaxRequestTarget target) {
|
||||
Collection<PullRequest> requests = new ArrayList<>();
|
||||
for (IModel<PullRequest> each : selectionColumn.getSelections())
|
||||
requests.add(each.getObject());
|
||||
OneDev.getInstance(PullRequestManager.class).delete(requests, getProject());
|
||||
getTransactionManager().run(()-> {
|
||||
Collection<PullRequest> requests = new ArrayList<>();
|
||||
for (IModel<PullRequest> each : selectionColumn.getSelections())
|
||||
requests.add(each.getObject());
|
||||
getPullRequestManager().delete(requests, getProject());
|
||||
for (var request: requests) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(request).toXML();
|
||||
getAuditManager().audit(request.getProject(), "deleted pull request \"" + request.getReference().toString(request.getProject()) + "\"", oldAuditContent, null);
|
||||
}
|
||||
});
|
||||
target.add(countLabel);
|
||||
target.add(body);
|
||||
selectionColumn.getSelections().clear();
|
||||
@ -614,10 +627,16 @@ public abstract class PullRequestListPanel extends Panel {
|
||||
|
||||
@Override
|
||||
protected void onConfirm(AjaxRequestTarget target) {
|
||||
Collection<PullRequest> requests = new ArrayList<>();
|
||||
for (Iterator<PullRequest> it = (Iterator<PullRequest>) dataProvider.iterator(0, requestsTable.getItemCount()); it.hasNext(); )
|
||||
requests.add(it.next());
|
||||
OneDev.getInstance(PullRequestManager.class).delete(requests, getProject());
|
||||
getTransactionManager().run(()-> {
|
||||
Collection<PullRequest> requests = new ArrayList<>();
|
||||
for (Iterator<PullRequest> it = (Iterator<PullRequest>) dataProvider.iterator(0, requestsTable.getItemCount()); it.hasNext(); )
|
||||
requests.add(it.next());
|
||||
getPullRequestManager().delete(requests, getProject());
|
||||
for (var request: requests) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(request).toXML();
|
||||
getAuditManager().audit(request.getProject(), "deleted pull request \"" + request.getReference().toString(request.getProject()) + "\"", oldAuditContent, null);
|
||||
}
|
||||
});
|
||||
dataProvider.detach();
|
||||
target.add(countLabel);
|
||||
target.add(body);
|
||||
@ -1106,6 +1125,10 @@ public abstract class PullRequestListPanel extends Panel {
|
||||
return OneDev.getInstance(PullRequestWatchManager.class);
|
||||
}
|
||||
|
||||
private AuditManager getAuditManager() {
|
||||
return OneDev.getInstance(AuditManager.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderHead(IHeaderResponse response) {
|
||||
super.renderHead(response);
|
||||
|
||||
@ -96,15 +96,19 @@
|
||||
}
|
||||
|
||||
.select2-container-multi .select2-choices .select2-search-field input {
|
||||
height: calc(1.5em + 1.3rem);
|
||||
height: calc(1.5em + 1.3rem);
|
||||
line-height: 1.42857;
|
||||
}
|
||||
|
||||
.select2-container-multi.form-control-sm .select2-choices .select2-search-field input,
|
||||
.input-group-sm .select2-container-multi .select2-choices .select2-search-field input {
|
||||
height: calc(1.35em + 1.1rem + 2px);
|
||||
height: calc(1.3em + 1.1rem + 1px);
|
||||
line-height: 1.35;
|
||||
border-radius: 0.42rem;
|
||||
border-radius: 0.28rem;
|
||||
}
|
||||
|
||||
.form-control-sm.select2-container .select2-choice, .form-control-sm.select2-container .select2-choices {
|
||||
border-radius: 0.28rem;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,19 +1,21 @@
|
||||
package io.onedev.server.web.component.user;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import io.onedev.server.web.WebSession;
|
||||
import io.onedev.server.web.page.admin.usermanagement.UserListPage;
|
||||
import io.onedev.server.web.util.ConfirmClickModifier;
|
||||
|
||||
import static io.onedev.server.web.translation.Translation._T;
|
||||
|
||||
import org.apache.wicket.RestartResponseException;
|
||||
import org.apache.wicket.markup.html.link.Link;
|
||||
import org.apache.wicket.request.flow.RedirectToUrlException;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.UserManager;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.security.SecurityUtils;
|
||||
import io.onedev.server.web.WebSession;
|
||||
import io.onedev.server.web.page.admin.usermanagement.UserListPage;
|
||||
import io.onedev.server.web.util.ConfirmClickModifier;
|
||||
|
||||
public abstract class UserDeleteLink extends Link<Void> {
|
||||
|
||||
public UserDeleteLink(String id) {
|
||||
@ -30,13 +32,17 @@ public abstract class UserDeleteLink extends Link<Void> {
|
||||
@Override
|
||||
public void onClick() {
|
||||
var userManager = OneDev.getInstance(UserManager.class);
|
||||
var auditManager = OneDev.getInstance(AuditManager.class);
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(getUser()).toXML();
|
||||
if (getUser().equals(SecurityUtils.getAuthUser())) {
|
||||
userManager.delete(getUser());
|
||||
auditManager.audit(null, "deleted account \"" + getUser().getName() + "\"", oldAuditContent, null);
|
||||
WebSession.get().success("Account removed");
|
||||
WebSession.get().logout();
|
||||
throw new RestartResponseException(getApplication().getHomePage());
|
||||
} else {
|
||||
userManager.delete(getUser());
|
||||
auditManager.audit(null, "deleted account \"" + getUser().getName() + "\"", oldAuditContent, null);
|
||||
WebSession.get().success("Account removed");
|
||||
String redirectUrlAfterDelete = WebSession.get().getRedirectUrlAfterDelete(User.class);
|
||||
if (redirectUrlAfterDelete != null)
|
||||
|
||||
@ -15,8 +15,10 @@ import org.apache.wicket.markup.html.panel.Panel;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AccessTokenAuthorizationManager;
|
||||
import io.onedev.server.entitymanager.AccessTokenManager;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.entitymanager.ProjectManager;
|
||||
import io.onedev.server.entitymanager.RoleManager;
|
||||
import io.onedev.server.model.AccessToken;
|
||||
@ -25,9 +27,12 @@ import io.onedev.server.persistence.TransactionManager;
|
||||
import io.onedev.server.util.Path;
|
||||
import io.onedev.server.util.PathNode;
|
||||
import io.onedev.server.web.editable.BeanContext;
|
||||
import io.onedev.server.web.page.user.UserPage;
|
||||
|
||||
abstract class AccessTokenEditPanel extends Panel {
|
||||
|
||||
private String oldAuditContent;
|
||||
|
||||
public AccessTokenEditPanel(String id) {
|
||||
super(id);
|
||||
}
|
||||
@ -40,6 +45,9 @@ abstract class AccessTokenEditPanel extends Panel {
|
||||
|
||||
var token = getToken();
|
||||
var bean = AccessTokenEditBean.of(token);
|
||||
|
||||
if (!token.isNew())
|
||||
oldAuditContent = VersionedXmlDoc.fromBean(bean).toXML();
|
||||
|
||||
var editor = BeanContext.edit("editor", bean, Sets.newHashSet("value"), true);
|
||||
form.add(editor);
|
||||
@ -89,8 +97,15 @@ abstract class AccessTokenEditPanel extends Panel {
|
||||
token.setExpireDate(bean.getExpireDate());
|
||||
|
||||
getTransactionManager().run(() -> {
|
||||
if (token.isNew())
|
||||
getTokenManager().createOrUpdate(token);
|
||||
getAuthorizationManager().syncAuthorizations(token, authorizations);
|
||||
if (getPage() instanceof UserPage) {
|
||||
var newAuditContent = VersionedXmlDoc.fromBean(bean).toXML();
|
||||
var verb = oldAuditContent != null ? "changed" : "created";
|
||||
getAuditManager().audit(null, verb + " access token \"" + token.getName() + "\" for account \"" + token.getOwner().getName() + "\"", oldAuditContent, newAuditContent);
|
||||
oldAuditContent = newAuditContent;
|
||||
}
|
||||
});
|
||||
onSaved(target);
|
||||
}
|
||||
@ -115,6 +130,10 @@ abstract class AccessTokenEditPanel extends Panel {
|
||||
|
||||
setOutputMarkupId(true);
|
||||
}
|
||||
|
||||
private AuditManager getAuditManager() {
|
||||
return OneDev.getInstance(AuditManager.class);
|
||||
}
|
||||
|
||||
private TransactionManager getTransactionManager() {
|
||||
return OneDev.getInstance(TransactionManager.class);
|
||||
|
||||
@ -15,9 +15,12 @@ import org.apache.wicket.markup.html.panel.Panel;
|
||||
import org.apache.wicket.model.AbstractReadOnlyModel;
|
||||
|
||||
import io.onedev.server.OneDev;
|
||||
import io.onedev.server.data.migration.VersionedXmlDoc;
|
||||
import io.onedev.server.entitymanager.AccessTokenManager;
|
||||
import io.onedev.server.entitymanager.AuditManager;
|
||||
import io.onedev.server.model.AccessToken;
|
||||
import io.onedev.server.model.User;
|
||||
import io.onedev.server.web.page.user.UserPage;
|
||||
|
||||
public abstract class AccessTokenListPanel extends Panel {
|
||||
|
||||
@ -50,7 +53,12 @@ public abstract class AccessTokenListPanel extends Panel {
|
||||
|
||||
@Override
|
||||
protected void onDelete(AjaxRequestTarget target) {
|
||||
getTokenManager().delete(getToken());
|
||||
var token = getToken();
|
||||
getTokenManager().delete(token);
|
||||
if (getPage() instanceof UserPage) {
|
||||
var oldAuditContent = VersionedXmlDoc.fromBean(token).toXML();
|
||||
getAuditManager().audit(null, "deleted access token \"" + token.getName() + "\" for account \"" + token.getOwner().getName() + "\"", oldAuditContent, null);
|
||||
}
|
||||
target.add(container);
|
||||
}
|
||||
|
||||
@ -146,4 +154,8 @@ public abstract class AccessTokenListPanel extends Panel {
|
||||
return OneDev.getInstance(AccessTokenManager.class);
|
||||
}
|
||||
|
||||
private AuditManager getAuditManager() {
|
||||
return OneDev.getInstance(AuditManager.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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