method level security for dataservice
This commit is contained in:
parent
864874e5b2
commit
2404d017b8
8 changed files with 131 additions and 40 deletions
|
@ -111,7 +111,8 @@ public class User implements UserDetails {
|
|||
public enum Role implements GrantedAuthority {
|
||||
ADMIN,
|
||||
USER,
|
||||
REPORTER;
|
||||
REPORTER,
|
||||
API;
|
||||
|
||||
@Override
|
||||
public String getAuthority() {
|
||||
|
|
40
src/main/java/com/faendir/acra/rest/RestApiInterface.java
Normal file
40
src/main/java/com/faendir/acra/rest/RestApiInterface.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* (C) Copyright 2018 Lukas Morawietz (https://github.com/F43nd1r)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.faendir.acra.rest;
|
||||
|
||||
import com.faendir.acra.service.DataService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author lukas
|
||||
* @since 23.08.18
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping(RestApiInterface.API_PATH)
|
||||
@PreAuthorize("hasRole(T(com.faendir.acra.model.User$Role).API)")
|
||||
public class RestApiInterface {
|
||||
public static final String API_PATH = "api";
|
||||
@NonNull private final DataService dataService;
|
||||
|
||||
@Autowired
|
||||
public RestApiInterface(@NonNull DataService dataService) {
|
||||
this.dataService = dataService;
|
||||
}
|
||||
}
|
|
@ -96,10 +96,10 @@ public class RestReportInterface {
|
|||
if (!app.isPresent()) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
BooleanExpression where = report.stacktrace.bug.app.eq(app.get());
|
||||
BooleanExpression where = null;
|
||||
String name = "";
|
||||
if (mail != null && !mail.isEmpty()) {
|
||||
where = where.and(report.userEmail.eq(mail));
|
||||
where = report.userEmail.eq(mail).and(where);
|
||||
name += "_" + mail;
|
||||
}
|
||||
if (id != null && !id.isEmpty()) {
|
||||
|
@ -111,6 +111,6 @@ public class RestReportInterface {
|
|||
}
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentDispositionFormData("attachment", "reports" + name + ".json");
|
||||
return ResponseEntity.ok().headers(headers).body(dataService.getFromReports(where, report.content, report.id).stream().collect(Collectors.joining(", ", "[", "]")));
|
||||
return ResponseEntity.ok().headers(headers).body(dataService.getFromReports(app.get(), where, report.content, report.id).stream().collect(Collectors.joining(", ", "[", "]")));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package com.faendir.acra.security;
|
||||
|
||||
import com.faendir.acra.model.User;
|
||||
import com.faendir.acra.rest.RestApiInterface;
|
||||
import com.faendir.acra.rest.RestReportInterface;
|
||||
import com.faendir.acra.service.UserService;
|
||||
import org.apache.commons.text.RandomStringGenerator;
|
||||
|
@ -54,7 +55,6 @@ import java.util.stream.Stream;
|
|||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
|
||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@NonNull private final UserService userService;
|
||||
|
||||
@Autowired
|
||||
|
@ -116,17 +116,22 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
|||
|
||||
@Override
|
||||
protected void configure(@NonNull HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.csrf().disable()
|
||||
.headers().disable()
|
||||
.anonymous().disable()
|
||||
.exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint())
|
||||
http.csrf()
|
||||
.disable()
|
||||
.headers()
|
||||
.disable()
|
||||
.anonymous()
|
||||
.disable()
|
||||
.exceptionHandling()
|
||||
.authenticationEntryPoint(new Http403ForbiddenEntryPoint())
|
||||
.and()
|
||||
.sessionManagement()
|
||||
.and()
|
||||
.antMatcher("/"+RestReportInterface.REPORT_PATH).httpBasic();
|
||||
// @formatter:on
|
||||
.antMatcher("/" + RestReportInterface.REPORT_PATH)
|
||||
.httpBasic()
|
||||
.and()
|
||||
.antMatcher("/" + RestApiInterface.API_PATH + "/**")
|
||||
.httpBasic();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
|
|
@ -56,6 +56,9 @@ import org.hibernate.Session;
|
|||
import org.json.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.security.access.prepost.PostAuthorize;
|
||||
import org.springframework.security.access.prepost.PostFilter;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
@ -118,6 +121,7 @@ public class DataService implements Serializable {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public QueryDslDataProvider<VBug> getBugProvider(@NonNull App app, BooleanSupplier onlyNonSolvedProvider) {
|
||||
Supplier<BooleanExpression> whereSupplier = () -> onlyNonSolvedProvider.getAsBoolean() ? bug.app.eq(app).and(bug.solved.eq(false)) : bug.app.eq(app);
|
||||
return new QueryDslDataProvider<>(() -> Queries.selectVBug(entityManager).where(whereSupplier.get()),
|
||||
|
@ -125,6 +129,7 @@ public class DataService implements Serializable {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#bug.app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public QueryDslDataProvider<Report> getReportProvider(@NonNull Bug bug) {
|
||||
return new QueryDslDataProvider<>(new JPAQuery<>(entityManager).from(report)
|
||||
.join(report.stacktrace, stacktrace1)
|
||||
|
@ -134,6 +139,7 @@ public class DataService implements Serializable {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public QueryDslDataProvider<Report> getReportProvider(@NonNull App app) {
|
||||
return new QueryDslDataProvider<>(new JPAQuery<>(entityManager).from(report)
|
||||
.join(report.stacktrace, stacktrace1)
|
||||
|
@ -144,6 +150,7 @@ public class DataService implements Serializable {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public QueryDslDataProvider<ProguardMapping> getMappingProvider(@NonNull App app) {
|
||||
return new QueryDslDataProvider<>(new JPAQuery<>(entityManager).from(proguardMapping).where(proguardMapping.app.eq(app)).select(proguardMapping));
|
||||
}
|
||||
|
@ -166,6 +173,7 @@ public class DataService implements Serializable {
|
|||
*/
|
||||
@Transactional
|
||||
@NonNull
|
||||
@PreAuthorize("hasRole(T(com.faendir.acra.model.User$Role).ADMIN)")
|
||||
public PlainTextUser createNewApp(@NonNull String name) {
|
||||
PlainTextUser user = userService.createReporterUser();
|
||||
store(new App(name, user));
|
||||
|
@ -174,6 +182,7 @@ public class DataService implements Serializable {
|
|||
|
||||
@Transactional
|
||||
@NonNull
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).ADMIN)")
|
||||
public PlainTextUser recreateReporterUser(@NonNull App app) {
|
||||
PlainTextUser user = userService.createReporterUser();
|
||||
app.setReporter(user);
|
||||
|
@ -181,23 +190,27 @@ public class DataService implements Serializable {
|
|||
return user;
|
||||
}
|
||||
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#bugs[0].app, T(com.faendir.acra.model.Permission$Level).EDIT)")
|
||||
public void mergeBugs(@NonNull @Size(min = 2) Collection<Bug> bugs, @NonNull String title) {
|
||||
bugMerger.mergeBugs(bugs, title);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#bug.app, T(com.faendir.acra.model.Permission$Level).EDIT)")
|
||||
public void unmergeBug(@NonNull Bug bug) {
|
||||
getStacktraces(bug).forEach(stacktrace -> stacktrace.setBug(new Bug(bug.getApp(), stacktrace.getStacktrace())));
|
||||
delete(bug);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#bug.app, T(com.faendir.acra.model.Permission$Level).EDIT)")
|
||||
public void setBugSolved(@NonNull Bug bug, boolean solved) {
|
||||
bug.setSolved(solved);
|
||||
store(bug);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public Optional<ProguardMapping> findMapping(@NonNull App app, int versionCode) {
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(proguardMapping)
|
||||
.where(proguardMapping.app.eq(app).and(proguardMapping.versionCode.eq(versionCode)))
|
||||
|
@ -206,6 +219,7 @@ public class DataService implements Serializable {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
@PostAuthorize("!returnObject.isPresent() || T(com.faendir.acra.security.SecurityUtils).hasPermission(returnObject.get().stacktrace.bug.app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public Optional<Report> findReport(@NonNull String id) {
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(report)
|
||||
.join(report.stacktrace, stacktrace1)
|
||||
|
@ -220,6 +234,7 @@ public class DataService implements Serializable {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
@PostAuthorize("!returnObject.isPresent() || T(com.faendir.acra.security.SecurityUtils).hasPermission(returnObject.get().app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public Optional<Bug> findBug(@NonNull String encodedId) {
|
||||
try {
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(bug).join(bug.app).fetchJoin().where(bug.id.eq(Integer.parseInt(encodedId))).select(bug).fetchOne());
|
||||
|
@ -229,6 +244,7 @@ public class DataService implements Serializable {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
@PostAuthorize("!returnObject.isPresent() || T(com.faendir.acra.security.SecurityUtils).hasPermission(returnObject.get(), T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public Optional<App> findApp(@NonNull String encodedId) {
|
||||
try {
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(app).where(app.id.eq(Integer.parseInt(encodedId))).select(app).fetchOne());
|
||||
|
@ -238,22 +254,26 @@ public class DataService implements Serializable {
|
|||
}
|
||||
|
||||
@NonNull
|
||||
@PostFilter("T(com.faendir.acra.security.SecurityUtils).hasPermission(filterObject, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public List<App> findAllApps() {
|
||||
return new JPAQuery<>(entityManager).from(app).select(app).fetch();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#report.stacktrace.bug.app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public List<Attachment> findAttachments(@NonNull Report report) {
|
||||
return new JPAQuery<>(entityManager).from(attachment).where(attachment.report.eq(report)).select(attachment).fetch();
|
||||
}
|
||||
|
||||
public Optional<Stacktrace> findStacktrace(@NonNull String stacktrace, int versionCode) {
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public Optional<Stacktrace> findStacktrace(@NonNull App app, @NonNull String stacktrace, int versionCode) {
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(stacktrace1)
|
||||
.where(stacktrace1.stacktrace.eq(stacktrace).and(stacktrace1.version.code.eq(versionCode)))
|
||||
.where(stacktrace1.stacktrace.eq(stacktrace).and(stacktrace1.version.code.eq(versionCode)).and(stacktrace1.bug.app.eq(app)))
|
||||
.select(stacktrace1)
|
||||
.fetchOne());
|
||||
}
|
||||
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
private Optional<Bug> findBug(@NonNull App app, @NonNull String stacktrace) {
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(stacktrace1)
|
||||
.join(stacktrace1.bug, bug)
|
||||
|
@ -263,11 +283,13 @@ public class DataService implements Serializable {
|
|||
}
|
||||
|
||||
@Transactional
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).EDIT)")
|
||||
public void changeConfiguration(@NonNull App app, @NonNull App.Configuration configuration) {
|
||||
bugMerger.changeConfiguration(app, configuration);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).EDIT)")
|
||||
public void deleteReportsOlderThanDays(@NonNull App app, @NonNull int days) {
|
||||
new JPADeleteClause(entityManager, report).where(report.stacktrace.bug.app.eq(app).and(report.date.before(ZonedDateTime.now().minus(days, ChronoUnit.DAYS))));
|
||||
entityManager.flush();
|
||||
|
@ -275,6 +297,7 @@ public class DataService implements Serializable {
|
|||
}
|
||||
|
||||
@Transactional
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).EDIT)")
|
||||
public void deleteReportsBeforeVersion(@NonNull App app, int versionCode) {
|
||||
new JPADeleteClause(entityManager, report).where(report.stacktrace.bug.app.eq(app).and(report.stacktrace.version.code.lt(versionCode)));
|
||||
entityManager.flush();
|
||||
|
@ -282,13 +305,14 @@ public class DataService implements Serializable {
|
|||
}
|
||||
|
||||
@Transactional
|
||||
@PreAuthorize("hasRole(T(com.faendir.acra.model.User$Role).REPORTER)")
|
||||
public void createNewReport(@NonNull String reporterUserName, @NonNull String content, @NonNull List<MultipartFile> attachments) {
|
||||
App app = new JPAQuery<>(entityManager).from(QApp.app).where(QApp.app.reporter.username.eq(reporterUserName)).select(QApp.app).fetchOne();
|
||||
if (app != null) {
|
||||
JSONObject jsonObject = new JSONObject(content);
|
||||
String trace = jsonObject.optString(ReportField.STACK_TRACE.name());
|
||||
Version version = getVersion(jsonObject);
|
||||
Stacktrace stacktrace = findStacktrace(trace, version.getCode()).orElseGet(() -> new Stacktrace(findBug(app, trace).orElseGet(() -> new Bug(app, trace)),
|
||||
Stacktrace stacktrace = findStacktrace(app, trace, version.getCode()).orElseGet(() -> new Stacktrace(findBug(app, trace).orElseGet(() -> new Bug(app, trace)),
|
||||
trace,
|
||||
version));
|
||||
Report report = store(new Report(stacktrace, content));
|
||||
|
@ -328,32 +352,48 @@ public class DataService implements Serializable {
|
|||
return new Version(versionCode, versionName);
|
||||
}
|
||||
|
||||
public <T> Map<T, Long> countReports(@NonNull Predicate where, @NonNull Expression<T> select) {
|
||||
List<Tuple> result = ((JPAQuery<?>) new JPAQuery<>(entityManager)).from(report).where(where).groupBy(select).select(select, report.id.count()).fetch();
|
||||
@NonNull
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public <T> Map<T, Long> countReports(@NonNull App app, @NonNull Predicate where, @NonNull Expression<T> select) {
|
||||
List<Tuple> result = ((JPAQuery<?>) new JPAQuery<>(entityManager)).from(report)
|
||||
.where(report.stacktrace.bug.app.eq(app).and(where))
|
||||
.groupBy(select)
|
||||
.select(select, report.id.count())
|
||||
.fetch();
|
||||
return result.stream().collect(Collectors.toMap(tuple -> tuple.get(select), tuple -> Optional.ofNullable(tuple.get(report.id.count())).orElse(0L)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public <T extends Comparable> List<T> getFromReports(@NonNull Predicate where, @NonNull ComparableExpressionBase<T> select) {
|
||||
return getFromReports(where, select, select);
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public <T extends Comparable> List<T> getFromReports(@NonNull App app, @NonNull Predicate where, @NonNull ComparableExpressionBase<T> select) {
|
||||
return getFromReports(app, where, select, select);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public <T> List<T> getFromReports(@NonNull Predicate where, @NonNull Expression<T> select, ComparableExpressionBase<?> order) {
|
||||
return ((JPAQuery<?>) new JPAQuery<>(entityManager)).from(report).where(where).select(select).distinct().orderBy(order.asc()).fetch();
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public <T> List<T> getFromReports(@NonNull App app, @NonNull Predicate where, @NonNull Expression<T> select, ComparableExpressionBase<?> order) {
|
||||
return ((JPAQuery<?>) new JPAQuery<>(entityManager)).from(report)
|
||||
.where(report.stacktrace.bug.app.eq(app).and(where))
|
||||
.select(select)
|
||||
.distinct()
|
||||
.orderBy(order.asc())
|
||||
.fetch();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#bug.app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public List<Stacktrace> getStacktraces(@NonNull Bug bug) {
|
||||
return new JPAQuery<>(entityManager).from(stacktrace1).where(stacktrace1.bug.eq(bug)).select(stacktrace1).fetch();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@PreAuthorize("T(com.faendir.acra.security.SecurityUtils).hasPermission(#app, T(com.faendir.acra.model.Permission$Level).VIEW)")
|
||||
public Optional<Integer> getMaximumMappingVersion(@NonNull App app) {
|
||||
return Optional.ofNullable(new JPAQuery<>(entityManager).from(proguardMapping).where(proguardMapping.app.eq(app)).select(proguardMapping.versionCode.max()).fetchOne());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@PreAuthorize("hasRole(T(com.faendir.acra.model.User$Role).ADMIN)")
|
||||
public ImportResult importFromAcraStorage(String host, int port, boolean ssl, String database) {
|
||||
HttpClient httpClient = new StdHttpClient.Builder().host(host).port(port).enableSSL(ssl).build();
|
||||
CouchDbConnector db = new StdCouchDbConnector(database, new StdCouchDbInstance(httpClient));
|
||||
|
|
|
@ -18,7 +18,6 @@ package com.faendir.acra.ui.view.app.tabs;
|
|||
|
||||
import com.faendir.acra.i18n.Messages;
|
||||
import com.faendir.acra.model.App;
|
||||
import com.faendir.acra.model.QReport;
|
||||
import com.faendir.acra.service.DataService;
|
||||
import com.faendir.acra.ui.navigation.NavigationManager;
|
||||
import com.faendir.acra.ui.view.base.statistics.Statistics;
|
||||
|
@ -49,7 +48,7 @@ public class StatisticsTab implements AppTab {
|
|||
|
||||
@Override
|
||||
public Component createContent(@NonNull App app, @NonNull NavigationManager navigationManager) {
|
||||
Panel root = new Panel(new Statistics(QReport.report.stacktrace.bug.app.eq(app), dataService, i18n));
|
||||
Panel root = new Panel(new Statistics(app, null, dataService, i18n));
|
||||
root.setSizeFull();
|
||||
root.addStyleNames(AcraTheme.NO_BACKGROUND, AcraTheme.NO_BORDER);
|
||||
return root;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
package com.faendir.acra.ui.view.base.statistics;
|
||||
|
||||
import com.faendir.acra.i18n.I18nCheckBox;
|
||||
import com.faendir.acra.model.App;
|
||||
import com.faendir.acra.service.DataService;
|
||||
import com.querydsl.core.types.Expression;
|
||||
import com.querydsl.core.types.dsl.BooleanExpression;
|
||||
|
@ -28,6 +29,7 @@ import com.vaadin.ui.CheckBox;
|
|||
import com.vaadin.ui.ComboBox;
|
||||
import com.vaadin.ui.Component;
|
||||
import com.vaadin.ui.ComponentContainer;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.vaadin.risto.stepper.IntStepper;
|
||||
import org.vaadin.spring.i18n.I18N;
|
||||
|
||||
|
@ -41,6 +43,7 @@ import java.util.function.Function;
|
|||
* @since 01.06.18
|
||||
*/
|
||||
class Property<F, C extends Component & HasValue<F>, T> {
|
||||
private final App app;
|
||||
private final DataService dataService;
|
||||
private final CheckBox checkBox;
|
||||
private final C filterComponent;
|
||||
|
@ -48,7 +51,8 @@ class Property<F, C extends Component & HasValue<F>, T> {
|
|||
private final Chart<T> chart;
|
||||
private final Expression<T> select;
|
||||
|
||||
private Property(C filterComponent, Function<F, BooleanExpression> filter, Chart<T> chart, DataService dataService, Expression<T> select, I18N i18n, String filterTextId) {
|
||||
private Property(App app, C filterComponent, Function<F, BooleanExpression> filter, Chart<T> chart, DataService dataService, Expression<T> select, I18N i18n, String filterTextId) {
|
||||
this.app = app;
|
||||
this.dataService = dataService;
|
||||
this.checkBox = new I18nCheckBox(i18n, filterTextId);
|
||||
this.filterComponent = filterComponent;
|
||||
|
@ -67,15 +71,15 @@ class Property<F, C extends Component & HasValue<F>, T> {
|
|||
chartLayout.addComponent(chart);
|
||||
}
|
||||
|
||||
BooleanExpression applyFilter(BooleanExpression expression) {
|
||||
BooleanExpression applyFilter(@Nullable BooleanExpression expression) {
|
||||
if (checkBox.getValue() && filterComponent.getValue() != null) {
|
||||
return expression.and(filter.apply(filterComponent.getValue()));
|
||||
return filter.apply(filterComponent.getValue()).and(expression);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
void update(BooleanExpression expression) {
|
||||
chart.setContent(dataService.countReports(expression, select));
|
||||
chart.setContent(dataService.countReports(app, expression, select));
|
||||
}
|
||||
|
||||
static class Factory {
|
||||
|
@ -87,17 +91,17 @@ class Property<F, C extends Component & HasValue<F>, T> {
|
|||
this.expression = expression;
|
||||
}
|
||||
|
||||
Property<?, ?, ?> createStringProperty(ComparableExpressionBase<String> stringExpression, I18N i18n, String filterTextId, String chartTitleId) {
|
||||
ComboBox<String> comboBox = new ComboBox<>(null, dataService.getFromReports(expression, stringExpression));
|
||||
Property<?, ?, ?> createStringProperty(App app, ComparableExpressionBase<String> stringExpression, I18N i18n, String filterTextId, String chartTitleId) {
|
||||
ComboBox<String> comboBox = new ComboBox<>(null, dataService.getFromReports(app, expression, stringExpression));
|
||||
comboBox.setEmptySelectionAllowed(false);
|
||||
return new Property<>(comboBox, stringExpression::eq, new PieChart(i18n, chartTitleId), dataService, stringExpression, i18n, filterTextId);
|
||||
return new Property<>(app, comboBox, stringExpression::eq, new PieChart(i18n, chartTitleId), dataService, stringExpression, i18n, filterTextId);
|
||||
}
|
||||
|
||||
Property<?, ?, ?> createAgeProperty(DateTimePath<ZonedDateTime> dateTimeExpression, I18N i18n, String filterTextId, String chartTitleId) {
|
||||
Property<?, ?, ?> createAgeProperty(App app, DateTimePath<ZonedDateTime> dateTimeExpression, I18N i18n, String filterTextId, String chartTitleId) {
|
||||
IntStepper stepper = new IntStepper();
|
||||
stepper.setValue(30);
|
||||
stepper.setMinValue(1);
|
||||
return new Property<>(stepper,
|
||||
return new Property<>(app, stepper,
|
||||
days -> dateTimeExpression.after(ZonedDateTime.now().minus(days, ChronoUnit.DAYS)),
|
||||
new TimeChart(i18n, chartTitleId),
|
||||
dataService,
|
||||
|
|
|
@ -19,6 +19,7 @@ package com.faendir.acra.ui.view.base.statistics;
|
|||
import com.faendir.acra.i18n.I18nButton;
|
||||
import com.faendir.acra.i18n.I18nPanel;
|
||||
import com.faendir.acra.i18n.Messages;
|
||||
import com.faendir.acra.model.App;
|
||||
import com.faendir.acra.model.QReport;
|
||||
import com.faendir.acra.service.DataService;
|
||||
import com.faendir.acra.ui.view.base.layout.FlexLayout;
|
||||
|
@ -29,6 +30,7 @@ import com.vaadin.ui.Composite;
|
|||
import com.vaadin.ui.GridLayout;
|
||||
import com.vaadin.ui.Panel;
|
||||
import com.vaadin.ui.themes.AcraTheme;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.vaadin.risto.stepper.IntStepper;
|
||||
import org.vaadin.spring.i18n.I18N;
|
||||
|
||||
|
@ -44,10 +46,10 @@ public class Statistics extends Composite {
|
|||
static final Color BLUE = new Color(0x197de1); //vaadin blue
|
||||
static final Color FOREGROUND_DARK = new Color(0xcacecf);
|
||||
static final Color FOREGROUND_LIGHT = new Color(0x464646);
|
||||
private final BooleanExpression baseExpression;
|
||||
@Nullable private final BooleanExpression baseExpression;
|
||||
private final List<Property<?, ?, ?>> properties;
|
||||
|
||||
public Statistics(BooleanExpression baseExpression, DataService dataService, I18N i18n) {
|
||||
public Statistics(App app, @Nullable BooleanExpression baseExpression, DataService dataService, I18N i18n) {
|
||||
this.baseExpression = baseExpression;
|
||||
properties = new ArrayList<>();
|
||||
GridLayout filterLayout = new GridLayout(2, 1);
|
||||
|
@ -61,11 +63,11 @@ public class Statistics extends Composite {
|
|||
dayStepper.setValue(30);
|
||||
dayStepper.setMinValue(1);
|
||||
Property.Factory factory = new Property.Factory(dataService, baseExpression);
|
||||
properties.add(factory.createAgeProperty(QReport.report.date, i18n, Messages.LAST_X_DAYS, Messages.REPORTS_OVER_TIME));
|
||||
properties.add(factory.createStringProperty(QReport.report.androidVersion, i18n, Messages.ANDROID_VERSION, Messages.REPORTS_PER_ANDROID_VERSION));
|
||||
properties.add(factory.createStringProperty(QReport.report.stacktrace.version.name, i18n, Messages.APP_VERSION, Messages.REPORTS_PER_APP_VERSION));
|
||||
properties.add(factory.createStringProperty(QReport.report.phoneModel, i18n, Messages.PHONE_MODEL, Messages.REPORTS_PER_PHONE_MODEL));
|
||||
properties.add(factory.createStringProperty(QReport.report.brand, i18n, Messages.PHONE_BRAND, Messages.REPORTS_PER_BRAND));
|
||||
properties.add(factory.createAgeProperty(app, QReport.report.date, i18n, Messages.LAST_X_DAYS, Messages.REPORTS_OVER_TIME));
|
||||
properties.add(factory.createStringProperty(app, QReport.report.androidVersion, i18n, Messages.ANDROID_VERSION, Messages.REPORTS_PER_ANDROID_VERSION));
|
||||
properties.add(factory.createStringProperty(app, QReport.report.stacktrace.version.name, i18n, Messages.APP_VERSION, Messages.REPORTS_PER_APP_VERSION));
|
||||
properties.add(factory.createStringProperty(app, QReport.report.phoneModel, i18n, Messages.PHONE_MODEL, Messages.REPORTS_PER_PHONE_MODEL));
|
||||
properties.add(factory.createStringProperty(app, QReport.report.brand, i18n, Messages.PHONE_BRAND, Messages.REPORTS_PER_BRAND));
|
||||
|
||||
Panel filterPanel = new I18nPanel(filterLayout, i18n, Messages.FILTER);
|
||||
filterPanel.addStyleName(AcraTheme.NO_BACKGROUND);
|
||||
|
|
Loading…
Reference in a new issue