diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java index 7ab8183a..05b4e64c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java @@ -39,6 +39,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.text.StringEscapeUtils; import org.eclipse.swt.graphics.RGB; import org.joda.time.DateTime; +import org.joda.time.DateTimeUtils; import org.joda.time.DateTimeZone; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -522,11 +523,11 @@ public final class Utils { } public static long getMillisecondsNow() { - return DateTime.now(DateTimeZone.UTC).getMillis(); + return DateTimeUtils.currentTimeMillis(); } public static long getSecondsNow() { - return DateTime.now(DateTimeZone.UTC).getMillis() / 1000; + return getMillisecondsNow() / 1000; } public static RGB toRGB(final String rgbString) { diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultPageLayout.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultPageLayout.java index 7c24d3c3..8c67a1e2 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultPageLayout.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/DefaultPageLayout.java @@ -164,13 +164,15 @@ public class DefaultPageLayout implements TemplateComposer { private void composeLogoBar(final PageContext pageContext) { final Composite logoBar = new Composite(pageContext.getParent(), SWT.NONE); - final GridData logoBarCell = new GridData(SWT.FILL, SWT.TOP, false, false); + final GridData logoBarCell = new GridData(SWT.FILL, SWT.TOP, true, false); logoBarCell.minimumHeight = 80; logoBarCell.heightHint = 80; + logoBarCell.horizontalIndent = 0; logoBar.setLayoutData(logoBarCell); logoBar.setData(RWT.CUSTOM_VARIANT, "logo"); - final GridLayout logoBarLayout = new GridLayout(2, false); + final GridLayout logoBarLayout = new GridLayout(2, true); logoBarLayout.horizontalSpacing = 0; + logoBarLayout.verticalSpacing = 0; logoBarLayout.marginHeight = 0; logoBar.setLayout(logoBarLayout); @@ -179,7 +181,7 @@ public class DefaultPageLayout implements TemplateComposer { logoCell.minimumHeight = LOGO_IMAGE_MAX_HEIGHT; logoCell.heightHint = LOGO_IMAGE_MAX_HEIGHT; logoCell.minimumWidth = LOGO_IMAGE_MAX_WIDTH; - logoCell.horizontalIndent = 50; + logoCell.horizontalIndent = 0; logo.setLayoutData(logoCell); // try to get institutional logo first. If no success, use default logo @@ -206,8 +208,8 @@ public class DefaultPageLayout implements TemplateComposer { contentBackground.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); contentBackground.setData(RWT.CUSTOM_VARIANT, "bgContent"); final GridLayout innerGrid = new GridLayout(); - innerGrid.marginLeft = 50; - innerGrid.marginRight = 50; + innerGrid.marginLeft = 55; + innerGrid.marginRight = 55; innerGrid.marginHeight = 0; innerGrid.marginWidth = 0; diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ExamDAO.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ExamDAO.java index d5c8b1af..fbcd0840 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ExamDAO.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/ExamDAO.java @@ -128,6 +128,9 @@ public interface ExamDAO extends ActivatableEntityDAO, BulkActionSup * @return Result refer to the lock-check-result or to an error if happened */ Result isLocked(Long examId); + /** This checks if there are write locks that are out of date and release such. */ + void releaseAgedLocks(); + /** Use this to check if the exam with the specified identifier is up to date * * @param examId the exam identifier diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientInstructionDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientInstructionDAOImpl.java index a72871d1..c3a16593 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientInstructionDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientInstructionDAOImpl.java @@ -131,6 +131,7 @@ public class ClientInstructionDAOImpl implements ClientInstructionDAO { } @Override + @Transactional public Result insert( final Long examId, final InstructionType type, diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java index 704ac367..51917bac 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ExamDAOImpl.java @@ -574,7 +574,8 @@ public class ExamDAOImpl implements ExamDAO { } return Result.tryCatch(() -> { - final Collection result = this.examRecordMapper.selectIdsByExample() + final Collection result = this.examRecordMapper + .selectIdsByExample() .where(ExamRecordDynamicSqlSupport.lastupdate, isEqualTo(updateId)) .build() .execute() @@ -596,6 +597,39 @@ public class ExamDAOImpl implements ExamDAO { .map(rec -> BooleanUtils.toBooleanObject(rec.getUpdating())); } + @Override + @Transactional + public void releaseAgedLocks() { + try { + + final List lockedRecords = this.examRecordMapper + .selectByExample() + .where(ExamRecordDynamicSqlSupport.updating, isNotEqualTo(0)) + .build() + .execute(); + + if (lockedRecords != null && !lockedRecords.isEmpty()) { + final long millisecondsNow = Utils.getMillisecondsNow(); + lockedRecords.stream().forEach(record -> { + try { + final String lastUpdateString = record.getLastupdate(); + if (StringUtils.isNotBlank(lastUpdateString)) { + final String[] split = StringUtils.split(lastUpdateString, Constants.UNDERLINE); + final long timestamp = Long.parseLong(split[2]); + if (millisecondsNow - timestamp > Constants.MINUTE_IN_MILLIS) { + forceUnlock(record.getId()).getOrThrow(); + } + } + } catch (final Exception e) { + log.warn("Failed to release aged write lock for exam: {} cause:", record, e.getMessage()); + } + }); + } + } catch (final Exception e) { + log.error("Failed to release aged write locks: {}", e.getMessage()); + } + } + @Override @Transactional(readOnly = true) public Result upToDate(final Long examId, final String updateId) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/WebserviceInfoDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/WebserviceInfoDAOImpl.java index 9cd25318..7c03a347 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/WebserviceInfoDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/WebserviceInfoDAOImpl.java @@ -108,7 +108,7 @@ public class WebserviceInfoDAOImpl implements WebserviceInfoDAO { new WebserviceServerInfoRecord(masterRec.getId(), null, null, null, now)); if (log.isDebugEnabled()) { - log.debug("Update master webservice {} time: {}", uuid, now); + log.trace("Update master webservice {} time: {}", uuid, now); } return true; diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamConfigUpdateServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamConfigUpdateServiceImpl.java index 0e7f8e98..1947a493 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamConfigUpdateServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamConfigUpdateServiceImpl.java @@ -147,7 +147,8 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService { // release the update-locks on involved exams for (final Long examId : examIdsFirstCheck) { - this.examDAO.releaseLock(examId, updateId) + this.examDAO + .releaseLock(examId, updateId) .onError(t -> log.error("Failed to release lock for Exam: {}", examId, t)); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamSessionControlTask.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamSessionControlTask.java index 6fdddc58..a1e77179 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamSessionControlTask.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ExamSessionControlTask.java @@ -106,6 +106,7 @@ class ExamSessionControlTask implements DisposableBean { controlExamStart(updateId); controlExamEnd(updateId); + this.examDAO.releaseAgedLocks(); } @Scheduled(fixedRateString = "${sebserver.webservice.api.seb.lostping.update:5000}") diff --git a/src/main/resources/ch/ethz/seb/sebserver/gui/service/session/proctoring/zoomWindow.html b/src/main/resources/ch/ethz/seb/sebserver/gui/service/session/proctoring/zoomWindow.html index b0dd4266..3a5dbf72 100644 --- a/src/main/resources/ch/ethz/seb/sebserver/gui/service/session/proctoring/zoomWindow.html +++ b/src/main/resources/ch/ethz/seb/sebserver/gui/service/session/proctoring/zoomWindow.html @@ -89,6 +89,11 @@ passWord: config.passWord, success(res) { console.log('JOIN SUCCESS') + ZoomMtg.getAttendeeslist({ + success: function (res) { + console.log(res, "get getAttendeeslist"); + } + }); }, error(res) { console.warn('JOIN ERROR') diff --git a/src/main/resources/config/application-dev.properties b/src/main/resources/config/application-dev.properties index bcaaa941..b11db757 100644 --- a/src/main/resources/config/application-dev.properties +++ b/src/main/resources/config/application-dev.properties @@ -8,6 +8,7 @@ server.servlet.context-path=/ server.tomcat.uri-encoding=UTF-8 logging.level.ch=INFO +logging.level.ch.ethz.seb.sebserver.webservice.datalayer=INFO logging.level.org.springframework.cache=INFO logging.level.ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl=DEBUG logging.level.ch.ethz.seb.sebserver.webservice.servicelayer.session=DEBUG diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index 363f88ef..e325d612 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -19,7 +19,6 @@ - diff --git a/src/main/resources/static/css/sebserver.css b/src/main/resources/static/css/sebserver.css index 8f36434c..a633beb9 100644 --- a/src/main/resources/static/css/sebserver.css +++ b/src/main/resources/static/css/sebserver.css @@ -157,6 +157,7 @@ Composite.header { Composite.logo { background-color: #1F407A; + margin: 0 0 0 0; } Composite.bgLogo { @@ -164,12 +165,14 @@ Composite.bgLogo { background-image: url(static/images/sebserver-logo.png); background-repeat: no-repeat; background-position: left center; + margin: 0 0 0 0; } Composite.bgLogoNoImage { background-color: transparent; background-repeat: no-repeat; background-position: left center; + margin: 0 0 0 0; } Composite.bgContent { diff --git a/src/test/java/ch/ethz/seb/sebserver/gbl/util/UtilsTest.java b/src/test/java/ch/ethz/seb/sebserver/gbl/util/UtilsTest.java index 3aad984c..3c0ae379 100644 --- a/src/test/java/ch/ethz/seb/sebserver/gbl/util/UtilsTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/gbl/util/UtilsTest.java @@ -14,6 +14,7 @@ import java.util.Collection; import java.util.Set; import org.eclipse.swt.graphics.RGB; +import org.joda.time.DateTimeUtils; import org.junit.Test; public class UtilsTest { @@ -66,4 +67,13 @@ public class UtilsTest { } + @Test + public void testTimestamp() { + final long currentTimeMillis = DateTimeUtils.currentTimeMillis(); + final long millisecondsNow = Utils.getMillisecondsNow(); + System.out.println("************* currentTimeMillis: " + currentTimeMillis); + System.out.println("************* millisecondsNow: " + millisecondsNow); + System.out.println("************* div: " + (millisecondsNow - currentTimeMillis)); + } + }