fixes and server init
This commit is contained in:
parent
7ce1baafa5
commit
1da72a0f31
11 changed files with 168 additions and 79 deletions
|
@ -38,7 +38,7 @@ The SEB Server Setup repository contains predefined, docker-based installation d
|
|||
Install SEB Server
|
||||
------------------
|
||||
|
||||
For a complete guide to install SEB Server please go to `SEB Server Installation Guide <https://seb-server-setup.readthedocs.io/en/latest/#>`_
|
||||
For a complete guide to install SEB Server please go to `SEB Server Installation Guide <https://seb-server-setup.readthedocs.io/en/latest/overview.html>`_
|
||||
|
||||
Getting started with SEB Server
|
||||
-------------------------------
|
||||
|
|
31
src/main/java/ch/ethz/seb/sebserver/gui/GuiInit.java
Normal file
31
src/main/java/ch/ethz/seb/sebserver/gui/GuiInit.java
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class GuiInit implements ApplicationListener<ApplicationReadyEvent> {
|
||||
|
||||
static final Logger INIT_LOGGER = LoggerFactory.getLogger("SEB SERVER INIT");
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(final ApplicationReadyEvent event) {
|
||||
INIT_LOGGER.info("----> SEB Server GUI Component sucessfully initialized!");
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -51,7 +51,7 @@ class AdminUserInitializer {
|
|||
@Qualifier(WebSecurityConfig.USER_PASSWORD_ENCODER_BEAN_NAME) final PasswordEncoder passwordEncoder,
|
||||
@Value("${sebserver.init.adminaccount.gen-on-init:false}") final boolean initializeAdmin,
|
||||
@Value("${sebserver.init.adminaccount.username:seb-server-admin}") final String adminName,
|
||||
@Value("${sebserver.init.organisation.name:ETHZ}") final String orgName) {
|
||||
@Value("${sebserver.init.organisation.name:[SET_ORGANIZATION_NAME]}") final String orgName) {
|
||||
|
||||
this.userDAO = userDAO;
|
||||
this.institutionDAO = institutionDAO;
|
||||
|
@ -67,72 +67,78 @@ class AdminUserInitializer {
|
|||
return;
|
||||
}
|
||||
|
||||
log.debug("Create initial admin account is switched on. Check database if exists...");
|
||||
final Result<SEBServerUser> byUsername = this.userDAO.sebServerUserByUsername(this.adminName);
|
||||
if (byUsername.hasValue()) {
|
||||
try {
|
||||
|
||||
log.debug("Initial admin account already exists. Check if the password must be reset...");
|
||||
log.debug("Create initial admin account is switched on. Check database if exists...");
|
||||
final Result<SEBServerUser> byUsername = this.userDAO.sebServerUserByUsername(this.adminName);
|
||||
if (byUsername.hasValue()) {
|
||||
|
||||
final SEBServerUser sebServerUser = byUsername.get();
|
||||
final String password = sebServerUser.getPassword();
|
||||
if (this.passwordEncoder.matches("admin", password)) {
|
||||
log.debug("Initial admin account already exists. Check if the password must be reset...");
|
||||
|
||||
log.debug("Setting new generated password for already existing admin account");
|
||||
final SEBServerUser sebServerUser = byUsername.get();
|
||||
final String password = sebServerUser.getPassword();
|
||||
if (this.passwordEncoder.matches("admin", password)) {
|
||||
|
||||
log.debug("Setting new generated password for already existing admin account");
|
||||
final CharSequence generateAdminPassword = this.generateAdminPassword();
|
||||
if (generateAdminPassword != null) {
|
||||
this.userDAO.changePassword(
|
||||
sebServerUser.getUserInfo().getModelId(),
|
||||
generateAdminPassword);
|
||||
this.writeAdminCredentials(this.adminName, generateAdminPassword);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final CharSequence generateAdminPassword = this.generateAdminPassword();
|
||||
if (generateAdminPassword != null) {
|
||||
this.userDAO.changePassword(
|
||||
sebServerUser.getUserInfo().getModelId(),
|
||||
generateAdminPassword);
|
||||
this.writeAdminCredentials(this.adminName, generateAdminPassword);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
final CharSequence generateAdminPassword = this.generateAdminPassword();
|
||||
if (generateAdminPassword != null) {
|
||||
|
||||
Long institutionId = this.institutionDAO.allMatching(new FilterMap())
|
||||
.getOrElse(() -> Collections.emptyList())
|
||||
.stream()
|
||||
.findFirst()
|
||||
.filter(Institution::isActive)
|
||||
.map(Institution::getInstitutionId)
|
||||
.orElseGet(() -> -1L);
|
||||
|
||||
if (institutionId < 0) {
|
||||
|
||||
log.debug("Create new initial institution");
|
||||
institutionId = this.institutionDAO.createNew(new Institution(
|
||||
null,
|
||||
this.orgName,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
true))
|
||||
.map(inst -> this.institutionDAO.setActive(inst, true).getOrThrow())
|
||||
Long institutionId = this.institutionDAO.allMatching(new FilterMap())
|
||||
.getOrElse(() -> Collections.emptyList())
|
||||
.stream()
|
||||
.findFirst()
|
||||
.filter(Institution::isActive)
|
||||
.map(Institution::getInstitutionId)
|
||||
.orElseGet(() -> -1L);
|
||||
|
||||
if (institutionId < 0) {
|
||||
|
||||
log.debug("Create new initial institution");
|
||||
institutionId = this.institutionDAO.createNew(new Institution(
|
||||
null,
|
||||
this.orgName,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
true))
|
||||
.map(inst -> this.institutionDAO.setActive(inst, true).getOrThrow())
|
||||
.map(Institution::getInstitutionId)
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
this.userDAO.createNew(new UserMod(
|
||||
this.adminName,
|
||||
institutionId,
|
||||
this.adminName,
|
||||
this.adminName,
|
||||
generateAdminPassword,
|
||||
generateAdminPassword,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new HashSet<>(Arrays.asList(UserRole.SEB_SERVER_ADMIN.name()))))
|
||||
.flatMap(account -> this.userDAO.setActive(account, true))
|
||||
.map(account -> {
|
||||
writeAdminCredentials(this.adminName, generateAdminPassword);
|
||||
return account;
|
||||
})
|
||||
.getOrThrow();
|
||||
}
|
||||
|
||||
this.userDAO.createNew(new UserMod(
|
||||
this.adminName,
|
||||
institutionId,
|
||||
this.adminName,
|
||||
this.adminName,
|
||||
generateAdminPassword,
|
||||
generateAdminPassword,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
new HashSet<>(Arrays.asList(UserRole.SEB_SERVER_ADMIN.name()))))
|
||||
.flatMap(account -> this.userDAO.setActive(account, true))
|
||||
.map(account -> {
|
||||
writeAdminCredentials(this.adminName, generateAdminPassword);
|
||||
return account;
|
||||
})
|
||||
.getOrThrow();
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
WebserviceInit.INIT_LOGGER.error("---->");
|
||||
WebserviceInit.INIT_LOGGER.error("----> SEB Server initial admin-account creation failed: ", e);
|
||||
WebserviceInit.INIT_LOGGER.error("---->");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void writeAdminCredentials(final String name, final CharSequence pwd) {
|
||||
|
|
|
@ -33,6 +33,7 @@ public class WebserviceInfo {
|
|||
|
||||
private static final Logger log = LoggerFactory.getLogger(WebserviceInfo.class);
|
||||
|
||||
private static final String VERSION_KEY = "sebserver.version";
|
||||
private static final String WEB_SERVICE_TEST_PROPERTY = "sebserver.test.property";
|
||||
private static final String WEB_SERVICE_SERVER_NAME_KEY = "sebserver.webservice.http.server.name";
|
||||
private static final String WEB_SERVICE_HTTP_SCHEME_KEY = "sebserver.webservice.http.scheme";
|
||||
|
@ -43,6 +44,7 @@ public class WebserviceInfo {
|
|||
"sebserver.webservice.api.exam.endpoint.discovery";
|
||||
private static final String WEB_SERVICE_EXTERNAL_ADDRESS_ALIAS = "sebserver.webservice.lms.address.alias";
|
||||
|
||||
private final String sebServerVersion;
|
||||
private final String testProperty;
|
||||
private final String httpScheme;
|
||||
private final String hostAddress; // internal
|
||||
|
@ -57,6 +59,7 @@ public class WebserviceInfo {
|
|||
private Map<String, String> externalAddressAlias;
|
||||
|
||||
public WebserviceInfo(final Environment environment) {
|
||||
this.sebServerVersion = environment.getRequiredProperty(VERSION_KEY);
|
||||
this.testProperty = environment.getProperty(WEB_SERVICE_TEST_PROPERTY, "NOT_AVAILABLE");
|
||||
this.httpScheme = environment.getRequiredProperty(WEB_SERVICE_HTTP_SCHEME_KEY);
|
||||
this.hostAddress = environment.getRequiredProperty(WEB_SERVICE_HOST_ADDRESS_KEY);
|
||||
|
@ -100,6 +103,10 @@ public class WebserviceInfo {
|
|||
}
|
||||
}
|
||||
|
||||
public String getSebServerVersion() {
|
||||
return this.sebServerVersion;
|
||||
}
|
||||
|
||||
public String getTestProperty() {
|
||||
return this.testProperty;
|
||||
}
|
||||
|
|
|
@ -58,21 +58,24 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
|||
INIT_LOGGER.info("---->");
|
||||
INIT_LOGGER.info("----> SEB Server successfully started up!");
|
||||
INIT_LOGGER.info("---->");
|
||||
INIT_LOGGER.info("----> Version: {}", this.webserviceInfo.getSebServerVersion());
|
||||
|
||||
try {
|
||||
INIT_LOGGER.info("----> config server address: {}", this.environment.getProperty("server.address"));
|
||||
INIT_LOGGER.info("----> config server port: {}", this.environment.getProperty("server.port"));
|
||||
|
||||
INIT_LOGGER.info("----> local host address: {}", InetAddress.getLocalHost().getHostAddress());
|
||||
INIT_LOGGER.info("----> local host name: {}", InetAddress.getLocalHost().getHostName());
|
||||
|
||||
INIT_LOGGER.info("----> remote host address: {}", InetAddress.getLoopbackAddress().getHostAddress());
|
||||
INIT_LOGGER.info("----> remote host name: {}", InetAddress.getLoopbackAddress().getHostName());
|
||||
INIT_LOGGER.info("----> Server address: {}", this.environment.getProperty("server.address"));
|
||||
INIT_LOGGER.info("----> Server port: {}", this.environment.getProperty("server.port"));
|
||||
INIT_LOGGER.info("---->");
|
||||
INIT_LOGGER.info("----> Local-Host address: {}", InetAddress.getLocalHost().getHostAddress());
|
||||
INIT_LOGGER.info("----> Local-Host name: {}", InetAddress.getLocalHost().getHostName());
|
||||
INIT_LOGGER.info("---->");
|
||||
INIT_LOGGER.info("----> Remote-Host address: {}", InetAddress.getLoopbackAddress().getHostAddress());
|
||||
INIT_LOGGER.info("----> Remote-Host name: {}", InetAddress.getLoopbackAddress().getHostName());
|
||||
} catch (final UnknownHostException e) {
|
||||
log.error("Unknown Host: ", e);
|
||||
}
|
||||
|
||||
INIT_LOGGER.info("----> {}", this.webserviceInfo);
|
||||
INIT_LOGGER.info("---->");
|
||||
INIT_LOGGER.info("----> HTTP Scheme {}", this.webserviceInfo.getHttpScheme());
|
||||
INIT_LOGGER.info("----> Property Override Test: {}", this.webserviceInfo.getTestProperty());
|
||||
|
||||
// TODO integration of Flyway for database initialization and migration: https://flywaydb.org
|
||||
// see also https://flywaydb.org/getstarted/firststeps/api
|
||||
|
|
|
@ -96,6 +96,12 @@ public interface ExamDAO extends ActivatableEntityDAO<Exam, Exam>, BulkActionSup
|
|||
* @return Result refer to the specified exam or to an error if happened */
|
||||
Result<Long> forceUnlock(Long examId);
|
||||
|
||||
/** Used to force unlock all locked exams for a specified updateId
|
||||
*
|
||||
* @param updateId the update identifier
|
||||
* @return list of identifiers of unlocked exams */
|
||||
Result<Collection<Long>> forceUnlockAll(String updateId);
|
||||
|
||||
/** Indicates if the exam with specified identifier has an internal write lock.
|
||||
*
|
||||
* @param examId the exam identifier
|
||||
|
|
|
@ -465,7 +465,9 @@ public class ExamDAOImpl implements ExamDAO {
|
|||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public Result<Long> forceUnlock(final Long examId) {
|
||||
|
||||
log.info("forceUnlock for exam: {}", examId);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("forceUnlock for exam: {}", examId);
|
||||
}
|
||||
|
||||
return Result.tryCatch(() -> {
|
||||
final ExamRecord examRecord = new ExamRecord(
|
||||
|
@ -481,6 +483,30 @@ public class ExamDAOImpl implements ExamDAO {
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||
public Result<Collection<Long>> forceUnlockAll(final String updateId) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("forceUnlock for updateId: {}", updateId);
|
||||
}
|
||||
|
||||
return Result.tryCatch(() -> {
|
||||
final Collection<Long> result = this.examRecordMapper.selectIdsByExample()
|
||||
.where(ExamRecordDynamicSqlSupport.lastupdate, isEqualTo(updateId))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(this::forceUnlock)
|
||||
.flatMap(Result::skipOnError)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return result;
|
||||
})
|
||||
.onError(TransactionHandler::rollback);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Result<Boolean> isLocked(final Long examId) {
|
||||
|
|
|
@ -293,8 +293,12 @@ public class UserDAOImpl implements UserDAO {
|
|||
.build()
|
||||
.execute();
|
||||
|
||||
return ids.stream()
|
||||
.map(id -> new EntityKey(id, EntityType.USER))
|
||||
return this.userRecordMapper.selectByExample()
|
||||
.where(UserRecordDynamicSqlSupport.id, isIn(ids))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.map(record -> new EntityKey(record.getUuid(), EntityType.USER))
|
||||
.collect(Collectors.toList());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ import ch.ethz.seb.sebserver.gbl.util.Utils;
|
|||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamConfigurationMapDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.TransactionHandler;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamConfigUpdateService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
||||
|
||||
|
@ -150,7 +149,7 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
|||
|
||||
return examIdsFirstCheck;
|
||||
})
|
||||
.onError(TransactionHandler::rollback);
|
||||
.onError(t -> this.examDAO.forceUnlockAll(updateId));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -180,7 +179,8 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
|||
checkActiveClientConnections(exam);
|
||||
|
||||
// lock the exam
|
||||
this.examDAO.placeLock(exam.id, updateId)
|
||||
this.examDAO
|
||||
.placeLock(exam.id, updateId)
|
||||
.getOrThrow();
|
||||
|
||||
// check again if there are no new active client connections in the meantime
|
||||
|
@ -188,7 +188,8 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
|||
|
||||
// apply the referenced change action. On error the change is rolled back and
|
||||
// this processing returns immediately with the error
|
||||
final T result = changeAction.apply(mapping)
|
||||
final T result = changeAction
|
||||
.apply(mapping)
|
||||
.onError(t -> log.error("Fauled to save exam configuration: {}",
|
||||
mapping.configurationNodeId))
|
||||
.getOrThrow();
|
||||
|
@ -205,11 +206,13 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
|||
|
||||
// flush the exam cache. If there was an error during flush, it is logged but this process goes on
|
||||
// and the saved changes are not rolled back
|
||||
this.examSessionService.flushCache(exam)
|
||||
this.examSessionService
|
||||
.flushCache(exam)
|
||||
.onError(t -> log.error("Failed to flush cache for exam: {}", exam));
|
||||
|
||||
// release the exam lock
|
||||
this.examDAO.releaseLock(exam.id, updateId)
|
||||
this.examDAO
|
||||
.releaseLock(exam.id, updateId)
|
||||
.onError(t -> log.error("Failed to release lock for exam: {}", exam));
|
||||
|
||||
return result;
|
||||
|
@ -238,7 +241,8 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
|||
configurationId);
|
||||
|
||||
try {
|
||||
final Configuration config = this.configurationDAO.byPK(configurationId)
|
||||
final Configuration config = this.configurationDAO
|
||||
.byPK(configurationId)
|
||||
.getOrThrow();
|
||||
|
||||
final Collection<Long> involvedExams = this.examConfigurationMapDAO
|
||||
|
@ -260,7 +264,8 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
|||
|
||||
@Override
|
||||
public Collection<Result<Long>> forceReleaseUpdateLocks(final Collection<Long> examIds) {
|
||||
return examIds.stream()
|
||||
return examIds
|
||||
.stream()
|
||||
.map(this.examDAO::forceUnlock)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ sebserver.http.client.connection-request-timeout=10000
|
|||
sebserver.http.client.read-timeout=10000
|
||||
|
||||
# webservice configuration
|
||||
sebserver.init.adminaccount.gen-on-init=false
|
||||
sebserver.webservice.distributed=false
|
||||
sebserver.webservice.http.scheme=http
|
||||
sebserver.webservice.http.server.name=${server.address}
|
||||
|
|
|
@ -79,8 +79,8 @@ public class HTTPClientBot {
|
|||
|
||||
public HTTPClientBot(final Map<String, String> args) {
|
||||
|
||||
this.webserviceAddress = args.getOrDefault("webserviceAddress", "http://ralph.ethz.ch:8080");
|
||||
// this.webserviceAddress = args.getOrDefault("webserviceAddress", "http://localhost:8080");
|
||||
// this.webserviceAddress = args.getOrDefault("webserviceAddress", "http://ralph.ethz.ch:8080");
|
||||
this.webserviceAddress = args.getOrDefault("webserviceAddress", "http://localhost:8080");
|
||||
//this.webserviceAddress = args.getOrDefault("webserviceAddress", "https://seb.test-swissmooc.ch");
|
||||
|
||||
this.accessTokenEndpoint = args.getOrDefault("accessTokenEndpoint", "/oauth/token");
|
||||
|
|
Loading…
Reference in a new issue