Gitlab Community Edition Instance

Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • j.michal/grady
1 result
Select Git revision
Show changes
Commits on Source (71)
Showing
with 329 additions and 261 deletions
stages:
- build
- test
- pages
- staging
- build
- test
- pages
- build_image
- staging
variables:
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME
# ============================= Building section ============================= #
build_backend:
image: docker:latest
stage: build
script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
# ========================== Build Testing section =========================== #
build_test_env:
image: python:3.6
stage: build
script:
- python -m venv .venv
- source .venv/bin/activate
- make install
artifacts:
paths:
- .venv/
expire_in: 20 minutes
cache:
paths:
- .venv
# ============================== Testing section ============================= #
# ----------------------------- Backend subsection --------------------------- #
.test_template_backend: &test_definition_backend
stage: test
image: $IMAGE_TAG
before_script:
- pip install -r requirements.dev.txt
.test_template_virtualenv: &test_definition_virtualenv
image: python:3.6
before_script:
- source .venv/bin/activate
dependencies:
- build_test_env
test_pytest:
<<: *test_definition_backend
services:
- postgres:9.5
script:
- DJANGO_SETTINGS_MODULE=grady.settings pytest --cov
artifacts:
paths:
- .coverage
<<: *test_definition_virtualenv
stage: test
services:
- postgres:9.5
script:
- DJANGO_SETTINGS_MODULE=grady.settings pytest --cov
artifacts:
paths:
- .coverage
test_prospector:
<<: *test_definition_backend
script:
- prospector --uses django || exit 0
test_flake8:
<<: *test_definition_virtualenv
stage: test
script:
- flake8 --exclude=migrations --ignore=N802 core
# ----------------------------- Frontend subsection -------------------------- #
.test_template_frontend: &test_definition_frontend
image: node:carbon
stage: test
before_script:
- cd frontend/
image: node:carbon
before_script:
- cd frontend/
test_frontend:
<<: *test_definition_frontend
script:
- yarn install
- yarn test --single-run
<<: *test_definition_frontend
stage: test
script:
- yarn install
- yarn test --single-run
cache:
paths:
- frontend/node_modules/
# =========================== Gitlab pages section =========================== #
test_coverage:
image: $IMAGE_TAG
stage:
pages
script:
- coverage html -d public
dependencies:
- test_pytest
artifacts:
paths:
- public
only:
- master
pages:
<<: *test_definition_virtualenv
stage:
pages
script:
- coverage html -d public
dependencies:
- test_pytest
- build_test_env
artifacts:
paths:
- public
only:
- master
# =========================== Build Image section ============================ #
build_backend:
image: docker:latest
stage: build_image
script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build -t $IMAGE_TAG .
- docker push $IMAGE_TAG
only:
- master
# ============================== Staging section ============================= #
.staging_template: &staging_definition
stage: staging
image: docker:latest
only:
- master
before_script:
- apk add --update py-pip && pip install docker-compose
stage: staging
image: docker:latest
only:
- master
before_script:
- apk add --update py-pip && pip install docker-compose
staging:
<<: *staging_definition
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://staging.grady.janmax.org
on_stop: staging_stop
script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker-compose up -d --force-recreate
<<: *staging_definition
environment:
name: review/$CI_COMMIT_REF_NAME
url: https://staging.grady.janmax.org
on_stop: staging_stop
script:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker-compose up -d --force-recreate
staging_stop:
<<: *staging_definition
script:
- docker-compose rm --force --stop
when: manual
environment:
name: review/$CI_COMMIT_REF_NAME
action: stop
<<: *staging_definition
script:
- docker-compose rm --force --stop
when: manual
environment:
name: review/$CI_COMMIT_REF_NAME
action: stop
......@@ -12,10 +12,3 @@
args:
- requirements.txt
- requirements.dev.txt
- repo: local
hooks:
- id: prospector
name: prospector
entry: ./pre-commit-scripts/prospector.sh
language: script
types: [python]
......@@ -17,9 +17,6 @@ RUN apk update \
&& apk add --virtual build-deps gcc python3-dev musl-dev curl \
&& apk add --no-cache postgresql-dev
RUN mkdir -p /usr/share/dict
RUN curl -s https://gitlab.gwdg.de/snippets/51/raw --output /usr/share/dict/words
WORKDIR /code
COPY . /code
......
......@@ -24,8 +24,8 @@ migrate:
python manage.py migrate
install:
pip install -r requirements.txt
pip install -r requirements.dev.txt
pip install -Ur requirements.txt
pip install -Ur requirements.dev.txt
test:
DJANGO_SETTINGS_MODULE=grady.settings pytest
......
grady_says = [
"Now let's see if we can improve this with a little water, sir.",
"Won't keep you a moment, sir.",
"Grady, sir. Delbert Grady.",
"Yes, sir.",
"That's right, sir.",
"Why no, sir. I don't believe so.",
"Ah ha, it's coming off now, sir.",
"Why no, sir. I don't believe so.",
"Yes, sir. I have a wife and two daughters, sir.",
"Oh, they're somewhere around. I'm not quite sure at the moment, sir.",
"That's strange, sir. I don't have any recollection of that at all.",
"I'm sorry to differ with you, sir, but you are the caretaker.",
"You have always been the caretaker, I should know, sir.",
"I've always been here.",
"Indeed, he is, Mr. Torrance. Avery willful boy. ",
"A rather naughty boy, if I may be so bold, sir.",
"Perhaps they need a good talking to, if you don't mind my saying so. Perhaps a bit more.",
"My girls, sir, they didn't care for the Overlook at first.",
"One of them actually stole a packet of matches and tried to burn it down.",
"But I corrected them, sir.",
"And when my wife tried to prevent me from doing my duty... I corrected her.",
]
......@@ -13,9 +13,8 @@ from typing import Dict, Union
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AbstractUser
from django.db import models
from django.db.models import Value as V
from django.db.models import (BooleanField, Case, Count, F, IntegerField, Q,
QuerySet, Sum, When)
QuerySet, Sum, Value, When)
from django.db.models.functions import Coalesce
......@@ -125,7 +124,7 @@ class SubmissionType(models.Model):
When(
Q(submissions__feedback__isnull=False) &
Q(submissions__feedback__status=Feedback.ACCEPTED),
then=V(1)), output_field=IntegerField(),
then=Value(1)), output_field=IntegerField(),
)
)
).annotate(
......@@ -230,11 +229,12 @@ class Student(models.Model):
the annotated QuerySet as described above.
"""
return cls.objects.annotate(
overall_score=Coalesce(Sum('submissions__feedback__score'), V(0)),
overall_score=Coalesce(Sum('submissions__feedback__score'),
Value(0)),
).annotate(
done=Case(
When(exam__pass_score__lt=F('overall_score'), then=V(1)),
default=V(0),
When(exam__pass_score__lt=F('overall_score'), then=Value(1)),
default=Value(0),
output_field=BooleanField()
)
)
......@@ -362,12 +362,12 @@ class Submission(models.Model):
candidates = cls.objects.filter(
(
Q(feedback__isnull=True)
| Q(feedback__origin=Feedback.DID_NOT_COMPILE)
| Q(feedback__origin=Feedback.COULD_NOT_LINK)
| Q(feedback__origin=Feedback.FAILED_UNIT_TESTS)
)
& ~Q(feedback__of_tutor=tutor)
Q(feedback__isnull=True) |
Q(feedback__origin=Feedback.DID_NOT_COMPILE) |
Q(feedback__origin=Feedback.COULD_NOT_LINK) |
Q(feedback__origin=Feedback.FAILED_UNIT_TESTS)
) &
~Q(feedback__of_tutor=tutor)
)
# we want a submission of a specific type
......@@ -542,6 +542,7 @@ class Feedback(models.Model):
)
return tutor_feedback[0] if tutor_feedback else None
@classmethod
def tutor_assigned_feedback(cls, user: Union[Tutor, Reviewer]):
"""Gets all feedback that is assigned to the tutor including
all status cases.
......
import logging
from drf_dynamic_fields import DynamicFieldsMixin
from rest_framework import serializers
from core.models import (ExamType, Feedback, Student, Submission,
......@@ -10,7 +11,12 @@ log = logging.getLogger(__name__)
user_factory = GradyUserFactory()
class ExamSerializer(serializers.ModelSerializer):
class DynamicFieldsModelSerializer(DynamicFieldsMixin,
serializers.ModelSerializer):
pass
class ExamSerializer(DynamicFieldsModelSerializer):
class Meta:
model = ExamType
......@@ -18,32 +24,34 @@ class ExamSerializer(serializers.ModelSerializer):
'pass_score', 'pass_only',)
class FeedbackSerializer(serializers.ModelSerializer):
class FeedbackSerializer(DynamicFieldsModelSerializer):
class Meta:
model = Feedback
fields = ('text', 'score')
class SubmissionTypeSerializer(serializers.ModelSerializer):
class SubmissionTypeSerializer(DynamicFieldsModelSerializer):
class Meta:
model = SubmissionType
fields = ('name', 'full_score', 'description', 'solution')
class SubmissionSerializer(serializers.ModelSerializer):
class SubmissionSerializer(DynamicFieldsModelSerializer):
feedback = serializers.ReadOnlyField(source='feedback.text')
score = serializers.ReadOnlyField(source='feedback.score')
type = serializers.ReadOnlyField(source='type.name')
type_id = serializers.ReadOnlyField(source='type.id')
type_name = serializers.ReadOnlyField(source='type.name')
full_score = serializers.ReadOnlyField(source='type.full_score')
class Meta:
model = Submission
fields = ('type', 'text', 'feedback', 'score', 'full_score')
fields = ('type_id', 'type_name', 'text',
'feedback', 'score', 'full_score')
class StudentSerializer(serializers.ModelSerializer):
class StudentSerializer(DynamicFieldsModelSerializer):
name = serializers.ReadOnlyField(source='user.fullname')
user = serializers.ReadOnlyField(source='user.username')
exam = ExamSerializer()
......@@ -54,7 +62,7 @@ class StudentSerializer(serializers.ModelSerializer):
fields = ('name', 'user', 'exam', 'submissions')
class SubmissionNoTextFieldsSerializer(serializers.ModelSerializer):
class SubmissionNoTextFieldsSerializer(DynamicFieldsModelSerializer):
score = serializers.ReadOnlyField(source='feedback.score')
type = serializers.ReadOnlyField(source='type.name')
full_score = serializers.ReadOnlyField(source='type.full_score')
......@@ -64,7 +72,7 @@ class SubmissionNoTextFieldsSerializer(serializers.ModelSerializer):
fields = ('type', 'score', 'full_score')
class StudentSerializerForListView(serializers.ModelSerializer):
class StudentSerializerForListView(DynamicFieldsModelSerializer):
name = serializers.ReadOnlyField(source='user.fullname')
user = serializers.ReadOnlyField(source='user.username')
exam = serializers.ReadOnlyField(source='exam.module_reference')
......@@ -75,7 +83,7 @@ class StudentSerializerForListView(serializers.ModelSerializer):
fields = ('name', 'user', 'exam', 'submissions')
class TutorSerializer(serializers.ModelSerializer):
class TutorSerializer(DynamicFieldsModelSerializer):
username = serializers.CharField(source='user.username')
feedback_count = serializers.IntegerField(source='get_feedback_count',
read_only=True)
......
""" A set of factory methods that make testing easier. Each method creates all
reuired subfields if not provided by via kwargs. """
from core.models import (ExamType, Feedback, Reviewer, Student, Submission,
SubmissionType, Tutor, UserAccount)
# These methods are meant to be used to provide data to insert into the test
# database
def make_user(username='user01',
password='p',
fullname='us er01',
is_admin=False):
user = UserAccount.objects.create(username=username,
fullname=fullname,
is_admin=is_admin)
user.set_password(password)
user.save()
return user
def make_exam(module_reference='TestExam B.Inf.0042',
total_score=42,
pass_score=21,
**kwargs):
return ExamType.objects.create(module_reference=module_reference,
total_score=total_score,
pass_score=pass_score, **kwargs)
def make_submission_type(name='problem01',
full_score=10,
description='Very hard',
solution='Impossible!'):
return SubmissionType.objects.create(name=name,
full_score=full_score,
description=description,
solution=solution)
def make_student(user=None, exam=None):
if user is None:
user = make_user()
if exam is None:
exam = make_exam()
return Student.objects.create(user=user, exam=exam)
def make_tutor(user=None):
if user is None:
user = make_user()
return Tutor.objects.create(user=user)
def make_reviewer(user=None):
if user is None:
user = make_user()
return Reviewer.objects.create(user=user)
def make_submission(type=None, student=None, text='Too hard for me ;-('):
if type is None:
type = make_submission_type()
if student is None:
student = make_student()
return Submission.objects.create(text=text, type=type, student=student)
def make_feedback(of_tutor, of_submission=None, text='Very bad!', score=3):
if of_submission is None:
of_submission = make_submission()
return Feedback.objects.create(of_tutor=of_tutor,
of_submission=of_submission,
text=text,
score=score)
def make_minimal_exam():
# also creates default examType, submissionType and student
submission = make_submission()
tutor = make_tutor(user=make_user(username='tutor01'))
feedback = make_feedback(of_tutor=tutor, of_submission=submission)
return submission, tutor, feedback
......@@ -4,7 +4,7 @@ from rest_framework.test import (APIRequestFactory, APITestCase,
force_authenticate)
from core.views import (ExamApiViewSet, StudentReviewerApiViewSet,
StudentSelfApiViewSet, TutorApiViewSet)
StudentSelfApiView, TutorApiViewSet)
from util.factories import GradyUserFactory
......@@ -21,8 +21,8 @@ class AccessRightsOfStudentAPIViewTests(APITestCase):
self.student = self.user_factory.make_student()
self.tutor = self.user_factory.make_tutor()
self.reviewer = self.user_factory.make_reviewer()
self.request = self.factory.get(reverse('student_page-list'))
self.view = StudentSelfApiViewSet.as_view({'get': 'retrieve'})
self.request = self.factory.get(reverse('student-page'))
self.view = StudentSelfApiView.as_view()
def test_unauthenticated_access_denied(self):
response = self.view(self.request)
......
from django.urls import reverse
from rest_framework.test import (APIRequestFactory, APITestCase,
force_authenticate)
from core.views import get_user_role
from util.factories import GradyUserFactory
class GetUserRoleTest(APITestCase):
@classmethod
def setUpTestData(cls):
cls.factory = APIRequestFactory()
cls.user_factory = GradyUserFactory()
cls.student = cls.user_factory.make_student()
cls.tutor = cls.user_factory.make_tutor()
cls.reviewer = cls.user_factory.make_reviewer()
def setUp(self):
self.request = self.factory.get(reverse('user-role'))
def test_get_user_model_returns_student(self):
force_authenticate(self.request, user=self.student.user)
response = get_user_role(self.request)
self.assertEqual(response.data['role'], 'Student')
def test_get_user_model_returns_tutor(self):
force_authenticate(self.request, user=self.tutor.user)
response = get_user_role(self.request)
self.assertEqual(response.data['role'], 'Tutor')
def test_get_user_model_returns_reviewer(self):
force_authenticate(self.request, user=self.reviewer.user)
response = get_user_role(self.request)
self.assertEqual(response.data['role'], 'Reviewer')
......@@ -2,9 +2,9 @@ from django.urls import reverse
from rest_framework.test import (APIRequestFactory, APITestCase,
force_authenticate)
from core.models import Reviewer, SubmissionType
from core.tests import data_factories
from core.views import StudentSelfApiViewSet
from core.models import SubmissionType
from core.views import StudentSelfApiView
from util.factories import make_test_data
class StudentPageTests(APITestCase):
......@@ -14,13 +14,49 @@ class StudentPageTests(APITestCase):
cls.factory = APIRequestFactory()
def setUp(self):
self.submission, self.tutor, self.feedback = \
data_factories.make_minimal_exam()
self.student = self.submission.student
self.reviewer = Reviewer.objects.create(
user=data_factories.make_user(username='reviewer'))
self.request = self.factory.get(reverse('student_page-list'))
self.view = StudentSelfApiViewSet.as_view({'get': 'retrieve'})
self.test_data = make_test_data(data_dict={
'exams': [{
'module_reference': 'TestExam B.Inf.0042',
'total_score': 42,
'pass_score': 21
}],
'submission_types': [{
'name': 'problem01',
'full_score': 10,
'description': 'Very hard',
'solution': 'Impossible!'
}],
'students': [{
'username': 'user01',
'fullname': 'us er01',
'exam': 'TestExam B.Inf.0042'
}],
'tutors': [{
'username': 'tutor01'
}],
'reviewers': [{
'username': 'reviewer'
}],
'submissions': [{
'user': 'user01',
'type': 'problem01',
'text': 'Too hard for me ;-(',
'feedback': {
'of_tutor': 'tutor01',
'text': 'Very bad!',
'score': 3
}
}]
})
self.student = self.test_data['students'][0]
self.tutor = self.test_data['tutors'][0]
self.reviewer = self.test_data['reviewers'][0]
self.submission = self.test_data['submissions'][0]
self.feedback = self.submission.feedback
self.request = self.factory.get(reverse('student-page'))
self.view = StudentSelfApiView.as_view()
force_authenticate(self.request, user=self.student.user)
self.response = self.view(self.request)
......@@ -60,11 +96,16 @@ class StudentPageTests(APITestCase):
self.exam_obj["pass_only"], self.student.exam.pass_only)
# Tests concerning submission data
def test_a_student_submissions_contains_type(self):
def test_a_student_submissions_contains_type_name(self):
self.assertEqual(
self.submission_list_first_entry['type'],
self.submission_list_first_entry['type_name'],
self.student.submissions.first().type.name)
def test_a_student_submissions_contains_type_id(self):
self.assertEqual(
self.submission_list_first_entry['type_id'],
self.student.submissions.first().type.id)
def test_submission_data_contains_text(self):
self.assertEqual(
self.submission_list_first_entry['text'],
......
......@@ -3,9 +3,8 @@ from rest_framework import status
from rest_framework.test import (APIRequestFactory, APITestCase,
force_authenticate)
from core.tests import data_factories
from core.views import StudentReviewerApiViewSet
from util.factories import GradyUserFactory
from util.factories import make_test_data
class StudentPageTests(APITestCase):
......@@ -13,12 +12,46 @@ class StudentPageTests(APITestCase):
@classmethod
def setUpTestData(cls):
cls.factory = APIRequestFactory()
cls.user_factory = GradyUserFactory()
def setUp(self):
self.submission, _, _ = data_factories.make_minimal_exam()
self.student = self.submission.student
self.reviewer = self.user_factory.make_reviewer(username='reviewer')
self.test_data = make_test_data(data_dict={
'exams': [{
'module_reference': 'TestExam B.Inf.0042',
'total_score': 42,
'pass_score': 21
}],
'submission_types': [{
'name': 'problem01',
'full_score': 10,
'description': 'Very hard',
'solution': 'Impossible!'
}],
'students': [{
'username': 'user01',
'fullname': 'us er01',
'exam': 'TestExam B.Inf.0042'
}],
'tutors': [{
'username': 'tutor'
}],
'reviewers': [{
'username': 'reviewer'
}],
'submissions': [{
'user': 'user01',
'type': 'problem01',
'text': 'Too hard for me ;-(',
'feedback': {
'score': 3,
'of_tutor': 'tutor'
}
}]
})
self.student = self.test_data['students'][0]
self.reviewer = self.test_data['reviewers'][0]
self.submission = self.test_data['submissions'][0]
self.request = self.factory.get(reverse('student-list'))
self.view = StudentReviewerApiViewSet.as_view({'get': 'list'})
......
......@@ -12,11 +12,19 @@ router.register(r'student', views.StudentReviewerApiViewSet)
router.register(r'examtype', views.ExamApiViewSet)
router.register(r'submissiontype', views.SubmissionTypeApiView)
router.register(r'tutor', views.TutorApiViewSet)
router.register(r'student-page', views.StudentSelfApiViewSet,
base_name='student_page')
# regular views that are not viewsets
regular_views_urlpatterns = [
url(r'student-page', views.StudentSelfApiView.as_view(),
name='student-page'),
url(r'user-role', views.get_user_role, name='user-role'),
url(r'jwt-time-delta', views.get_jwt_expiration_delta,
name='jwt-time-delta')
]
urlpatterns = [
url(r'^api/', include(router.urls)),
url(r'^api/', include(regular_views_urlpatterns)),
url(r'^api-token-auth/', obtain_jwt_token),
url(r'^api-token-refresh', refresh_jwt_token),
url(r'^$', TemplateView.as_view(template_name='index.html')),
......
""" All API views that are used to retrieve data from the database. They
can be categorized by the permissions they require. All views require a
user to be authenticated and most are only accessible by one user group """
from rest_framework import mixins, viewsets
from django.conf import settings
from rest_framework import mixins, viewsets, generics
from rest_framework.decorators import api_view
from rest_framework.response import Response
from core.models import ExamType, Student, SubmissionType, Tutor
from core.permissions import IsReviewer, IsStudent
......@@ -10,10 +13,20 @@ from core.serializers import (ExamSerializer, StudentSerializer,
SubmissionTypeSerializer, TutorSerializer)
class StudentSelfApiViewSet(viewsets.ReadOnlyModelViewSet):
@api_view()
def get_jwt_expiration_delta(request):
return Response({'timeDelta': settings.JWT_AUTH['JWT_EXPIRATION_DELTA']})
@api_view()
def get_user_role(request):
return Response({'role':
type(request.user.get_associated_user()).__name__})
class StudentSelfApiView(generics.RetrieveAPIView):
""" Gets all data that belongs to one student """
permission_classes = (IsStudent,)
queryset = Student.objects.all()
serializer_class = StudentSerializer
def get_object(self) -> Student:
......
......@@ -17,7 +17,7 @@ module.exports = {
// Surge or Netlify already gzip all static assets for you.
// Before setting to `true`, make sure to:
// npm install --save-dev compression-webpack-plugin
productionGzip: false,
productionGzip: true,
productionGzipExtensions: ['js', 'css'],
// Run the build command with an extra argument to
// View the bundle analyzer report after build finishes:
......
......@@ -2,7 +2,7 @@
<html>
<head>
<meta charset="utf-8">
<title>frontend</title>
<title>Grady</title>
</head>
<body>
<div id="app"></div>
......
......@@ -14,9 +14,11 @@
},
"dependencies": {
"axios": "^0.17.0",
"google-code-prettify": "^1.0.5",
"material-design-icons": "^3.0.1",
"vue": "^2.5.2",
"vue-router": "^3.0.1",
"vuetify": "^0.16.9",
"vuetify": "^0.17.3",
"vuex": "^3.0.1"
},
"devDependencies": {
......@@ -31,6 +33,7 @@
"babel-register": "^6.22.0",
"chai": "^4.1.2",
"chalk": "^2.0.1",
"compression-webpack-plugin": "^1.0.1",
"connect-history-api-fallback": "^1.3.0",
"copy-webpack-plugin": "^4.0.1",
"cross-env": "^5.0.1",
......
......@@ -11,11 +11,8 @@
name: 'app',
components: {
}
}
}
</script>
<style>
#app {
}
</style>
frontend/src/assets/logo.png

6.69 KiB

......@@ -4,20 +4,30 @@
<v-flex text-xs-center md4 lg2>
<img src="../assets/brand.png"/>
<h3 class="pt-3">Log in</h3>
<p>But I corrected them, sir.</p>
<v-form>
<v-alert
outline
v-if="error"
color="error"
:value="true"
transition="fade-transition"
>{{ error }}</v-alert>
<p v-else>But I corrected them, sir.</p>
<v-form
@submit="submit">
<v-text-field
label="Username"
v-model="credentials.username"
required></v-text-field>
required
autofocus
></v-text-field>
<v-text-field
label="Password"
v-model="credentials.password"
type="password"
required></v-text-field>
required
></v-text-field>
<v-btn :loading="loading" type="submit" color="primary">Access</v-btn>
</v-form>
<v-btn color="primary" @click="submit()">Access</v-btn>
</v-flex>
</v-layout>
</v-container>
......@@ -25,6 +35,7 @@
<script>
import {mapActions, mapState} from 'vuex'
export default {
name: 'grady-login',
data () {
......@@ -33,18 +44,29 @@
username: '',
password: ''
},
error: ''
loading: false
}
},
computed: {
...mapState([
'error'
])
},
methods: {
...mapActions([
'getJWTToken',
'getExamModule',
'getUserRole',
'getJWTTimeDelta'
]),
submit () {
const credentials = {
username: this.credentials.username,
password: this.credentials.password
}
this.$store.dispatch('getToken', credentials).then(response => {
this.$router.push('/reviewer/')
})
this.loading = true
this.getJWTToken(this.credentials).then(() => {
this.getUserRole()
this.getJWTTimeDelta()
this.loading = false
this.$router.push('/student/')
}).catch(() => { this.loading = false })
}
}
}
......