diff --git a/src/locales/cs.json b/src/locales/cs.json
index def3d9a76..1bb6c3e5e 100644
--- a/src/locales/cs.json
+++ b/src/locales/cs.json
@@ -745,9 +745,8 @@
"app.examForm.errors.length": "Délka musí být v platném formátu a větší než nula.",
"app.examForm.errors.tooLongExam": "Zkouška nesmí trvat déle než 24 hodin.",
"app.examForm.length": "Délka [h:mm]:",
+ "app.examForm.lockTypeTitle": "Úroveň omezení přístupu pro zamčené studenty",
"app.examForm.saveExam": "Uložit zkoušku",
- "app.examForm.strict": "Striktní zámek",
- "app.examForm.strictLockExplanation": "Během zkoušky se studenti musí zamknout ve skupině, přičemž se jim omezí přístup k ostatním skupinám. V případě běžného zámku budou ostatní skupiny přístupné pouze pro čtení. Striktní zámek zakáže přístup do ostatních skupin zcela. Pokud si nepřejete, aby studenti mohli používat části zdrojových kódu dříve odevzdaných řešení, zvolte striktní zámek.",
"app.exercise.addReferenceSolutionDetailed": "Referenční řešení můžete vytvořit na hlavní stránce úlohy.",
"app.exercise.admins": "Administrátoři",
"app.exercise.admins.explanation": "Administrátoři mají stejná práva jako autor úlohy, ale nejsou zobrazováni v seznamech ani nejsou použiti při filtrování úloh.",
@@ -1117,26 +1116,40 @@
"app.groupExams.ipLockInfo": "Vaše akce budou příjmány pouze z IP adresy [{ipLock}] dokud budete v uzamčeném režimu. Kontaktujte vašeho zkoušejícího pokud potřebujete změnit svoje umístění.",
"app.groupExams.ipLocked": "IP zamčena",
"app.groupExams.listBoxTitle": "Předchozí zkoušky",
- "app.groupExams.lockRegular": "běžný",
- "app.groupExams.lockRegularExplanation": "Studenti, kteří se účastní zkoušky, budou moci číst data z ostatních skupin (a tedy i použít části dříve odevzdaných řešení).",
- "app.groupExams.lockRegularTitle": "Běžný zámek",
- "app.groupExams.lockStrict": "striktní",
- "app.groupExams.lockStrictExplanation": "Studenti, kteří se účastní zkoušky, nebudou moct přistupovat do jiných skupin ani v režimu pro čtení (jsou tedy odříznuti od jejich dříve odevzdaných řešení).",
- "app.groupExams.lockStrictTitle": "Striktní zámek",
+ "app.groupExams.lock.accepted": "akceptované",
+ "app.groupExams.lock.restricted": "nepřístupné",
+ "app.groupExams.lock.reviewed": "revidované",
+ "app.groupExams.lock.visible": "viditelné",
+ "app.groupExams.lockExplanation.accepted": "Studenti, kteří se účastní zkoušky, budou moci přistupovat pouze k řešením, která jsou v ostatních skupinách označena jako akceptovaná (v režimu pro čtení).",
+ "app.groupExams.lockExplanation.restricted": "Studenti, kteří se účastní zkoušky, nebudou moct přistupovat do jiných skupin ani v režimu pro čtení (jsou tedy odříznuti od jejich dříve odevzdaných řešení).",
+ "app.groupExams.lockExplanation.reviewed": "Studenti, kteří se účastní zkoušky, budou moci přistupovat k revidovaným a akceptovaným řešením v jiných skupinách v režimu pro čtení.",
+ "app.groupExams.lockExplanation.visible": "Studenti, kteří se účastní zkoušky, budou moci číst všechna data z ostatních skupin (a tedy i použít části dříve odevzdaných řešení).",
"app.groupExams.lockStudentButton": "Zamknout se",
+ "app.groupExams.lockTitle.accepted": "Akceptovaná řešení",
+ "app.groupExams.lockTitle.restricted": "Nepřístupné",
+ "app.groupExams.lockTitle.reviewed": "Revidovaná a akceptovaná řešení",
+ "app.groupExams.lockTitle.visible": "Vše viditelné (pro čtení)",
+ "app.groupExams.lockType": "Omezení přístupu",
"app.groupExams.lockedElsewhere": "Právě jste zamčený ve zkouškovém režimu v jiné skupině (tuto skupinu můžete procházet pouze v režimu ke čtení).",
+ "app.groupExams.lockedElsewhereStudentInfo.accepted": "Váš přístup je omezen pouze na akceptovaná řešení.",
+ "app.groupExams.lockedElsewhereStudentInfo.reviewed": "Váš přístup je omezen pouze na revidovaná a akceptovaná řešení.",
"app.groupExams.lockedStudentInfo": "Nyní můžete vidět zkouškové úlohy a odevzdávat u nich řešení.",
- "app.groupExams.lockedStudentInfoRegular": "K ostatním skupinám můžete přistupovat pouze v režimu pro čtení dokud jste v uzamčeném režimu.",
- "app.groupExams.lockedStudentInfoStrict": "K ostatním skupinám nemáte přístup dokud jste v uzamčeném režimu.",
- "app.groupExams.locking": "Typ zámku",
+ "app.groupExams.lockedStudentInfo.accepted": "V ostatních skupinách můžete přistupovat pouze k akceptovaným řešením v režimu pro čtení dokud jste uzamčen v probíhající zkoušce.",
+ "app.groupExams.lockedStudentInfo.restricted": "K ostatním skupinám nemáte přístup dokud jste uzamčen v probíhající zkoušce.",
+ "app.groupExams.lockedStudentInfo.reviewed": "V ostatních skupinách můžete přistupovat pouze k revidovaným a akceptovaným řešením v režimu pro čtení dokud jste uzamčen v probíhající zkoušce.",
+ "app.groupExams.lockedStudentInfo.visible": "K ostatním skupinám můžete přistupovat pouze v režimu pro čtení dokud jste v uzamčen v probíhající zkoušce.",
"app.groupExams.locksBoxTitle": "Zaznamenané události zamykání studentů",
"app.groupExams.noExam": "V tuto chvíli není naplánovaná žádná zkouška",
"app.groupExams.pending.studentLockedTitle": "Jste uzamčeném režimu pro probíhající zkoušku",
"app.groupExams.pending.teacherInfo": "V tuto chvíli jsou zkouškové úlohy viditelné pouze studentům, kteří se uzamkli ve skupině.",
"app.groupExams.remainingStudentsBoxTitle": "Zbývající studenti (dosud nezamčení)",
"app.groupExams.studentInfo": "Musíte se uzamknout ve skupině, abyste mohl(a) vidět zkouškové úlohy. Po čas uzamčení je komunikace s vámi omezena na vaši aktuální IP adresu.",
- "app.groupExams.studentInfoRegular": "Navíc budete moct přistupovat k ostatním skupinám pouze v režimu pro čtení dokud budete v uzamčeném režimu.",
- "app.groupExams.studentInfoStrict": "Navíc nebudete moct přistupovat k ostatním skupinám dokud budete v uzamčeném režimu.",
+ "app.groupExams.studentInfo.accepted": "Navíc budete moct přistupovat k akceptovaným řešením v jiných skupinách v režimu pro čtení dokud budete v uzamčeném režimu.",
+ "app.groupExams.studentInfo.restricted": "Navíc nebudete moct přistupovat k ostatním skupinám dokud budete v uzamčeném režimu.",
+ "app.groupExams.studentInfo.reviewed": "Navíc budete moct přistupovat k revidovaným a akceptovaným řešením v jiných skupinách v režimu pro čtení dokud budete v uzamčeném režimu.",
+ "app.groupExams.studentInfo.visible": "Navíc budete moct přistupovat k ostatním skupinám pouze v režimu pro čtení dokud budete v uzamčeném režimu.",
+ "app.groupExams.studentSolutionsRestrictions.accepted": "zobazují se pouze akceptovaná řešení",
+ "app.groupExams.studentSolutionsRestrictions.reviewed": "zobazují se pouze akceptovaná a revidovaná řešení",
"app.groupExams.studentsBoxTitle": "Studenti účastnící se zkoušky",
"app.groupExams.studentsCount": "({count, plural, one {# student} =2 {# studenti} =3 {# studenti} =4 {# studenti} other {# studentů}})",
"app.groupExams.timeAccuracyWarning": "Lokální hodiny na vašem systému musí být dostatečně seřízené, jinak nemusí tato komponenta fungovat zcela správně.",
diff --git a/src/locales/en.json b/src/locales/en.json
index 0800c992f..b1fbec71d 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -745,9 +745,8 @@
"app.examForm.errors.length": "The length must be in valid format and not zero.",
"app.examForm.errors.tooLongExam": "The exam must not be longer than 24 hours.",
"app.examForm.length": "Length [h:mm]:",
+ "app.examForm.lockTypeTitle": "Access limitations for locked students",
"app.examForm.saveExam": "Save Exam",
- "app.examForm.strict": "Strict lock",
- "app.examForm.strictLockExplanation": "During the exam, students will be required to lock themselves in the group. When locked, access to all other groups is restricted. In case of regular locks, other groups are read-only. If the lock is strict, the groups may not be accessed at all. Use strict locking when the students are to be prevented from utilizing pieced of previously submitted code.",
"app.exercise.addReferenceSolutionDetailed": "A reference solution can be added on the exercise detail page.",
"app.exercise.admins": "Administrators",
"app.exercise.admins.explanation": "The administrators have the same permissions as the author towards the exercise, but they are not explicitly mentioned in listings or used in search filters.",
@@ -1117,26 +1116,40 @@
"app.groupExams.ipLockInfo": "Your actions are restricted to IP address [{ipLock}] until the exam lock expires. Contact your exam supervisor if you require relocation.",
"app.groupExams.ipLocked": "IP locked",
"app.groupExams.listBoxTitle": "Previous exams",
- "app.groupExams.lockRegular": "regular",
- "app.groupExams.lockRegularExplanation": "Users taking the exam will be able to access other groups in read-only mode (for instance to utilize pieces of previously submitted code).",
- "app.groupExams.lockRegularTitle": "Regular lock",
- "app.groupExams.lockStrict": "strict",
- "app.groupExams.lockStrictExplanation": "Users taking the exam will not be allowed to access any other group, not even for reading (so that are cut of source codes they submitted before the exam).",
- "app.groupExams.lockStrictTitle": "Strict lock",
+ "app.groupExams.lock.accepted": "accepted",
+ "app.groupExams.lock.restricted": "restricted",
+ "app.groupExams.lock.reviewed": "reviewed",
+ "app.groupExams.lock.visible": "visible",
+ "app.groupExams.lockExplanation.accepted": "Users taking the exam will be allowed to access solutions marked as accepted in other groups in read-only mode.",
+ "app.groupExams.lockExplanation.restricted": "Users taking the exam will not be allowed to access any other group, not even for reading (so that are cut of source codes they submitted before the exam).",
+ "app.groupExams.lockExplanation.reviewed": "Users taking the exam will be allowed to access reviewed and accepted solutions in other groups in read-only mode.",
+ "app.groupExams.lockExplanation.visible": "Users taking the exam will be able to see everything in all other groups in read-only mode (for instance to utilize pieces of previously submitted code).",
"app.groupExams.lockStudentButton": "Lock In",
+ "app.groupExams.lockTitle.accepted": "Accepted solutions",
+ "app.groupExams.lockTitle.restricted": "Restricted access",
+ "app.groupExams.lockTitle.reviewed": "Reviewed and accepted solutions",
+ "app.groupExams.lockTitle.visible": "All visible (read-only)",
+ "app.groupExams.lockType": "Access limit",
"app.groupExams.lockedElsewhere": "You are already locked for an exam in a different group (you can see this group in a read-only mode now).",
+ "app.groupExams.lockedElsewhereStudentInfo.accepted": "Your access is limited to accepted solutions only.",
+ "app.groupExams.lockedElsewhereStudentInfo.reviewed": "Your access is limited to accepted and reviewed solutions only.",
"app.groupExams.lockedStudentInfo": "You may now see and submit solutions to exam assignments.",
- "app.groupExams.lockedStudentInfoRegular": "You may access other groups in read-only mode until the exam lock expires.",
- "app.groupExams.lockedStudentInfoStrict": "You may not access any other groups until the exam lock expires.",
- "app.groupExams.locking": "Lock type",
+ "app.groupExams.lockedStudentInfo.accepted": "You may access accepted solutions in other groups in read-only mode until the exam lock expires.",
+ "app.groupExams.lockedStudentInfo.restricted": "You may not access any other groups until the exam lock expires.",
+ "app.groupExams.lockedStudentInfo.reviewed": "You may access accepted and reviewed solutions in other groups in read-only mode until the exam lock expires.",
+ "app.groupExams.lockedStudentInfo.visible": "You may access other groups in read-only mode until the exam lock expires.",
"app.groupExams.locksBoxTitle": "Recorded student locking events",
"app.groupExams.noExam": "There is currently no exam scheduled",
"app.groupExams.pending.studentLockedTitle": "You are locked in for an exam",
"app.groupExams.pending.teacherInfo": "The exam assignments are currently visible only to students who have lock themselves in the group.",
"app.groupExams.remainingStudentsBoxTitle": "Remaining students (not locked yet)",
"app.groupExams.studentInfo": "You need to lock yourself in to see the exam assignments. When locked, your actions will be restricted to your current IP address.",
- "app.groupExams.studentInfoRegular": "Furthermore, you will be able to access other groups in a read-only mode until the exam lock expires.",
- "app.groupExams.studentInfoStrict": "Furthermore, you will not be able to access other groups until the exam lock expires.",
+ "app.groupExams.studentInfo.accepted": "Furthermore, you will be able to access accepted solutions in other groups in a read-only mode until the exam lock expires.",
+ "app.groupExams.studentInfo.restricted": "Furthermore, you will not be able to access other groups until the exam lock expires.",
+ "app.groupExams.studentInfo.reviewed": "Furthermore, you will be able to access accepted and reviewed solutions in other groups in a read-only mode until the exam lock expires.",
+ "app.groupExams.studentInfo.visible": "Furthermore, you will be able to access other groups in a read-only mode until the exam lock expires.",
+ "app.groupExams.studentSolutionsRestrictions.accepted": "showing only accepted solutions",
+ "app.groupExams.studentSolutionsRestrictions.reviewed": "showing only accepted and reviewed solutions",
"app.groupExams.studentsBoxTitle": "Participating students",
"app.groupExams.studentsCount": "({count, plural, one {# student} other {# students}})",
"app.groupExams.timeAccuracyWarning": "Your local system clock should be sufficiently synchronized or this component may not work properly.",
@@ -2187,4 +2200,4 @@
"recodex-judge-shuffle-all": "Unordered-tokens-and-rows judge",
"recodex-judge-shuffle-newline": "Unordered-tokens judge (ignoring ends of lines)",
"recodex-judge-shuffle-rows": "Unordered-rows judge"
-}
+}
\ No newline at end of file
diff --git a/src/pages/Assignment/Assignment.js b/src/pages/Assignment/Assignment.js
index 620d4ae8d..1a79abca7 100644
--- a/src/pages/Assignment/Assignment.js
+++ b/src/pages/Assignment/Assignment.js
@@ -8,8 +8,10 @@ import { Col, Row } from 'react-bootstrap';
import Box from '../../components/widgets/Box';
import Callout from '../../components/widgets/Callout';
import OptionalPopoverWrapper from '../../components/widgets/OptionalPopoverWrapper';
+import GroupExamPending from '../../components/Groups/GroupExamPending';
import { fetchAssignmentIfNeeded, syncWithExercise, SYNC_OPTIONS_ALL } from '../../redux/modules/assignments.js';
+import { fetchGroupIfNeeded } from '../../redux/modules/groups.js';
import { canSubmit } from '../../redux/modules/canSubmit.js';
import {
init,
@@ -38,13 +40,14 @@ import {
} from '../../redux/selectors/solutions.js';
import { loggedUserIsStudentOfSelector } from '../../redux/selectors/usersGroups.js';
import { loggedInUserSelector } from '../../redux/selectors/users.js';
+import { groupSelector } from '../../redux/selectors/groups.js';
import Page from '../../components/layout/Page';
import { AssignmentNavigation } from '../../components/layout/Navigation';
import ResourceRenderer from '../../components/helpers/ResourceRenderer';
import FetchManyResourceRenderer from '../../components/helpers/FetchManyResourceRenderer';
import AssignmentDetails from '../../components/Assignments/Assignment/AssignmentDetails';
-import Icon, { AssignmentIcon } from '../../components/icons';
+import Icon, { AssignmentIcon, WarningIcon } from '../../components/icons';
import LocalizedTexts from '../../components/helpers/LocalizedTexts';
import SubmitSolutionButton from '../../components/Assignments/SubmitSolutionButton';
import SubmitSolutionContainer from '../../containers/SubmitSolutionContainer';
@@ -55,6 +58,7 @@ import CommentThreadContainer from '../../containers/CommentThreadContainer';
import LoadingSolutionsTable from '../../components/Assignments/SolutionsTable/LoadingSolutionsTable.js';
import FailedLoadingSolutionsTable from '../../components/Assignments/SolutionsTable/FailedLoadingSolutionsTable.js';
import { isStudentLocked } from '../../components/helpers/exams.js';
+import { STUDENT_SOLUTIONS_RESTRICTIONS } from '../../components/Groups/helpers/groupExamMessages.js';
import { hasPermissions } from '../../helpers/common.js';
const getReason = ({ lockedReason }, locale) =>
@@ -65,7 +69,9 @@ const getReason = ({ lockedReason }, locale) =>
class Assignment extends Component {
static loadAsync = ({ assignmentId }, dispatch, { userId }) =>
Promise.all([
- dispatch(fetchAssignmentIfNeeded(assignmentId)),
+ dispatch(fetchAssignmentIfNeeded(assignmentId))
+ .then(res => res.value)
+ .then(assignment => dispatch(fetchGroupIfNeeded(assignment.groupId))),
dispatch(fetchRuntimeEnvironments()),
dispatch(canSubmit(assignmentId)),
dispatch(fetchUsersSolutions(userId, assignmentId)),
@@ -108,6 +114,7 @@ class Assignment extends Component {
fetchManyStatus,
assignmentSolversLoading,
assignmentSolverSelector,
+ getGroup,
intl: { locale },
} = this.props;
@@ -133,6 +140,10 @@ class Assignment extends Component {
}
/>
+
+ {group => group.privateData && }
+
+
{assignment.exerciseId && hasPermissions(assignment, 'update') && (
)}
@@ -155,8 +166,8 @@ class Assignment extends Component {
)}
-
- {(canSubmitObj, ...runtimes) => (
+
+ {(canSubmitObj, group, ...runtimes) => (