URMS-36: Плагин для Confluence готов, протестирован и поставлен в бой.

master 1.1.1
CMX\tiburon 2019-07-29 13:07:40 +03:00
parent 698d117cdc
commit f1f87a39f2
27 changed files with 2355 additions and 1 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.settings
.vscode
target
.classpath
.project

340
README.md
View File

@ -1,2 +1,340 @@
# confluence-rest-extender [![OCTOPUS CodeWare](https://www.tiburon.su/files/logo_octo_text_600_153.png)](https://www.tiburon.su)
REST API Extender for Confluence
================
REST API for automated Confluence configuration with URMS
Resources
---------
All resources produce JSON (media type: `application/json`) results.
### Page versions
Get and delete outdated page versions
* #### `GET /rest/extender/1/api/versions/all`
**QueryString**
- type: all or page or attachment. (default:all)
- endDays: 1 (0=today, 1=yesterday) (default:0)
- limit: 11000 (default:1000)
Get all page versions in all instance.
__Responses__
![Status 200][status-200]
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
* #### `DELETE /rest/extender/1/api/versions/all`
**QueryString**
- type: all or page or attachment. (default:all)
- endDays: 1 (0=today, 1=yesterday) (default:0)
- limit: 11000 (default:1000)
Remove all page versions in all instance.
__Responses__
![Status 200][status-200]
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
* #### `GET /rest/extender/1/api/versions/space/{spaceKey}`
**QueryString**
- spaceKey: Key of the target space. (required)
- type: all or page or attachment. (default:all)
- endDays: 1 (0=today, 1=yesterday) (default:0)
- limit: 11000 (default:1000)
Get all page versions in space with key=`spaceKey`.
__Responses__
![Status 200][status-200]
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
* #### `DELETE /rest/extender/1/api/versions/space/{spaceKey}`
**QueryString**
- spaceKey: Key of the target space. (required)
- type: all or page or attachment. (default:all)
- endDays: 1 (0=today, 1=yesterday) (default:0)
- limit: 11000 (default:1000)
Remove all page versions in space with key=`spaceKey`.
__Responses__
![Status 200][status-200]
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
* #### `GET /rest/extender/1/api/versions/page/{pageId}`
**QueryString**
- pageId: Id of the target page. (required)
- type: all or page or attachment. (default:all)
- endDays: 1 (0=today, 1=yesterday) (default:0)
- limit: 11000 (default:1000)
Get versions of the page with id=`pageId`.
__Responses__
![Status 200][status-200]
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
* #### `DELETE /rest/extender/1/api/versions/page/{pageId}`
**QueryString**
- pageId: Id of the target page. (required)
- type: all or page or attachment. (default:all)
- endDays: 1 (0=today, 1=yesterday) (default:0)
- limit: 11000 (default:1000)
Remove versions of the page with id=`pageId`.
__Responses__
![Status 200][status-200]
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
### Trashes
Get and delete trash
* #### `GET /rest/extender/1/api/trash/all`
**QueryString**
- limit: 11000 (default:1000)
Get all trash in all instance.
__Responses__
![Status 200][status-200]
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
* #### `DELETE /rest/extender/1/api/trash/all`
**QueryString**
- limit: 11000 (default:1000)
Remove all trash in all instance.
__Responses__
![Status 200][status-200]
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
* #### `GET /rest/extender/1/api/trash/space/{spaceKey}`
**QueryString**
- spaceKey: Key of the target space. (required)
- limit: 11000 (default:1000)
Get trash from space with key=`spaceKey`.
__Responses__
![Status 200][status-200]
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
* #### `DELETE /rest/extender/1/api/trash/space/{spaceKey}`
**QueryString**
- spaceKey: Key of the target space. (required)
- limit: 11000 (default:1000)
Remove trash from space with key=`spaceKey`.
__Responses__
![Status 200][status-200]
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
**QueryString**
- type: all or page or attachment. (default:all)
- endDays: 1 (0=today, 1=yesterday) (default:0)
- limit: 11000 (default:1000)
Remove versions of the page with id=`pageId`.
__Responses__
![Status 200][status-200]
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
### Syncronise Crowd User Directory
* #### `GET /rest/extender/1/directory`
Get info about User Directories.
__Responses__
![Status 200][status-200]
```javascript
[
{
"id": 262145,
"type": "INTERNAL",
"issynchronising": false
},
{
"id": 1277953,
"type": "CROWD",
"issynchronising": false
}
]
```
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
* #### `PUT /rest/extender/1/directory`
**QueryString**
- id: User Directory ID. (required)
Start sycronyse User Directory.
__Responses__
![Status 200][status-200]
If OK, `issynchronising` of target directory returned as `true`
```javascript
[
{
"id": 262145,
"type": "INTERNAL",
"issynchronising": false
},
{
"id": 1277953,
"type": "CROWD",
"issynchronising": true
}
]
```
![Status 401][status-401]
Returned if the current user is not authenticated.
![Status 403][status-403]
Returned if the current user is not an administrator.
[status-200]: https://img.shields.io/badge/status-200-brightgreen.svg
[status-400]: https://img.shields.io/badge/status-400-red.svg
[status-401]: https://img.shields.io/badge/status-401-red.svg
[status-403]: https://img.shields.io/badge/status-403-red.svg
[status-404]: https://img.shields.io/badge/status-404-red.svg

229
pom.xml Normal file
View File

@ -0,0 +1,229 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>su.tiburon.confluence</groupId>
<artifactId>rest-extender</artifactId>
<version>1.1.1</version>
<packaging>atlassian-plugin</packaging>
<name>REST API extender for Confluence</name>
<description>REST API extender for Confluence.</description>
<licenses>
<license>
<name>BSD 3-Clause License</name>
<url>https://opensource.org/licenses/BSD-3-Clause</url>
</license>
</licenses>
<issueManagement>
<system>Github</system>
<url>https://github.com/tiburon-777/confluence-rest-extender/issues</url>
</issueManagement>
<scm>
<connection>scm:git:git://github.com/tiburon-777/confluence-rest-extender.git</connection>
<developerConnection>scm:git:git@github.com:tiburon-777/confluence-rest-extender.git</developerConnection>
<url>https://github.com/tiburon-777/confluence-rest-extender</url>
</scm>
<organization>
<name>OCTOPUS CodeWare</name>
<url>http://www.tiburon.su/</url>
</organization>
<developers>
<developer>
<name>Andrey Ivanov</name>
<email>ya@tiburon.su</email>
<organization>OCTOPUS CodeWare</organization>
<organizationUrl>https://www.tiburon.su</organizationUrl>
</developer>
</developers>
<repositories>
<repository>
<id>atlassian-public</id>
<url>https://packages.atlassian.com/maven/repository/public</url>
<snapshots>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
<releases>
<enabled>true</enabled>
<checksumPolicy>warn</checksumPolicy>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>atlassian-public</id>
<url>https://m2proxy.atlassian.com/repository/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20090211</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.atlassian.confluence</groupId>
<artifactId>confluence</artifactId>
<version>${confluence.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-annotation</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>provided</scope>
</dependency>
<!-- WIRED TEST RUNNER DEPENDENCIES -->
<dependency>
<groupId>com.atlassian.plugins</groupId>
<artifactId>atlassian-plugins-osgi-testrunner</artifactId>
<version>${plugin.testrunner.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.2-atlassian-1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.atlassian.plugins.rest</groupId>
<artifactId>atlassian-rest-common</artifactId>
<version>1.0.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.atlassian.sal</groupId>
<artifactId>sal-api</artifactId>
<version>2.10.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.wink</groupId>
<artifactId>wink-client</artifactId>
<version>1.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>confluence-maven-plugin</artifactId>
<version>${amps.version}</version>
<extensions>true</extensions>
<configuration>
<productVersion>${confluence.version}</productVersion>
<productDataVersion>${confluence.data.version}</productDataVersion>
<enableQuickReload>true</enableQuickReload>
<!-- See here for an explanation of default instructions: -->
<!-- https://developer.atlassian.com/docs/advanced-topics/configuration-of-instructions-in-atlassian-plugins -->
<instructions>
<Atlassian-Plugin-Key>${atlassian.plugin.key}</Atlassian-Plugin-Key>
<!-- Add package to export here -->
<Export-Package>sample.api</Export-Package>
<!-- Add package import here -->
<Import-Package>
<!-- For use of @ModuleType -->
<!-- com.atlassian.plugin.osgi.bridge.external, -->
<!-- For ConfluenceImports -->
com.atlassian.confluence.*;resolution:="optional",
<!-- All the rest should be common to all products -->
*
</Import-Package>
<!-- Ensure plugin is spring powered -->
<Spring-Context>*</Spring-Context>
</instructions>
<skipManifestValidation>true</skipManifestValidation>
</configuration>
</plugin>
<plugin>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-maven-plugin</artifactId>
<version>${atlassian.spring.scanner.version}</version>
<executions>
<execution>
<goals>
<goal>atlassian-spring-scanner</goal>
</goals>
<phase>process-classes</phase>
</execution>
</executions>
<configuration>
<scannedDependencies>
<dependency>
<groupId>com.atlassian.plugin</groupId>
<artifactId>atlassian-spring-scanner-external-jar</artifactId>
</dependency>
</scannedDependencies>
<verbose>false</verbose>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<confluence.version>6.14.0</confluence.version>
<confluence.data.version>6.14.0</confluence.data.version>
<amps.version>8.0.0</amps.version>
<plugin.testrunner.version>2.0.1</plugin.testrunner.version>
<atlassian.spring.scanner.version>2.1.8</atlassian.spring.scanner.version>
<!-- This property ensures consistency between the key in atlassian-plugin.xml and the OSGi bundle's key. -->
<atlassian.plugin.key>${project.groupId}.${project.artifactId}</atlassian.plugin.key>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
</project>

View File

@ -0,0 +1,49 @@
package su.tiburon.atlassian.confluence.api;
import java.util.Date;
import java.util.List;
import com.atlassian.confluence.pages.AbstractPage;
import com.atlassian.confluence.pages.Attachment;
import com.atlassian.confluence.pages.Page;
import com.atlassian.confluence.spaces.Space;
import su.tiburon.atlassian.confluence.rest.PageVersionsModel;
import su.tiburon.atlassian.confluence.rest.SpaceTrashModel;
import su.tiburon.atlassian.confluence.rest.SpaceVersionsModel;
public interface DataCleanUtil {
public abstract Date getCreatedOrUpdatedDate(int paramInt);
public abstract List<Attachment> getAttachmentVersions(Attachment attachment, int endDays);
public abstract List<AbstractPage> getPageVersions(Page page, int endDays, String type);
public abstract long removePageVersions(Page paramPage, int paramInt, String paramString);
public abstract long removeSpaceVersions(Space paramSpace, int paramInt, String paramString);
public abstract long removeAllVersions(int paramInt, String paramString);
public abstract int removeSpaceTrash(Space paramSpace);
public abstract long removeAllTrash();
public abstract PageVersionsModel getPageVersionSummary(Page page, int endDays, String type);
public abstract SpaceVersionsModel getSpaceVersionSummary(Space paramSpace, int paramInt, String paramString);
public abstract List<SpaceVersionsModel> getAllVersionSummary(int paramInt, String paramString);
public abstract SpaceTrashModel getSpaceTrashSummary(Space paramSpace);
public abstract List<SpaceTrashModel> getAllTrashSummary();
public abstract void setLimit(int paramInt);
public abstract int getLimit();
public abstract void setCount(int paramInt);
public abstract int getCount();
}

View File

@ -0,0 +1,7 @@
package su.tiburon.atlassian.confluence.api;
import java.util.Date;
public interface DateTimeUtil {
public abstract Date getDate();
}

View File

@ -0,0 +1,364 @@
package su.tiburon.atlassian.confluence.impl;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.atlassian.confluence.core.VersionHistorySummary;
import com.atlassian.confluence.pages.AbstractPage;
import com.atlassian.confluence.pages.Attachment;
import com.atlassian.confluence.pages.AttachmentManager;
import com.atlassian.confluence.pages.Page;
import com.atlassian.confluence.pages.PageManager;
import com.atlassian.confluence.pages.TrashManager;
import com.atlassian.confluence.spaces.Space;
import com.atlassian.confluence.spaces.SpaceManager;
import com.atlassian.plugin.spring.scanner.annotation.export.ExportAsService;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import su.tiburon.atlassian.confluence.api.DataCleanUtil;
import su.tiburon.atlassian.confluence.api.DateTimeUtil;
import su.tiburon.atlassian.confluence.rest.AttachmentModel;
import su.tiburon.atlassian.confluence.rest.PageVersionsModel;
import su.tiburon.atlassian.confluence.rest.SpaceTrashModel;
import su.tiburon.atlassian.confluence.rest.SpaceVersionsModel;
@ExportAsService
@Named
public class DataCleanUtilImpl implements DataCleanUtil {
private static final Logger logger = LoggerFactory.getLogger(DataCleanUtil.class);
@ComponentImport
private final PageManager pageManager;
@ComponentImport
private final AttachmentManager attachmentManager;
@ComponentImport
private final TrashManager trashManager;
@ComponentImport
private final SpaceManager spaceManager;
private DateTimeUtil dateTimeUtil;
private int limit;
private int count;
@Inject
public DataCleanUtilImpl(PageManager pageManager, AttachmentManager attachmentManager, TrashManager trashManager, SpaceManager spaceManager, DateTimeUtil dateTimeUtil) {
this.pageManager = pageManager;
this.attachmentManager = attachmentManager;
this.trashManager = trashManager;
this.spaceManager = spaceManager;
this.limit = 1000;
this.count = 0;
this.dateTimeUtil = dateTimeUtil;
}
@Override
public Date getCreatedOrUpdatedDate(int endDays) {
Date defaultDate = dateTimeUtil.getDate();
try {
int lastCreatedOrUpdated = Integer.parseInt("-" + endDays);
Calendar cal = Calendar.getInstance();
cal.setTime(defaultDate);
cal.add(Calendar.DAY_OF_MONTH, lastCreatedOrUpdated);
return cal.getTime();
} catch (NumberFormatException e) {
logger.error(e.getMessage(), e);
}
return defaultDate;
}
@Override
public List<Attachment> getAttachmentVersions(Attachment attachment, int endDays) {
List<Attachment> resultAttachments = new ArrayList<Attachment>();
Date lastUpdatedOrCreatedDate = getCreatedOrUpdatedDate(endDays);
List<Attachment> vAttachments = this.attachmentManager.getPreviousVersions(attachment);
for (Attachment vAttachment : vAttachments) {
if (vAttachment.getLastModificationDate().before(lastUpdatedOrCreatedDate)) {
resultAttachments.add(vAttachment);
}
}
return resultAttachments;
}
@Override
public List<AbstractPage> getPageVersions(Page page, int endDays, String type) {
List<AbstractPage> resultVersions = new ArrayList<AbstractPage>();
Date lastUpdatedOrCreatedDate = getCreatedOrUpdatedDate(endDays);
List<VersionHistorySummary> versions = this.pageManager.getVersionHistorySummaries(page);
for (VersionHistorySummary vSummary : versions) {
if (page.getId() != vSummary.getId() && vSummary.getLastModificationDate().before(lastUpdatedOrCreatedDate)) {
AbstractPage vPage = this.pageManager.getPage(vSummary.getId());
if (vPage == null) {
vPage = this.pageManager.getBlogPost(vSummary.getId());
}
if (vPage != null) {
resultVersions.add(vPage);
}
}
}
return resultVersions;
}
@Override
public long removePageVersions(Page page, int endDays, String type) {
long delete_index = 0;
if (this.count >= this.limit) {
return delete_index;
}
if ("all".equals(type) || "page".equals(type)) {
List<AbstractPage> aPages = getPageVersions(page, endDays, type);
for (AbstractPage aPage : aPages) {
this.pageManager.removeHistoricalVersion(aPage);
delete_index++;
}
if (delete_index > 0) {
this.count++;
if (this.count >= this.limit) {
return delete_index;
}
}
}
if ("all".equals(type) || "attachment".equals(type)) {
List<Attachment> attachments = attachmentManager.getLatestVersionsOfAttachments(page);
for (Attachment attachment : attachments) {
List<Attachment> targetAttachments = getAttachmentVersions(attachment, endDays);
for (Attachment targetAttachment : targetAttachments) {
this.attachmentManager.removeAttachmentVersionFromServer(targetAttachment);
delete_index++;
}
if (targetAttachments.size() > 0) {
this.count++;
if (this.count >= this.limit) {
return delete_index;
}
}
}
}
return delete_index;
}
@Override
public long removeSpaceVersions(Space space, int endDays, String type) {
Date lastUpdatedOrCreatedDate = getCreatedOrUpdatedDate(endDays);
Collection<Page> pages = this.pageManager.getPages(space, true);
long delete_index = 0L;
for (Page page : pages) {
if (page.getCreationDate().before(lastUpdatedOrCreatedDate)) {
delete_index += removePageVersions(page, endDays, type);
if (this.count >= this.limit) {
return delete_index;
}
}
}
return delete_index;
}
@Override
public long removeAllVersions(int endDays, String type) {
long delete_index = 0L;
for (Space space : this.spaceManager.getAllSpaces()) {
delete_index += this.removeSpaceVersions(space, endDays, type);
if (this.count >= this.limit) {
return delete_index;
}
}
return delete_index;
}
@Override
public int removeSpaceTrash(Space space) {
int numberOfItems = this.trashManager.getNumberOfItemsInTrash(space);
this.trashManager.emptyTrash(space);
return numberOfItems;
}
@Override
public long removeAllTrash() {
long deleted = 0L;
for (Space space : this.spaceManager.getAllSpaces()) {
deleted += this.removeSpaceTrash(space);
this.count++;
if (this.count >= this.limit) {
return deleted;
}
}
return deleted;
}
@Override
public PageVersionsModel getPageVersionSummary(Page page, int endDays, String type) {
List<AbstractPage> resultVersions = new ArrayList<AbstractPage>();
if ("all".equals(type) || "page".equals(type)) {
resultVersions = getPageVersions(page, endDays, type);
}
PageVersionsModel pageModel = new PageVersionsModel();
String modifier = page.getLastModifier() != null ? page.getLastModifier().getName() : "";
pageModel.setId(page.getId());
pageModel.setTitle(page.getTitle());
pageModel.setVersionCount(resultVersions.size());
pageModel.setLastModifier(modifier);
pageModel.setLastModified(page.getLastModificationDate());
long totalPageVersionCount = pageModel.getVersionCount();
if (pageModel.getVersionCount() > 0) {
this.count++;
if (this.count >= this.limit) {
pageModel.setTotalVersionCount(totalPageVersionCount);
return pageModel;
}
}
if ("all".equals(type) || "attachment".equals(type)) {
List<Attachment> attachments = attachmentManager.getLatestVersionsOfAttachments(page);
List<Attachment> attachmentVersions = new ArrayList<Attachment>();
List<AttachmentModel> attachmentModels = new ArrayList<AttachmentModel>();
for (Attachment attachment : attachments) {
List<Attachment> tmpAttachmentVersions = getAttachmentVersions(attachment, endDays);
int tmpAttachmentVersionsCount = tmpAttachmentVersions.size();
if (tmpAttachmentVersionsCount > 0) {
attachmentVersions.addAll(tmpAttachmentVersions);
totalPageVersionCount += tmpAttachmentVersions.size();
String last_modifier = attachment.getLastModifier() != null ? attachment.getLastModifier().getName() : "";
AttachmentModel model = new AttachmentModel(
attachment.getId(),
attachment.getTitle(),
tmpAttachmentVersionsCount,
last_modifier,
attachment.getLastModificationDate()
);
attachmentModels.add(model);
this.count++;
if (this.count >= this.limit) {
break;
}
}
}
pageModel.setAttachments(attachmentModels);
}
pageModel.setTotalVersionCount(totalPageVersionCount);
return pageModel;
}
@Override
public SpaceVersionsModel getSpaceVersionSummary(Space space, int endDays, String type) {
Collection<Page> pages = this.pageManager.getPages(space, true);
List<PageVersionsModel> pageModels = new ArrayList<PageVersionsModel>();
long totalSpaceVersionCount = 0;
for (Page page : pages) {
PageVersionsModel pageModel = getPageVersionSummary(page, endDays, type);
if (pageModel.getTotalVersionCount() > 0) {
totalSpaceVersionCount += pageModel.getTotalVersionCount();
pageModels.add(pageModel);
}
if (this.count >= this.limit) {
break;
}
}
SpaceVersionsModel spaceModel = new SpaceVersionsModel(space.getKey(), space.getDisplayTitle(), totalSpaceVersionCount, pageModels);
return spaceModel;
}
@Override
public List<SpaceVersionsModel> getAllVersionSummary(int endDays, String type) {
List<SpaceVersionsModel> spaceModels = new ArrayList<SpaceVersionsModel>();
for (Space space : this.spaceManager.getAllSpaces()) {
SpaceVersionsModel spaceModel = this.getSpaceVersionSummary(space, endDays, type);
if(spaceModel.getTotalVersionCount() > 0) {
spaceModels.add(spaceModel);
}
if (this.count >= this.limit) {
return spaceModels;
}
}
return spaceModels;
}
@Override
public SpaceTrashModel getSpaceTrashSummary(Space space) {
int numberOfItems = this.trashManager.getNumberOfItemsInTrash(space);
SpaceTrashModel trashModel = new SpaceTrashModel(space.getKey(), space.getDisplayTitle(), numberOfItems);
return trashModel;
}
@Override
public List<SpaceTrashModel> getAllTrashSummary() {
List<SpaceTrashModel> trashModels = new ArrayList<SpaceTrashModel>();
for (Space space : this.spaceManager.getAllSpaces()) {
SpaceTrashModel trashModel = this.getSpaceTrashSummary(space);
if (trashModel.getNumberOfItemsInTrash() > 0) {
trashModels.add(trashModel);
this.count++;
if (this.count >= this.limit) {
return trashModels;
}
}
}
return trashModels;
}
@Override
public void setLimit(int limit) {
this.limit = limit;
}
@Override
public int getLimit() {
return this.limit;
}
@Override
public void setCount(int count) {
this.count = count;
}
@Override
public int getCount() {
return this.count;
}
}

View File

@ -0,0 +1,21 @@
package su.tiburon.atlassian.confluence.impl;
import java.util.Date;
import javax.inject.Named;
import com.atlassian.plugin.spring.scanner.annotation.export.ExportAsService;
import su.tiburon.atlassian.confluence.api.DateTimeUtil;
@ExportAsService
@Named
public class DateTimeUtilImpl implements DateTimeUtil {
@Override
public Date getDate() {
return new Date();
}
}

View File

@ -0,0 +1,34 @@
package su.tiburon.atlassian.confluence.rest;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class AllTrashModel {
@XmlElementWrapper
@XmlElement(name="trash")
public List<SpaceTrashModel> trashList;
public AllTrashModel() {
this.trashList = new ArrayList<SpaceTrashModel>();
}
public AllTrashModel(List<SpaceTrashModel> trashList) {
this.trashList = trashList;
}
public List<SpaceTrashModel> getTrashList() {
return trashList;
}
public void setTrashList(List<SpaceTrashModel> trashList) {
this.trashList = trashList;
}
}

View File

@ -0,0 +1,34 @@
package su.tiburon.atlassian.confluence.rest;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class AllVersionsModel {
@XmlElementWrapper
@XmlElement(name="space")
public List<SpaceVersionsModel> spaces;
public AllVersionsModel() {
this.spaces = new ArrayList<SpaceVersionsModel>();
}
public AllVersionsModel(List<SpaceVersionsModel> spaces) {
this.spaces = spaces;
}
public List<SpaceVersionsModel> getSpaces() {
return spaces;
}
public void setSpaces(List<SpaceVersionsModel> spaces) {
this.spaces = spaces;
}
}

View File

@ -0,0 +1,79 @@
package su.tiburon.atlassian.confluence.rest;
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class AttachmentModel {
@XmlElement
public String id;
@XmlElement
public String title;
@XmlElement
public int versionCount;
@XmlElement
public String lastModifier;
@XmlElement
public String lastModified;
public AttachmentModel() {
this.id = "";
this.title = "";
this.versionCount = -1;
this.lastModifier = "";
this.lastModified = "";
}
public AttachmentModel(Long id, String title, int versionCount, String lastModifier, Date lastModified) {
this.id = String.valueOf(id);
this.title = title;
this.versionCount = versionCount;
this.lastModifier = lastModifier;
this.lastModified = String.valueOf(lastModified);
}
public String getId() {
return id;
}
public void setId(Long id) {
this.id = String.valueOf(id);
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getVersionCount() {
return versionCount;
}
public void setVersionCount(int versionCount) {
this.versionCount = versionCount;
}
public String getLastModifier() {
return lastModifier;
}
public void setLastModifier(String lastModifier) {
this.lastModifier = lastModifier;
}
public String getLastModified() {
return lastModified;
}
public void setLastModified(Date lastModified) {
this.lastModified = String.valueOf(lastModified);
}
}

View File

@ -0,0 +1,456 @@
package su.tiburon.atlassian.confluence.rest;
import java.text.MessageFormat;
import java.util.List;
import javax.inject.Inject;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import com.atlassian.confluence.pages.Page;
import com.atlassian.confluence.pages.PageManager;
import com.atlassian.confluence.security.Permission;
import com.atlassian.confluence.security.PermissionManager;
import com.atlassian.confluence.spaces.Space;
import com.atlassian.confluence.spaces.SpaceManager;
import com.atlassian.confluence.user.AuthenticatedUserThreadLocal;
import com.atlassian.confluence.user.ConfluenceUser;
import com.atlassian.plugin.spring.scanner.annotation.imports.ConfluenceImport;
import com.atlassian.plugins.rest.common.security.AnonymousAllowed;
import su.tiburon.atlassian.confluence.api.DataCleanUtil;
@Path("/api")
public class Cleaner {
private static final Logger logger = LoggerFactory.getLogger(Cleaner.class);
private final DataCleanUtil dataCleanUtil;
@ConfluenceImport
private final PermissionManager permissionManager;
@ConfluenceImport
private final PageManager pageManager;
@ConfluenceImport
private final SpaceManager spaceManager;
private final static int MAX_LIMIT_FOR_VERSIONS = 1000;
private final static int MAX_LIMIT_FOR_TRASH = 100;
private final static long NOT_DELETED = 0;
private final static String ITEM_TYPE_FOR_SPACE_TRASH = "SpaceTrash";
private final static String END_DAYS_FOR_SPACE_TRASH = "Endless";
@Inject
public Cleaner(DataCleanUtil dataCleanUtil, PermissionManager permissionManager, PageManager pageManager, SpaceManager spaceManager) {
this.dataCleanUtil = dataCleanUtil;
this.permissionManager = permissionManager;
this.pageManager = pageManager;
this.spaceManager = spaceManager;
}
@GET
@Produces({MediaType.APPLICATION_JSON})
@Path("/versions/all")
@AnonymousAllowed
public Response getAllVersions(@QueryParam("type") String type, @QueryParam("endDays") String endDaysStr, @QueryParam("limit") String limitStr) {
// Authentication
ConfluenceUser loggedInAppUser = AuthenticatedUserThreadLocal.get();
if (!this.permissionManager.isConfluenceAdministrator(loggedInAppUser)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(new ErrorModel("401 Unauthorized", "Confluence Administrator Permission required!")).build();
}
// Validate Params
VersionBaseParam baseParam = new VersionBaseParam(type, endDaysStr, limitStr, MAX_LIMIT_FOR_VERSIONS);
if (baseParam.getErrorModel().getMessages().size() > 0) {
return Response.status(Response.Status.BAD_REQUEST).entity(baseParam.getErrorModel()).build();
}
// Set up
this.dataCleanUtil.setLimit(baseParam.getLimit());
this.dataCleanUtil.setCount(0);
// Main process
List<SpaceVersionsModel> spaceModels = this.dataCleanUtil.getAllVersionSummary(baseParam.getEndDays(), baseParam.getType());
ResponseModel responseModel = new ResponseModel(
baseParam.getType(),
baseParam.getEndDays(),
baseParam.getLimit(),
this.dataCleanUtil.getCount(),
NOT_DELETED,
NOT_DELETED,
spaceModels);
return Response.ok(responseModel).build();
}
@DELETE
@Produces({MediaType.APPLICATION_JSON})
@Path("/versions/all")
@AnonymousAllowed
public Response deleteAllVersions(@QueryParam("type") String type, @QueryParam("endDays") String endDaysStr, @QueryParam("limit") String limitStr) {
// Authentication
ConfluenceUser loggedInAppUser = AuthenticatedUserThreadLocal.get();
if (!this.permissionManager.isConfluenceAdministrator(loggedInAppUser)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(new ErrorModel("401 Unauthorized", "Confluence Administrator Permission required!")).build();
}
// Validate Params
VersionBaseParam baseParam = new VersionBaseParam(type, endDaysStr, limitStr, MAX_LIMIT_FOR_VERSIONS);
if (baseParam.getErrorModel().getMessages().size() > 0) {
return Response.status(Response.Status.BAD_REQUEST).entity(baseParam.getErrorModel()).build();
}
// Set up
this.dataCleanUtil.setLimit(baseParam.getLimit());
this.dataCleanUtil.setCount(0);
// Main process
logger.info(MessageFormat.format("User({0}) deleting versions for all spaces..", new Object[] {loggedInAppUser.getName() }));
long deleted = this.dataCleanUtil.removeAllVersions(baseParam.getEndDays(), baseParam.getType());
ResponseModel responseModel = new ResponseModel(
baseParam.getType(),
baseParam.getEndDays(),
baseParam.getLimit(),
this.dataCleanUtil.getCount(),
this.dataCleanUtil.getCount(),
deleted,
new MessageModel("Deleted Versions Count - " + deleted));
return Response.ok(responseModel).build();
}
@GET
@Produces({MediaType.APPLICATION_JSON})
@Path("/versions/space/{spaceKey}")
@AnonymousAllowed
public Response getSpaceVersionsBySpaceKey(@QueryParam("type") String type, @QueryParam("endDays") String endDaysStr, @QueryParam("limit") String limitStr, @PathParam("spaceKey") String spaceKey) {
// Authentication
if (StringUtils.isEmpty(spaceKey)) {
return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorModel("400 Bad Request", "Required fields are missing. : spaceKey")).build();
}
Space space = this.spaceManager.getSpace(spaceKey);
if (space == null) {
return Response.status(Response.Status.NOT_FOUND).entity(new ErrorModel("404 Not Found", "Space is not exists!")).build();
}
ConfluenceUser loggedInAppUser = AuthenticatedUserThreadLocal.get();
if (!this.permissionManager.hasPermission(loggedInAppUser, Permission.VIEW, space)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(new ErrorModel("401 Unauthorized", "View Permission denied!")).build();
}
// Validate Params
VersionBaseParam baseParam = new VersionBaseParam(type, endDaysStr, limitStr, MAX_LIMIT_FOR_VERSIONS);
if (baseParam.getErrorModel().getMessages().size() > 0) {
return Response.status(Response.Status.BAD_REQUEST).entity(baseParam.getErrorModel()).build();
}
// Set up
this.dataCleanUtil.setLimit(baseParam.getLimit());
this.dataCleanUtil.setCount(0);
// Main process
SpaceVersionsModel spaceVersionModel = this.dataCleanUtil.getSpaceVersionSummary(space, baseParam.getEndDays(), baseParam.getType());
ResponseModel responseModel = new ResponseModel(
baseParam.getType(),
baseParam.getEndDays(),
baseParam.getLimit(),
this.dataCleanUtil.getCount(),
NOT_DELETED,
NOT_DELETED,
spaceVersionModel);
return Response.ok(responseModel).build();
}
@DELETE
@Produces({MediaType.APPLICATION_JSON})
@Path("/versions/space/{spaceKey}")
@AnonymousAllowed
public Response deleteSpaceVersionsBySpaceKey(@QueryParam("type") String type, @QueryParam("endDays") String endDaysStr, @QueryParam("limit") String limitStr, @PathParam("spaceKey") String spaceKey) {
// Authentication
if (StringUtils.isEmpty(spaceKey)) {
return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorModel("400 Bad Request", "Required fields are missing. : spaceKey")).build();
}
Space space = this.spaceManager.getSpace(spaceKey);
if (space == null) {
return Response.status(Response.Status.NOT_FOUND).entity(new ErrorModel("404 Not Found", "Space is not exists!")).build();
}
ConfluenceUser loggedInAppUser = AuthenticatedUserThreadLocal.get();
if (!this.permissionManager.hasPermission(loggedInAppUser, Permission.ADMINISTER, space)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(new ErrorModel("401 Unauthorized", "Admin Permission denied!")).build();
}
// Validate Params
VersionBaseParam baseParam = new VersionBaseParam(type, endDaysStr, limitStr, MAX_LIMIT_FOR_VERSIONS);
if (baseParam.getErrorModel().getMessages().size() > 0) {
return Response.status(Response.Status.BAD_REQUEST).entity(baseParam.getErrorModel()).build();
}
// Set up
this.dataCleanUtil.setLimit(baseParam.getLimit());
this.dataCleanUtil.setCount(0);
// Main process
logger.info(MessageFormat.format("User({0}) deleting versions for spaceKey {1}", new Object[] {loggedInAppUser.getName(), spaceKey }));
long deleted = this.dataCleanUtil.removeSpaceVersions(space, baseParam.getEndDays(), baseParam.getType());
ResponseModel responseModel = new ResponseModel(
baseParam.getType(),
baseParam.getEndDays(),
baseParam.getLimit(),
this.dataCleanUtil.getCount(),
this.dataCleanUtil.getCount(),
deleted,
new MessageModel("Deleted Versions Count - " + deleted));
return Response.ok(responseModel).build();
}
@GET
@Produces({MediaType.APPLICATION_JSON})
@Path("/versions/page/{pageId}")
@AnonymousAllowed
public Response getPageVersionsByPageId(@QueryParam("type") String type, @QueryParam("endDays") String endDaysStr, @QueryParam("limit") String limitStr, @PathParam("pageId") long pageId) {
// Authentication
if (pageId <= 0L) {
return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorModel("400 Bad Request", "Required fields are missing. : spaceKey")).build();
}
Page page = this.pageManager.getPage(pageId);
if (page == null) {
return Response.status(Response.Status.NOT_FOUND).entity(new ErrorModel("404 Not Found", "Space is not exists!")).build();
}
ConfluenceUser loggedInAppUser = AuthenticatedUserThreadLocal.get();
if (!this.permissionManager.hasPermission(loggedInAppUser, Permission.VIEW, page)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(new ErrorModel("401 Unauthorized", "View Permission denied!")).build();
}
// Validate Params
VersionBaseParam baseParam = new VersionBaseParam(type, endDaysStr, limitStr, MAX_LIMIT_FOR_VERSIONS);
if (baseParam.getErrorModel().getMessages().size() > 0) {
return Response.status(Response.Status.BAD_REQUEST).entity(baseParam.getErrorModel()).build();
}
// Set up
this.dataCleanUtil.setLimit(baseParam.getLimit());
this.dataCleanUtil.setCount(0);
// Main process
PageVersionsModel pageVersionsModel = this.dataCleanUtil.getPageVersionSummary(page, baseParam.getEndDays(), baseParam.getType());
ResponseModel responseModel = new ResponseModel(
baseParam.getType(),
baseParam.getEndDays(),
baseParam.getLimit(),
this.dataCleanUtil.getCount(),
NOT_DELETED,
NOT_DELETED,
pageVersionsModel);
return Response.ok(responseModel).build();
}
@DELETE
@Produces({MediaType.APPLICATION_JSON})
@Path("/versions/page/{pageId}")
@AnonymousAllowed
public Response deletePageVersionsByPageId(@QueryParam("type") String type, @QueryParam("endDays") String endDaysStr, @QueryParam("limit") String limitStr, @PathParam("pageId") long pageId) {
// Authentication
if (pageId <= 0L) {
return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorModel("400 Bad Request", "Required fields are missing. : spaceKey")).build();
}
Page page = this.pageManager.getPage(pageId);
if (page == null) {
return Response.status(Response.Status.NOT_FOUND).entity(new ErrorModel("404 Not Found", "Space is not exists!")).build();
}
ConfluenceUser loggedInAppUser = AuthenticatedUserThreadLocal.get();
if (!this.permissionManager.hasPermission(loggedInAppUser, Permission.ADMINISTER, page)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(new ErrorModel("401 Unauthorized", "Admin Permission denied!")).build();
}
// Validate Params
VersionBaseParam baseParam = new VersionBaseParam(type, endDaysStr, limitStr, MAX_LIMIT_FOR_VERSIONS);
if (baseParam.getErrorModel().getMessages().size() > 0) {
return Response.status(Response.Status.BAD_REQUEST).entity(baseParam.getErrorModel()).build();
}
// Set up
this.dataCleanUtil.setLimit(baseParam.getLimit());
this.dataCleanUtil.setCount(0);
// Main process
logger.info(MessageFormat.format("User({0}) deleting page versions for pageId {1}", new Object[] {loggedInAppUser.getName(), Long.valueOf(pageId) }));
long deleted = this.dataCleanUtil.removePageVersions(page, baseParam.getEndDays(), baseParam.getType());
ResponseModel responseModel = new ResponseModel(
baseParam.getType(),
baseParam.getEndDays(),
baseParam.getLimit(),
this.dataCleanUtil.getCount(),
this.dataCleanUtil.getCount(),
deleted,
new MessageModel("Deleted Versions Count - " + deleted));
return Response.ok(responseModel).build();
}
@GET
@Produces({MediaType.APPLICATION_JSON})
@Path("/trash/all")
@AnonymousAllowed
public Response getAllGarbages(@QueryParam("limit") String limitStr) {
// Authentication
ConfluenceUser loggedInAppUser = AuthenticatedUserThreadLocal.get();
if (!this.permissionManager.isConfluenceAdministrator(loggedInAppUser)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(new ErrorModel("401 Unauthorized", "Confluence Administrator Permission required!")).build();
}
// Validate Params
TrashBaseParam baseParam = new TrashBaseParam(ITEM_TYPE_FOR_SPACE_TRASH, END_DAYS_FOR_SPACE_TRASH, limitStr, MAX_LIMIT_FOR_TRASH);
if (baseParam.getErrorModel().getMessages().size() > 0) {
return Response.status(Response.Status.BAD_REQUEST).entity(baseParam.getErrorModel()).build();
}
// Set up
this.dataCleanUtil.setLimit(baseParam.getLimit());
this.dataCleanUtil.setCount(0);
// Main process
List<SpaceTrashModel> trashModels = this.dataCleanUtil.getAllTrashSummary();
ResponseModel responseModel = new ResponseModel(
baseParam.getType(),
baseParam.getEndDays(),
baseParam.getLimit(),
this.dataCleanUtil.getCount(),
NOT_DELETED,
NOT_DELETED,
trashModels);
return Response.ok(responseModel).build();
}
@DELETE
@Produces({MediaType.APPLICATION_JSON})
@Path("/trash/all")
@AnonymousAllowed
public Response deleteAllGarbages(@QueryParam("limit") String limitStr) {
// Authentication
ConfluenceUser loggedInAppUser = AuthenticatedUserThreadLocal.get();
if (!this.permissionManager.isConfluenceAdministrator(loggedInAppUser)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(new ErrorModel("401 Unauthorized", "Confluence Administrator Permission required!")).build();
}
// Validate Params
TrashBaseParam baseParam = new TrashBaseParam(ITEM_TYPE_FOR_SPACE_TRASH, END_DAYS_FOR_SPACE_TRASH, limitStr, MAX_LIMIT_FOR_TRASH);
if (baseParam.getErrorModel().getMessages().size() > 0) {
return Response.status(Response.Status.BAD_REQUEST).entity(baseParam.getErrorModel()).build();
}
// Set up
this.dataCleanUtil.setLimit(baseParam.getLimit());
this.dataCleanUtil.setCount(0);
// Main process
logger.info(MessageFormat.format("User({0}) deleting space trash for all", new Object[] {loggedInAppUser.getName() }));
long deleted = this.dataCleanUtil.removeAllTrash();
ResponseModel responseModel = new ResponseModel(
baseParam.getType(),
baseParam.getEndDays(),
baseParam.getLimit(),
this.dataCleanUtil.getCount(),
this.dataCleanUtil.getCount(),
deleted,
new MessageModel("Deleted Trash Items Count - " + deleted));
return Response.ok(responseModel).build();
}
@GET
@Produces({MediaType.APPLICATION_JSON})
@Path("/trash/space/{spaceKey}")
@AnonymousAllowed
public Response getSpaceGarbagesBySpaceKey(@QueryParam("limit") String limitStr, @PathParam("spaceKey") String spaceKey) {
// Authentication
if (StringUtils.isEmpty(spaceKey)) {
return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorModel("400 Bad Request", "Required fields are missing. : spaceKey")).build();
}
Space space = this.spaceManager.getSpace(spaceKey);
if (space == null) {
return Response.status(Response.Status.NOT_FOUND).entity(new ErrorModel("404 Not Found", "Space is not exists!")).build();
}
ConfluenceUser loggedInAppUser = AuthenticatedUserThreadLocal.get();
if (!this.permissionManager.hasPermission(loggedInAppUser, Permission.VIEW, space)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(new ErrorModel("401 Unauthorized", "View Permission denied!")).build();
}
// Validate Params
TrashBaseParam baseParam = new TrashBaseParam(ITEM_TYPE_FOR_SPACE_TRASH, END_DAYS_FOR_SPACE_TRASH, limitStr, MAX_LIMIT_FOR_TRASH);
if (baseParam.getErrorModel().getMessages().size() > 0) {
return Response.status(Response.Status.BAD_REQUEST).entity(baseParam.getErrorModel()).build();
}
// Set up
this.dataCleanUtil.setLimit(baseParam.getLimit());
this.dataCleanUtil.setCount(0);
// Main process
SpaceTrashModel spaceTrashModel = this.dataCleanUtil.getSpaceTrashSummary(space);
ResponseModel responseModel = new ResponseModel(
baseParam.getType(),
baseParam.getEndDays(),
baseParam.getLimit(),
this.dataCleanUtil.getCount(),
NOT_DELETED,
NOT_DELETED,
spaceTrashModel);
return Response.ok(responseModel).build();
}
@DELETE
@Produces({MediaType.APPLICATION_JSON})
@Path("/trash/space/{spaceKey}")
@AnonymousAllowed
public Response deleteSpaceGarbagesBySpaceKey(@QueryParam("limit") String limitStr, @PathParam("spaceKey") String spaceKey) {
// Authentication
if (StringUtils.isEmpty(spaceKey)) {
return Response.status(Response.Status.BAD_REQUEST).entity(new ErrorModel("400 Bad Request", "Required fields are missing. : spaceKey")).build();
}
Space space = this.spaceManager.getSpace(spaceKey);
if (space == null) {
return Response.status(Response.Status.NOT_FOUND).entity(new ErrorModel("404 Not Found", "Space is not exists!")).build();
}
ConfluenceUser loggedInAppUser = AuthenticatedUserThreadLocal.get();
if (!this.permissionManager.hasPermission(loggedInAppUser, Permission.ADMINISTER, space)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(new ErrorModel("401 Unauthorized", "Admin Permission denied!")).build();
}
// Validate Params
TrashBaseParam baseParam = new TrashBaseParam(ITEM_TYPE_FOR_SPACE_TRASH, END_DAYS_FOR_SPACE_TRASH, limitStr, MAX_LIMIT_FOR_TRASH);
if (baseParam.getErrorModel().getMessages().size() > 0) {
return Response.status(Response.Status.BAD_REQUEST).entity(baseParam.getErrorModel()).build();
}
// Set up
this.dataCleanUtil.setLimit(baseParam.getLimit());
this.dataCleanUtil.setCount(0);
// Main process
logger.info(MessageFormat.format("User({0}) deleting space trash for spaceKey {1}", new Object[] {loggedInAppUser.getName(), Long.valueOf(spaceKey) }));
int deleted = 0;
deleted = this.dataCleanUtil.removeSpaceTrash(space);
ResponseModel responseModel = new ResponseModel(
baseParam.getType(),
baseParam.getEndDays(),
baseParam.getLimit(),
this.dataCleanUtil.getCount(),
this.dataCleanUtil.getCount(),
deleted,
new MessageModel("Deleted Trash Items Count - " + deleted));
return Response.ok(responseModel).build();
}
}

View File

@ -0,0 +1,35 @@
package su.tiburon.atlassian.confluence.rest;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import com.atlassian.crowd.embedded.api.DirectoryType;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class DirectoryModel {
@XmlElement
private Long id;
@XmlElement
private DirectoryType type;
@XmlElement
private Boolean issynchronising;
public DirectoryModel() {
this.id = null;
this.type = null;
this.issynchronising = false;
}
public DirectoryModel(Long id, DirectoryType type, Boolean issynchronising) {
this.id = id;
this.type = type;
this.issynchronising = issynchronising;
}
}

View File

@ -0,0 +1,80 @@
package su.tiburon.atlassian.confluence.rest;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.QueryParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.atlassian.confluence.security.PermissionManager;
import com.atlassian.confluence.user.AuthenticatedUserThreadLocal;
import com.atlassian.confluence.user.ConfluenceUser;
import com.atlassian.plugin.spring.scanner.annotation.imports.ConfluenceImport;
import com.atlassian.plugins.rest.common.security.AnonymousAllowed;
import com.atlassian.crowd.embedded.api.CrowdDirectoryService;
import com.atlassian.crowd.embedded.api.Directory;
@Path("/directory")
@AnonymousAllowed
@Produces(MediaType.APPLICATION_JSON)
public class DirectoryService {
private static final Logger logger = LoggerFactory.getLogger(DirectoryService.class);
@ConfluenceImport
private final PermissionManager permissionManager;
@ConfluenceImport
private final CrowdDirectoryService crowdDirectoryService;
@Inject
public DirectoryService(PermissionManager permissionManager, CrowdDirectoryService crowdDirectoryService) {
this.permissionManager = permissionManager;
this.crowdDirectoryService = crowdDirectoryService;
}
@GET
public Response getDir() {
// Authentication
ConfluenceUser loggedInAppUser = AuthenticatedUserThreadLocal.get();
if (!this.permissionManager.isConfluenceAdministrator(loggedInAppUser)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(new ErrorModel("401 Unauthorized", "Confluence Administrator Permission required!")).build();
}
logger.info(MessageFormat.format("User({0}) requesting infodmation about CUDs", new Object[] {loggedInAppUser.getName() }));
Collection<DirectoryModel> coll = new ArrayList<DirectoryModel>();
for (Directory dsa : crowdDirectoryService.findAllDirectories()) {
coll.add(new DirectoryModel(dsa.getId(),dsa.getType(),crowdDirectoryService.isDirectorySynchronising(dsa.getId())));
}
return Response.ok(coll).build();
}
@PUT
public Response syncDir(@QueryParam("id") Long dirId) {
// Authentication
ConfluenceUser loggedInAppUser = AuthenticatedUserThreadLocal.get();
if (!this.permissionManager.isConfluenceAdministrator(loggedInAppUser)) {
return Response.status(Response.Status.UNAUTHORIZED).entity(new ErrorModel("401 Unauthorized", "Confluence Administrator Permission required!")).build();
}
crowdDirectoryService.synchroniseDirectory(dirId, true);
Collection<DirectoryModel> coll = new ArrayList<DirectoryModel>();
for (Directory dsa : crowdDirectoryService.findAllDirectories()) {
coll.add(new DirectoryModel(dsa.getId(),dsa.getType(),crowdDirectoryService.isDirectorySynchronising(dsa.getId())));
}
return Response.ok(coll).build();
}
}

View File

@ -0,0 +1,52 @@
package su.tiburon.atlassian.confluence.rest;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ErrorModel {
@XmlElement(name = "statusCode")
private String statusCode;
@XmlElementWrapper
@XmlElement(name="message")
public List<MessageModel> messages;
public ErrorModel() {
this.statusCode = "";
this.messages = new ArrayList<MessageModel>();
}
public ErrorModel(String statusCode, String messages) {
this.statusCode = statusCode;
this.messages = new ArrayList<MessageModel>();
this.addMessage(messages);
}
public String getStatusCode() {
return statusCode;
}
public void setStatusCode(String statusCode) {
this.statusCode = statusCode;
}
public List<MessageModel> getMessages() {
return messages;
}
public void setMessages(List<MessageModel> messages) {
this.messages = messages;
}
public void addMessage(String message) {
this.messages.add(new MessageModel(message));
}
}

View File

@ -0,0 +1,29 @@
package su.tiburon.atlassian.confluence.rest;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class MessageModel {
@XmlElement(name = "message")
private String message;
public MessageModel() {
this.message = "";
}
public MessageModel(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -0,0 +1,109 @@
package su.tiburon.atlassian.confluence.rest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class PageVersionsModel {
@XmlElement
public String id;
@XmlElement
public String title;
@XmlElement
public long totalVersionCount;
@XmlElement
public int versionCount;
@XmlElement
public String lastModifier;
@XmlElement
public String lastModified;
@XmlElementWrapper
@XmlElement(name="attachment")
public List<AttachmentModel> attachments;
public PageVersionsModel() {
this.id = "";
this.title = "";
this.versionCount = -1;
this.totalVersionCount = -1;
this.lastModifier = "";
this.lastModified = "";
this.attachments = new ArrayList<AttachmentModel>();
}
public PageVersionsModel(Long id, String title, long totalVersionCount, int versionCount, String lastModifier, Date lastModified, List<AttachmentModel> attachments) {
this.id = String.valueOf(id);
this.title = title;
this.totalVersionCount = totalVersionCount;
this.versionCount = versionCount;
this.lastModifier = lastModifier;
this.lastModified = String.valueOf(lastModified);
this.attachments = attachments;
}
public String getId() {
return id;
}
public void setId(Long id) {
this.id = String.valueOf(id);
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getVersionCount() {
return versionCount;
}
public void setVersionCount(int versionCount) {
this.versionCount = versionCount;
}
public String getLastModifier() {
return lastModifier;
}
public void setLastModifier(String lastModifier) {
this.lastModifier = lastModifier;
}
public String getLastModified() {
return lastModified;
}
public void setLastModified(Date lastModified) {
this.lastModified = String.valueOf(lastModified);
}
public List<AttachmentModel> getAttachments() {
return attachments;
}
public void setAttachments(List<AttachmentModel> attachments) {
this.attachments = attachments;
}
public long getTotalVersionCount() {
return this.totalVersionCount;
}
public void setTotalVersionCount(long totalVersionCount) {
this.totalVersionCount = totalVersionCount;
}
}

View File

@ -0,0 +1,103 @@
package su.tiburon.atlassian.confluence.rest;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class ResponseModel {
@XmlElement
public String itemType;
@XmlElement
public String endDays;
@XmlElement
public int itemCountLimit;
@XmlElement
public int targetItemCount;
@XmlElement
public long deletedItemCount;
@XmlElement
public long deletedVersionCount;
@XmlElement
public Object result;
public ResponseModel(String itemType, int endDays, int itemCountLimit, int targetItemCount, long deletedItemCount, long deletedVersionCount, Object result) {
this.itemType = itemType;
this.endDays = String.valueOf(endDays);
this.itemCountLimit = itemCountLimit;
this.targetItemCount = targetItemCount;
this.deletedItemCount = deletedItemCount;
this.deletedVersionCount = deletedVersionCount;
this.result = result;
}
public ResponseModel(String itemType, String endDaysStr, int itemCountLimit, int targetItemCount, long deletedItemCount, long deletedVersionCount, Object result) {
this.itemType = itemType;
this.endDays = endDaysStr;
this.itemCountLimit = itemCountLimit;
this.targetItemCount = targetItemCount;
this.deletedItemCount = deletedItemCount;
this.deletedVersionCount = deletedVersionCount;
this.result = result;
}
public String getItemType() {
return itemType;
}
public void setItemType(String itemType) {
this.itemType = itemType;
}
public String getEndDays() {
return endDays;
}
public void setEndDays(String endDays) {
this.endDays = endDays;
}
public int getItemCountLimit() {
return itemCountLimit;
}
public void setItemCountLimit(int itemCountLimit) {
this.itemCountLimit = itemCountLimit;
}
public long getTargetItemCount() {
return targetItemCount;
}
public void setTargetItemCount(int targetItemCount) {
this.targetItemCount = targetItemCount;
}
public long getDeletedItemCount() {
return deletedItemCount;
}
public void setDeletedItemCount(long deletedItemCount) {
this.deletedItemCount = deletedItemCount;
}
public long getDeletedVersionCount() {
return deletedVersionCount;
}
public void setDeletedVersionCount(long deletedVersionCount) {
this.deletedVersionCount = deletedVersionCount;
}
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
}

View File

@ -0,0 +1,53 @@
package su.tiburon.atlassian.confluence.rest;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class SpaceTrashModel {
@XmlElement
public String spaceKey;
@XmlElement
public String title;
@XmlElement
public int numberOfItemsInTrash;
public SpaceTrashModel() {
this.spaceKey = "";
this.title = "";
this.numberOfItemsInTrash = 0;
}
public SpaceTrashModel(String spaceKey, String title, int numberOfItemsInTrash) {
this.spaceKey = spaceKey;
this.title = title;
this.numberOfItemsInTrash = numberOfItemsInTrash;
}
public String getSpaceKey() {
return spaceKey;
}
public void setSpaceKey(String spaceKey) {
this.spaceKey = spaceKey;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getNumberOfItemsInTrash() {
return numberOfItemsInTrash;
}
public void setNumberOfItemsInTrash(int numberOfItemsInTrash) {
this.numberOfItemsInTrash = numberOfItemsInTrash;
}
}

View File

@ -0,0 +1,70 @@
package su.tiburon.atlassian.confluence.rest;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class SpaceVersionsModel {
@XmlElement
public String spaceKey;
@XmlElement
public String title;
@XmlElement
public long totalVersionCount;
@XmlElementWrapper
@XmlElement(name="page")
public List<PageVersionsModel> pages;
public SpaceVersionsModel() {
this.spaceKey = "";
this.title = "";
this.totalVersionCount = -1;
this.pages = new ArrayList<PageVersionsModel>();
}
public SpaceVersionsModel(String spaceKey, String title, long totalVersionCount, List<PageVersionsModel> pages) {
this.spaceKey = spaceKey;
this.title = title;
this.totalVersionCount = totalVersionCount;
this.pages = pages;
}
public String getSpaceKey() {
return spaceKey;
}
public void setSpaceKey(String spaceKey) {
this.spaceKey = spaceKey;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public long getTotalVersionCount() {
return totalVersionCount;
}
public void setTotalVersionCount(long totalVersionCount) {
this.totalVersionCount = totalVersionCount;
}
public List<PageVersionsModel> getPages() {
return pages;
}
public void setPages(List<PageVersionsModel> pages) {
this.pages = pages;
}
}

View File

@ -0,0 +1,71 @@
package su.tiburon.atlassian.confluence.rest;
import org.springframework.util.StringUtils;
public class TrashBaseParam {
private String type;
private String endDays;
private int limit;
private ErrorModel errorModel;
public TrashBaseParam(String type, String endDaysStr, String limitStr, int maxLimit) {
this.errorModel = new ErrorModel();
this.type = type;
this.endDays = endDaysStr;
validateLimit(limitStr, maxLimit);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getEndDays() {
return endDays;
}
public void setEndDays(String endDays) {
this.endDays = endDays;
}
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public ErrorModel getErrorModel() {
return errorModel;
}
private void validateLimit(String limitStr, int maxLimit) {
if(StringUtils.isEmpty(limitStr)) {
limitStr = String.valueOf(maxLimit);
}
try {
this.limit = Integer.parseInt(limitStr);
if (limit < 1 || limit > maxLimit) {
this.errorModel.setStatusCode("400 Bad Request");
this.errorModel.addMessage("limit is invalid. : limit=1" + String.valueOf(maxLimit));
}
} catch (NumberFormatException e) {
this.errorModel.setStatusCode("400 Bad Request");
this.errorModel.addMessage("limit is invalid. : limit=1" + String.valueOf(maxLimit));
}
}
}

View File

@ -0,0 +1,99 @@
package su.tiburon.atlassian.confluence.rest;
import org.springframework.util.StringUtils;
public class VersionBaseParam {
private String type;
private int endDays;
private int limit;
private ErrorModel errorModel;
public VersionBaseParam(String type, String endDaysStr, String limitStr, int maxLimit) {
this.errorModel = new ErrorModel();
validateType(type);
validateEndDays(endDaysStr);
validateLimit(limitStr, maxLimit);
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getEndDays() {
return endDays;
}
public void setEndDays(int endDays) {
this.endDays = endDays;
}
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public ErrorModel getErrorModel() {
return errorModel;
}
private void validateType(String type) {
if(StringUtils.isEmpty(type)) {
type = "all";
}
if ("all".equals(type) || "page".equals(type) || "attachment".equals(type)) {
this.type = type;
} else {
this.errorModel.setStatusCode("400 Bad Request");
this.errorModel.addMessage("type is invalid. : type=all or type=page or type=attachment");
}
}
private void validateEndDays(String endDaysStr) {
if(StringUtils.isEmpty(endDaysStr)) {
endDaysStr = "0";
}
try {
this.endDays = Integer.parseInt(endDaysStr);
if (endDays < 0 ) {
this.errorModel.setStatusCode("400 Bad Request");
this.errorModel.addMessage("endDays is invalid. : endDays=0 ");
}
} catch (NumberFormatException e) {
this.errorModel.setStatusCode("400 Bad Request");
this.errorModel.addMessage("endDays is invalid. : endDays=0 ");
}
}
private void validateLimit(String limitStr, int maxLimit) {
if(StringUtils.isEmpty(limitStr)) {
limitStr = String.valueOf(maxLimit);
}
try {
this.limit = Integer.parseInt(limitStr);
if (limit < 1 || limit > maxLimit) {
this.errorModel.setStatusCode("400 Bad Request");
this.errorModel.addMessage("limit is invalid. : limit=1" + String.valueOf(maxLimit));
}
} catch (NumberFormatException e) {
this.errorModel.setStatusCode("400 Bad Request");
this.errorModel.addMessage("limit is invalid. : limit=1" + String.valueOf(maxLimit));
}
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:atlassian-scanner="http://www.atlassian.com/schema/atlassian-scanner/2"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.atlassian.com/schema/atlassian-scanner/2
http://www.atlassian.com/schema/atlassian-scanner/2/atlassian-scanner.xsd">
<atlassian-scanner:scan-indexes/>
</beans>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<atlassian-plugin key="${atlassian.plugin.key}" name="${project.name}" plugins-version="2">
<plugin-info>
<description>${project.description}</description>
<version>${project.version}</version>
<vendor name="${project.organization.name}" url="${project.organization.url}"/>
<param name="plugin-icon">images/logo_octo_375_293.png</param>
<param name="plugin-logo">images/logo_octo_375_293.png</param>
</plugin-info>
<!-- add our i18n resource -->
<resource type="i18n" name="i18n" location="rest-extender"/>
<!-- add our web resources -->
<web-resource key="rest-extender-web-resources" name="Rest Extender Web Resources">
<dependency>com.atlassian.auiplugin:ajs</dependency>
<resource type="download" name="rest-extender.css" location="/css/rest-extender.css"/>
<resource type="download" name="rest-extender.js" location="/js/rest-extender.js"/>
<resource type="download" name="images/" location="/images"/>
<context>rest-extender</context>
</web-resource>
<rest name="Rest Extender" i18n-name-key="rest-extender.name" key="rest-extender" path="/extender" version="1">
<description key="rest-extender.description">Rest Extender Plugin</description>
</rest>
</atlassian-plugin>

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

View File

@ -0,0 +1,3 @@
#put any key/value pairs here
rest-extender.name=REST Extender
rest-extender.description=Confluence REST API extender