feat: add last edit information to application (#6948)

Adds the last edit time and editor username to the application when there is a change in the application.
This commit is contained in:
Nayan 2021-09-06 16:17:02 +06:00 committed by GitHub
parent 7a0ec72304
commit c4a7c1fb01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 63 additions and 19 deletions

View File

@ -70,6 +70,18 @@ public class Application extends BaseDomain {
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
Instant lastDeployedAt; // when this application was last deployed
/**
* This method has been added because the updatedAt property in base domain has @JsonIgnore annotation
* @return updated time as a string
*/
@JsonProperty(value = "modifiedAt", access = JsonProperty.Access.READ_ONLY)
public String getLastUpdateTime() {
if(updatedAt != null) {
return ISO_FORMATTER.format(updatedAt);
}
return null;
}
public String getLastDeployedAt() {
if(lastDeployedAt != null) {
return ISO_FORMATTER.format(lastDeployedAt);

View File

@ -25,6 +25,7 @@ import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.Instant;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@ -122,6 +123,8 @@ public abstract class BaseAppsmithRepositoryImpl<T extends BaseDomain> {
// Set policies to null in the update object
resource.setPolicies(null);
resource.setUpdatedAt(Instant.now());
resource.setModifiedBy(user.getUsername());
DBObject update = getDbObject(resource);
Update updateObj = new Update();

View File

@ -1,7 +1,6 @@
package com.appsmith.server.repositories;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.Application;
import com.appsmith.server.domains.ApplicationPage;
import com.appsmith.server.domains.QApplication;

View File

@ -108,6 +108,7 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
final PageDTO savedPage = tuple.getT1();
final Application application = tuple.getT2();
return addPageToApplication(application, savedPage, false)
.then(applicationService.saveLastEditInformation(application.getId()))
.thenReturn(savedPage);
});
}
@ -309,7 +310,10 @@ public class ApplicationPageServiceImpl implements ApplicationPageService {
return newPageService.findById(pageId, MANAGE_PAGES)
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.ACTION_IS_NOT_AUTHORIZED, "Clone Page")))
.flatMap(page -> clonePageGivenApplicationId(pageId, page.getApplicationId(), " Copy"));
.flatMap(page ->
applicationService.saveLastEditInformation(page.getApplicationId())
.then(clonePageGivenApplicationId(pageId, page.getApplicationId(), " Copy"))
);
}
private Mono<PageDTO> clonePageGivenApplicationId(String pageId, String applicationId,

View File

@ -31,4 +31,6 @@ public interface ApplicationService extends CrudService<Application, String> {
Flux<Application> findAllApplicationsByOrganizationId(String organizationId);
Mono<Application> getApplicationInViewMode(String applicationId);
Mono<Application> saveLastEditInformation(String applicationId);
}

View File

@ -35,6 +35,7 @@ import java.util.Set;
import static com.appsmith.server.acl.AclPermission.EXECUTE_DATASOURCES;
import static com.appsmith.server.acl.AclPermission.MAKE_PUBLIC_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.MANAGE_APPLICATIONS;
import static com.appsmith.server.acl.AclPermission.READ_APPLICATIONS;
@ -301,4 +302,18 @@ public class ApplicationServiceImpl extends BaseService<ApplicationRepository, A
});
}
/**
* Sets the updatedAt and modifiedBy fields of the Application
* @param applicationId Application ID
* @return Application Mono of updated Application
*/
@Override
public Mono<Application> saveLastEditInformation(String applicationId) {
Application application = new Application();
/*
We're not setting updatedAt and modifiedBy fields to the application DTO because these fields will be set
by the updateById method of the BaseAppsmithRepositoryImpl
*/
return repository.updateById(applicationId, application, MANAGE_APPLICATIONS); // it'll do a set operation
}
}

View File

@ -26,6 +26,7 @@ import com.appsmith.server.helpers.WidgetSpecificUtils;
import com.appsmith.server.solutions.PageLoadActionsUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.minidev.json.JSONObject;
import net.minidev.json.parser.JSONParser;
@ -56,6 +57,7 @@ import static java.util.stream.Collectors.toSet;
@Service
@Slf4j
@RequiredArgsConstructor
public class LayoutActionServiceImpl implements LayoutActionService {
private final ObjectMapper objectMapper;
@ -64,6 +66,7 @@ public class LayoutActionServiceImpl implements LayoutActionService {
private final NewActionService newActionService;
private final PageLoadActionsUtil pageLoadActionsUtil;
private final SessionUserService sessionUserService;
private final ApplicationService applicationService;
private JSONParser jsonParser = new JSONParser(JSONParser.MODE_PERMISSIVE);
@ -75,20 +78,6 @@ public class LayoutActionServiceImpl implements LayoutActionService {
private final String preWord = "\\b(";
private final String postWord = ")\\b";
public LayoutActionServiceImpl(ObjectMapper objectMapper,
AnalyticsService analyticsService,
NewPageService newPageService,
NewActionService newActionService,
PageLoadActionsUtil pageLoadActionsUtil,
SessionUserService sessionUserService) {
this.objectMapper = objectMapper;
this.analyticsService = analyticsService;
this.newPageService = newPageService;
this.newActionService = newActionService;
this.pageLoadActionsUtil = pageLoadActionsUtil;
this.sessionUserService = sessionUserService;
}
@Override
public Mono<ActionDTO> moveAction(ActionMoveDTO actionMoveDTO) {
ActionDTO action = actionMoveDTO.getAction();
@ -676,7 +665,8 @@ public class LayoutActionServiceImpl implements LayoutActionService {
}
}
page.setLayouts(layoutList);
return newPageService.saveUnpublishedPage(page);
return applicationService.saveLastEditInformation(page.getApplicationId())
.then(newPageService.saveUnpublishedPage(page));
})
.flatMap(page -> {
List<Layout> layoutList = page.getLayouts();

View File

@ -4,7 +4,6 @@ import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.Application;
import com.appsmith.server.domains.ApplicationPage;
import com.appsmith.server.domains.Collection;
import com.appsmith.server.domains.Layout;
import com.appsmith.server.domains.NewPage;
import com.appsmith.server.dtos.ApplicationPagesDTO;
@ -381,7 +380,8 @@ public class NewPageServiceImpl extends BaseService<NewPageRepository, NewPage,
copyNewFieldValuesIntoOldObject(page, dbPage.getUnpublishedPage());
return this.update(id, dbPage);
})
.flatMap(savedPage -> getPageByViewMode(savedPage, false));
.flatMap(savedPage -> applicationService.saveLastEditInformation(savedPage.getApplicationId())
.then(getPageByViewMode(savedPage, false)));
}
@Override

View File

@ -148,6 +148,7 @@ public class ImportExportApplicationService {
final String organizationId = application.getOrganizationId();
application.setOrganizationId(null);
application.setPages(null);
application.setModifiedBy(null);
examplesOrganizationCloner.makePristine(application);
applicationJson.setExportedApplication(application);
return newPageRepository.findByApplicationId(applicationId, AclPermission.MANAGE_PAGES)

View File

@ -1238,4 +1238,22 @@ public class ApplicationServiceTest {
.verifyComplete();
}
@WithUserDetails("api_user")
@Test
public void saveLastEditInformation_WhenUserHasPermission_Updated() {
Application testApplication = new Application();
testApplication.setName("SaveLastEditInformation TestApp");
testApplication.setModifiedBy("test-user");
Mono<Application> updatedApplication = applicationPageService.createApplication(testApplication, orgId)
.flatMap(application ->
applicationService.saveLastEditInformation(application.getId())
);
StepVerifier.create(updatedApplication).assertNext(application -> {
assertThat(application.getLastUpdateTime()).isNotNull();
assertThat(application.getPolicies()).isNotNull().isNotEmpty();
assertThat(application.getModifiedBy()).isEqualTo("api_user");
}).verifyComplete();
}
}