diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/.idea/dictionaries/shafaqat.xml b/.idea/dictionaries/shafaqat.xml deleted file mode 100644 index aff52d5..0000000 --- a/.idea/dictionaries/shafaqat.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 17b6b9a..0000000 --- a/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index e719be2..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - false - - false - false - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index d213b4d..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/trainingportal.iml b/.idea/trainingportal.iml deleted file mode 100644 index 27b82f6..0000000 --- a/.idea/trainingportal.iml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index bb07a23..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,1013 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DATABASES - client_encoding - timezone - TIME_ZONE - MEDIA_ROOT - STATIC_ROOT - max_length - USER - static - password - authenticate - response - LOG - LOGIN_URL - extra_fields - model - model( - home - - - - - - - - - true - DEFINITION_ORDER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - project - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1518163119916 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/static/css/add_trainer_modal_style.css b/static/css/add_trainer_modal_style.css new file mode 100644 index 0000000..4147ffc --- /dev/null +++ b/static/css/add_trainer_modal_style.css @@ -0,0 +1,40 @@ +/* The Modal (background) */ +.modal { + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 1; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ +} + +/* Modal Content/Box */ +.modal-content { + background-color: #fefefe; + margin: 3% auto; /* 15% from the top and centered */ + padding: 10px; + border: 1px solid #888; + width: 50%; /* Could be more or less, depending on screen size */ + overflow: auto; + height: 85%; + +} + +/* The Close Button */ +.close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; +} + +.close:hover, +.close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} \ No newline at end of file diff --git a/static/js/trainingportal/add_task.js b/static/js/trainingportal/add_task.js new file mode 100644 index 0000000..694bdf9 --- /dev/null +++ b/static/js/trainingportal/add_task.js @@ -0,0 +1,49 @@ +/** + * Created by shafaqat on 2/21/18. + */ + +$(document).ready(function () { + + $("#submitBtn").click(function (event) { + $('#validate_text').html(''); + var title = $("#id_title").val(); + var description = $("#id_description").val(); + + if (title == null || title == '' || + description == null || description == '') { + $('#validate_text').html('Required fields are empty.
'); + event.preventDefault(); + } + }); + + var frm = $('#taskForm'); + frm.submit(function (event) { + event.preventDefault(); + $('#validate_text').html(''); + var data = new FormData(frm.get(0)); + $.ajax({ + type: frm.attr('method'), + url: frm.attr('action'), + data: frm.serialize(), + success: function (data) { + data = JSON.parse(data); + if (data['failure_message']) { + $('#validate_text').html('Required fields are empty.
'); + } + else { + frm.find("input, textarea").val(""); + var modal = document.getElementById('myModal'); + modal.style.display = "none"; + alert('Task added successfully'); + window.location.href = '/tasks/?trainer_id=' + data['trainer_id'] + + '&training_id=' + data['training_id'] + + '&trainee_id=' + data['trainee_id'] + } + }, + error: function (data) { + $('#validate_text').html('Required fields are empty.
'); + } + }); + return false; + }); +}); \ No newline at end of file diff --git a/static/js/trainingportal/add_training_modal.js b/static/js/trainingportal/add_training_modal.js new file mode 100644 index 0000000..5638961 --- /dev/null +++ b/static/js/trainingportal/add_training_modal.js @@ -0,0 +1,28 @@ +/** + * Created by shafaqat on 2/15/18. + */ +// Get the modal +var modal = document.getElementById('myModal'); + +// Get the button that opens the modal +var btn = document.getElementById("trainingBtn"); + +// Get the element that closes the modal +var span = document.getElementsByClassName("close")[0]; + +// When the user clicks on the button, open the modal +btn.onclick = function () { + modal.style.display = "block"; +} + +// When the user clicks on (x), close the modal +span.onclick = function () { + modal.style.display = "none"; +} + +// When the user clicks anywhere outside of the modal, close it +window.onclick = function (event) { + if (event.target == modal) { + modal.style.display = "none"; + } +} \ No newline at end of file diff --git a/static/js/trainingportal/assignment_form.js b/static/js/trainingportal/assignment_form.js new file mode 100644 index 0000000..06633ce --- /dev/null +++ b/static/js/trainingportal/assignment_form.js @@ -0,0 +1,92 @@ +/** + * Created by shafaqat on 2/22/18. + */ + +$(document).ready(function () { + + $("#submitBtn").click(function (event) { + $('#validate_text').html(''); + var title = $("#id_title").val(); + var description = $("#id_description").val(); + var due_date = $("#id_due_date").val(); + + if (title == null || title == '' || + description == null || description == '' || + due_date == null || due_date == '') { + $('#validate_text').html('Required fields are empty.
'); + event.preventDefault(); + } + }); + + var frm = $('#assignmentForm'); + frm.submit(function (event) { + event.preventDefault(); + $('#validate_text').html(''); + var data = new FormData(frm.get(0)); + $.ajax({ + type: frm.attr('method'), + url: frm.attr('action'), + processData: false, + contentType: false, + data: data, + success: function (data) { + data = JSON.parse(data); + if (data['failure_message']) { + $('#validate_text').html('Required fields are empty.
'); + } + else { + frm.find("input, textarea").val(""); + var modal = document.getElementById('myModal'); + modal.style.display = "none"; + alert('Assignment added successfully'); + window.location.href = '/assignments/?task_id=' + data['task_id'] + } + }, + error: function (data) { + $('#validate_text').html('Required fields are empty.
'); + } + }); + return false; + }); + + $("#evaluateBtn").click(function (event) { + $('#validate_text').html(''); + var score = $("#id_score").val(); + var remarks = $("#id_remarks").val(); + + if (score == null || score == '' || + remarks == null || remarks == '') { + $('#validate_text').html('Required fields are empty.
'); + event.preventDefault(); + } + }); + + var evaluateForm = $('#evaluateAssignmentForm'); + evaluateForm.submit(function (event) { + event.preventDefault(); + $('#validate_text').html(''); + var data = new FormData(evaluateForm.get(0)); + $.ajax({ + type: evaluateForm.attr('method'), + url: evaluateForm.attr('action'), + processData: false, + contentType: false, + data: data, + success: function (data) { + data = JSON.parse(data); + if (data['failure_message']) { + $('#validate_text').html('Required fields are empty.
'); + } + else { + evaluateForm.find("input, textarea").val(""); + alert('Assignment Evaluated successfully'); + window.location.href = data['redirect_path'] + } + }, + error: function (data) { + $('#validate_text').html('Required fields are empty.
'); + } + }); + return false; + }); +}); diff --git a/static/js/trainingportal/loginformvalidation.js b/static/js/trainingportal/loginformvalidation.js index bb0643f..d3cf01d 100644 --- a/static/js/trainingportal/loginformvalidation.js +++ b/static/js/trainingportal/loginformvalidation.js @@ -3,6 +3,7 @@ */ $(document).ready(function () { + $('#error_msg').hide(); $("#submitBtn").click(function(event) { var username = $("#id_username").val(); var password = $("#id_password").val(); @@ -12,10 +13,6 @@ $(document).ready(function () { $('#validate_text').html('Username or password is empty
'); event.preventDefault(); } - else - { - - } }); var frm = $('#loginForm'); @@ -25,11 +22,16 @@ $(document).ready(function () { url: frm.attr('action'), data: frm.serialize(), success: function (data) { - alert(data); - $('html').html(data); + data = JSON.parse(data); + if (data['failure_message']) + {$('#error_msg').show(1000);} + else + { + window.location.href = data['redirect_path']; + } }, error: function(data) { - alert('Request failed.'); + $('#error_msg').show(1000); } }); return false; diff --git a/static/js/trainingportal/submit_assignment.js b/static/js/trainingportal/submit_assignment.js new file mode 100644 index 0000000..cf7f852 --- /dev/null +++ b/static/js/trainingportal/submit_assignment.js @@ -0,0 +1,35 @@ +/** + * Created by shafaqat on 2/22/18. + */ + +$(document).ready(function () { + + var submitAssignmentForm = $('#submitAssignmentForm'); + submitAssignmentForm.submit(function (event) { + event.preventDefault(); + var data = new FormData(submitAssignmentForm.get(0)); + $.ajax({ + type: submitAssignmentForm.attr('method'), + url: submitAssignmentForm.attr('action'), + processData: false, + contentType: false, + data: data, + success: function (data) { + data = JSON.parse(data); + if (data['failure_message']) { + alert('File not uploaded.'); + } + else { + submitAssignmentForm.find("input, textarea").val(""); + alert('Assignment Submitted successfully'); + window.location.href = data['redirect_path'] + } + }, + error: function (data) { + alert('Required field(s) are empty'); + } + }); + return false; + }); +}); + diff --git a/static/js/trainingportal/training_form_validation.js b/static/js/trainingportal/training_form_validation.js new file mode 100644 index 0000000..d889684 --- /dev/null +++ b/static/js/trainingportal/training_form_validation.js @@ -0,0 +1,125 @@ +/** + * Created by shafaqat on 2/16/18. + */ + +$(document).ready(function () { + + $("#submitBtn").click(function (event) { + $('#validate_text').html(''); + var title = $("#id_title").val(); + var description = $("#id_description").val(); + var due_date = $("#id_due_date").val(); + + if (title == null || title == '' || + description == null || description == '' || + due_date == null || due_date == '') { + $('#validate_text').html('Required fields are empty.
'); + event.preventDefault(); + } + }); + + var frm = $('#trainingForm'); + frm.submit(function (event) { + event.preventDefault(); + $('#validate_text').html(''); + var data = new FormData(frm.get(0)); + $.ajax({ + type: frm.attr('method'), + processData: false, + contentType: false, + url: frm.attr('action'), + data: data, + success: function (data) { + data = JSON.parse(data); + if (data['failure_message']) { + $('#validate_text').html('Required fields are empty.
'); + } + else { + frm.find("input, textarea").val(""); + var modal = document.getElementById('myModal'); + modal.style.display = "none"; + alert('Training added successfully'); + window.location.href = frm.attr('action'); + } + }, + error: function (data) { + $('#validate_text').html('Required fields are empty.
'); + } + }); + return false; + }); + + var edit_form = $('#editTrainingForm'); + edit_form.submit(function (event) { + event.preventDefault(); + $('#validate_text').html(''); + var data = new FormData(edit_form.get(0)); + $.ajax({ + type: edit_form.attr('method'), + processData: false, + contentType: false, + url: edit_form.attr('action'), + data: data, + success: function (data) { + data = JSON.parse(data); + if (data['failure_message']) { + $('#validate_text').html('Required fields are empty.
'); + } + else { + edit_form.find("input, textarea").val(""); + alert('Training edited successfully.'); + window.location.href = data['redirect_path']; + } + }, + error: function (data) { + $('#validate_text').html('Required fields are empty.
'); + } + }); + return false; + }); + + $(function () { + $.ajaxSetup({ + headers: {"X-CSRFToken": getCookie("csrftoken")} + }); + }); +}); + + +function delete_training(training_id) { + if (confirm("Are you sure you want to delete training?")) { + $(document).ready(function () { + $.ajax({ + type: 'DELETE', + url: '/delete_training/', + data: { + 'training_id': training_id + }, + success: function (data) { + data = JSON.parse(data); + if (data['success_message']) { + alert(data['success_message']); + window.location.href = data['redirect_path']; + } + }, + error: function (data) { + alert("Failed to delete training."); + } + }); + }); + } +} + +function getCookie(c_name) { + if (document.cookie.length > 0) { + c_start = document.cookie.indexOf(c_name + "="); + if (c_start != -1) { + c_start = c_start + c_name.length + 1; + c_end = document.cookie.indexOf(";", c_start); + if (c_end == -1) c_end = document.cookie.length; + return unescape(document.cookie.substring(c_start, c_end)); + } + } + return ""; +} + diff --git a/static/js/trainingportal/training_status.js b/static/js/trainingportal/training_status.js new file mode 100644 index 0000000..857de74 --- /dev/null +++ b/static/js/trainingportal/training_status.js @@ -0,0 +1,26 @@ +/** + * Created by shafaqat on 2/21/18. + */ + +function update_training_status(training_id) { + $(document).ready(function () { + $.ajax({ + type: 'POST', + url: '/training_status/', + data: { + 'training_id': training_id + }, + success: function (data) { + data = JSON.parse(data); + if (data['success_message']) { + $('#' + training_id).attr('disabled', 'disabled'); + $('#status_' + training_id).text('Completed'); + + } + }, + error: function (data) { + alert("Failed to update training status."); + } + }); + }); +} diff --git a/trainingportal/__pycache__/__init__.cpython-35.pyc b/trainingportal/__pycache__/__init__.cpython-35.pyc deleted file mode 100644 index 4c6a58c..0000000 Binary files a/trainingportal/__pycache__/__init__.cpython-35.pyc and /dev/null differ diff --git a/trainingportal/__pycache__/forms.cpython-35.pyc b/trainingportal/__pycache__/forms.cpython-35.pyc deleted file mode 100644 index 3f369f5..0000000 Binary files a/trainingportal/__pycache__/forms.cpython-35.pyc and /dev/null differ diff --git a/trainingportal/__pycache__/models.cpython-35.pyc b/trainingportal/__pycache__/models.cpython-35.pyc deleted file mode 100644 index f553eeb..0000000 Binary files a/trainingportal/__pycache__/models.cpython-35.pyc and /dev/null differ diff --git a/trainingportal/__pycache__/settings.cpython-35.pyc b/trainingportal/__pycache__/settings.cpython-35.pyc deleted file mode 100644 index ab7f5d8..0000000 Binary files a/trainingportal/__pycache__/settings.cpython-35.pyc and /dev/null differ diff --git a/trainingportal/__pycache__/urls.cpython-35.pyc b/trainingportal/__pycache__/urls.cpython-35.pyc deleted file mode 100644 index da5eb59..0000000 Binary files a/trainingportal/__pycache__/urls.cpython-35.pyc and /dev/null differ diff --git a/trainingportal/__pycache__/views.cpython-35.pyc b/trainingportal/__pycache__/views.cpython-35.pyc deleted file mode 100644 index 191f794..0000000 Binary files a/trainingportal/__pycache__/views.cpython-35.pyc and /dev/null differ diff --git a/trainingportal/__pycache__/wsgi.cpython-35.pyc b/trainingportal/__pycache__/wsgi.cpython-35.pyc deleted file mode 100644 index fed80c6..0000000 Binary files a/trainingportal/__pycache__/wsgi.cpython-35.pyc and /dev/null differ diff --git a/trainingportal/forms.py b/trainingportal/forms.py index b433b60..295aaf1 100644 --- a/trainingportal/forms.py +++ b/trainingportal/forms.py @@ -1,16 +1,18 @@ from django import forms -from .models import Trainee from django.contrib.auth.forms import User from django.utils.translation import ugettext_lazy as _ from django.utils.safestring import mark_safe from django.core.exceptions import ValidationError -import re from django.core.validators import validate_email +import re + +from .models import Trainee, Training, AssignedTraining, Assignment, Task + class LoginForm(forms.Form): - username = forms.CharField(required=True, widget=forms.TextInput(attrs={'class':'form-control'})) - password = forms.CharField(required=True, widget=forms.PasswordInput(attrs={'class':'form-control'})) + username = forms.CharField(required=True, widget=forms.TextInput(attrs={'class': 'form-control'})) + password = forms.CharField(required=True, widget=forms.PasswordInput(attrs={'class': 'form-control'})) def clean_username(self): username = self.cleaned_data.get("username") @@ -28,8 +30,8 @@ def clean_password(self): else: return password -class ProfileForm(forms.ModelForm): +class ProfileForm(forms.ModelForm): class Meta: model = Trainee @@ -39,23 +41,23 @@ class Meta: def __init__(self, *args, **kwargs): super(ProfileForm, self).__init__(*args, **kwargs) - self.fields['designation'].required=False + self.fields['designation'].required = False - def save(self, user): + def save(self, *args, **kwargs): profile = super(ProfileForm, self).save(commit=False) - profile.user = user + profile.user = kwargs['user'] profile.save() return profile def clean_designation(self): designation = self.cleaned_data.get("designation") if not designation: - raise forms.ValidationError("Designation field is required.", code='invalid') + raise forms.ValidationError("Designation field is required.", code='invalid') else: return designation -class UserForm(forms.ModelForm): +class UserForm(forms.ModelForm): class Meta: model = User @@ -70,8 +72,8 @@ class Meta: 'password': forms.PasswordInput(), } # error_messages = { - # 'first_name': { - # 'required': _("This writer's name is too long.")} + # 'password': { + # 'required': _("This writer's password required.")} # } # def validate_even(self, value): @@ -83,19 +85,19 @@ class Meta: def __init__(self, *args, **kwargs): super(UserForm, self).__init__(*args, **kwargs) - self.fields['first_name'].required=True - self.fields['last_name'].required=True - self.fields['email'].required=True - #self.fields['username'].validators=[self.validate_even] + self.fields['first_name'].required = True + self.fields['last_name'].required = True + self.fields['email'].required = True + # self.fields['username'].validators=[self.validate_even] self.fields['username'].help_text = "" - #self.fields['username'].error_messages = {'required': 'Username field is required.'} - self.fields['password'].required=True + # self.fields['username'].error_messages = {'required': 'Username field is required.'} + self.fields['password'].required = True def clean_first_name(self): first_name = self.cleaned_data.get("first_name") if not re.match(r'^[A-Za-z ]+$', first_name): raise forms.ValidationError("Special characters or numbers are not valid.", - code = 'invalid') + code='invalid') else: return first_name @@ -103,7 +105,7 @@ def clean_last_name(self): last_name = self.cleaned_data.get("last_name") if not re.match(r'^[A-Za-z ]+$', last_name): raise forms.ValidationError("Special characters or numbers are not valid.", - code = 'invalid') + code='invalid') else: return last_name @@ -121,4 +123,208 @@ def clean_email(self): raise forms.ValidationError("Email ID field is required.", code='invalid') else: - return email \ No newline at end of file + return email + + +class AddTrainingForm(forms.ModelForm): + class Meta: + + model = Training + fields = '__all__' + + widgets = { + 'title': forms.TextInput(attrs={'class': 'form-control'}), + 'description': forms.Textarea(attrs={'class': 'form-control'}), + 'due_date': forms.TextInput(attrs={'type': 'date', 'class': 'form-control'}), + 'document': forms.FileInput(attrs={'class': 'form-control'}) + } + + def __init__(self, *args, **kwargs): + super(AddTrainingForm, self).__init__(*args, **kwargs) + self.fields['document'].required = False + + def clean_due_date(self): + due_date = self.cleaned_data.get("due_date") + if not due_date: + raise forms.ValidationError("Due date field is required.", + code='invalid') + else: + return due_date + + def clean_title(self): + title = self.cleaned_data.get("title") + if not title: + raise forms.ValidationError("Title field is required.", + code='invalid') + else: + return title + + def clean_description(self): + description = self.cleaned_data.get("description") + if not description: + raise forms.ValidationError("Description field is required.", + code='invalid') + else: + return description + + +class TaskForm(forms.ModelForm): + class Meta: + + model = Task + + fields = [ + 'title', + 'description' + ] + + widgets = { + 'title': forms.TextInput(attrs={'class': 'form-control'}), + 'description': forms.Textarea(attrs={'class': 'form-control'}), + } + + def clean_title(self): + title = self.cleaned_data.get("title") + if not title: + raise forms.ValidationError("Title field is required.", + code='invalid') + else: + return title + + def clean_description(self): + description = self.cleaned_data.get("description") + if not description: + raise forms.ValidationError("Description field is required.", + code='invalid') + else: + return description + + +class AssignmentForm(forms.ModelForm): + class Meta: + + model = Assignment + + fields = [ + 'title', + 'description', + 'assignment_file_path', + 'due_date' + ] + + widgets = { + 'title': forms.TextInput(attrs={'class': 'form-control'}), + 'description': forms.Textarea(attrs={'class': 'form-control'}), + 'due_date': forms.TextInput(attrs={'type': 'date', 'class': 'form-control'}), + 'assignment_file_path': forms.FileInput(attrs={'class': 'form-control'}) + } + + def __init__(self, *args, **kwargs): + super(AssignmentForm, self).__init__(*args, **kwargs) + self.fields['assignment_file_path'].required = False + + def clean_due_date(self): + due_date = self.cleaned_data.get("due_date") + if not due_date: + raise forms.ValidationError("Due date field is required.", + code='invalid') + else: + return due_date + + def clean_title(self): + title = self.cleaned_data.get("title") + if not title: + raise forms.ValidationError("Title field is required.", + code='invalid') + else: + return title + + def clean_description(self): + description = self.cleaned_data.get("description") + if not description: + raise forms.ValidationError("Description field is required.", + code='invalid') + else: + return description + +class SubmitAssignmentForm(forms.ModelForm): + + class Meta: + + model = Assignment + + fields = [ + 'title', + 'description', + 'assignment_submission_path', + 'due_date' + ] + + widgets = { + 'title': forms.TextInput(attrs={'class': 'form-control', + 'disabled': 'disabled'}), + 'description': forms.Textarea(attrs={'class': 'form-control', + 'disabled': 'disabled'}), + 'due_date': forms.TextInput(attrs={'type': 'date', 'class': 'form-control', + 'disabled': 'disabled'}), + 'assignment_submission_path': forms.FileInput(attrs={'class': 'form-control'}) + } + + def __init__(self, *args, **kwargs): + super(SubmitAssignmentForm, self).__init__(*args, **kwargs) + self.fields['assignment_submission_path'].required = True + self.fields['due_date'].required = False + self.fields['description'].required = False + self.fields['title'].required = False + + +class EvaluateAssignmentForm(forms.ModelForm): + class Meta: + + model = Assignment + + fields = [ + 'title', + 'description', + 'due_date', + 'assignment_submission_path', + 'score', + 'remarks' + ] + + widgets = { + 'title': forms.TextInput(attrs={'class': 'form-control', + 'disabled': 'disabled'}), + 'description': forms.Textarea(attrs={'class': 'form-control', + 'disabled': 'disabled'}), + 'due_date': forms.TextInput(attrs={'type': 'date', 'class': 'form-control', + 'disabled': 'disabled'}), + 'score': forms.NumberInput(attrs={'step': "0.5", + 'class': 'form-control'}), + 'assignment_submission_path': forms.TextInput(attrs={'class': 'form-control', + 'disabled': 'disabled'}), + 'remarks': forms.Textarea(attrs={'class': 'form-control'}), + } + + def __init__(self, *args, **kwargs): + super(EvaluateAssignmentForm, self).__init__(*args, **kwargs) + self.fields['assignment_submission_path'].required = False + self.fields['due_date'].required = False + self.fields['description'].required = False + self.fields['title'].required = False + + def clean_score(self): + score = self.cleaned_data.get("score") + if not score: + raise forms.ValidationError("Score field is required.", + code='invalid') + else: + return score + + def clean_remarks(self): + remarks = self.cleaned_data.get("remarks") + if not remarks: + raise forms.ValidationError("Remarks field is required.", + code='invalid') + else: + return remarks diff --git a/trainingportal/migrations/0001_initial.py b/trainingportal/migrations/0001_initial.py index fad6105..21ac07f 100644 --- a/trainingportal/migrations/0001_initial.py +++ b/trainingportal/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.2 on 2018-02-12 12:45 +# Generated by Django 2.0.2 on 2018-02-19 12:39 from django.conf import settings from django.db import migrations, models @@ -25,12 +25,29 @@ class Migration(migrations.Migration): name='Assignment', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('due_date', models.DurationField(null=True)), + ('due_date', models.DateField(null=True)), ('remarks', models.CharField(max_length=30, null=True)), ('score', models.FloatField(null=True)), ('assignment_submission_path', models.FileField(null=True, upload_to='solution_uploads/')), ], ), + migrations.CreateModel( + name='Snippet', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(auto_now_add=True)), + ('title', models.CharField(blank=True, default='', max_length=100)), + ('code', models.TextField()), + ('linenos', models.BooleanField(default=False)), + ('language', models.CharField(choices=[('abap', 'ABAP'), ('abnf', 'ABNF'), ('ada', 'Ada'), ('adl', 'ADL'), ('agda', 'Agda'), ('aheui', 'Aheui'), ('ahk', 'autohotkey'), ('alloy', 'Alloy'), ('ampl', 'Ampl'), ('antlr', 'ANTLR'), ('antlr-as', 'ANTLR With ActionScript Target'), ('antlr-cpp', 'ANTLR With CPP Target'), ('antlr-csharp', 'ANTLR With C# Target'), ('antlr-java', 'ANTLR With Java Target'), ('antlr-objc', 'ANTLR With ObjectiveC Target'), ('antlr-perl', 'ANTLR With Perl Target'), ('antlr-python', 'ANTLR With Python Target'), ('antlr-ruby', 'ANTLR With Ruby Target'), ('apacheconf', 'ApacheConf'), ('apl', 'APL'), ('applescript', 'AppleScript'), ('arduino', 'Arduino'), ('as', 'ActionScript'), ('as3', 'ActionScript 3'), ('aspectj', 'AspectJ'), ('aspx-cs', 'aspx-cs'), ('aspx-vb', 'aspx-vb'), ('asy', 'Asymptote'), ('at', 'AmbientTalk'), ('autoit', 'AutoIt'), ('awk', 'Awk'), ('basemake', 'Base Makefile'), ('bash', 'Bash'), ('bat', 'Batchfile'), ('bbcode', 'BBCode'), ('bc', 'BC'), ('befunge', 'Befunge'), ('bib', 'BibTeX'), ('blitzbasic', 'BlitzBasic'), ('blitzmax', 'BlitzMax'), ('bnf', 'BNF'), ('boo', 'Boo'), ('boogie', 'Boogie'), ('brainfuck', 'Brainfuck'), ('bro', 'Bro'), ('bst', 'BST'), ('bugs', 'BUGS'), ('c', 'C'), ('c-objdump', 'c-objdump'), ('ca65', 'ca65 assembler'), ('cadl', 'cADL'), ('camkes', 'CAmkES'), ('capdl', 'CapDL'), ('capnp', "Cap'n Proto"), ('cbmbas', 'CBM BASIC V2'), ('ceylon', 'Ceylon'), ('cfc', 'Coldfusion CFC'), ('cfengine3', 'CFEngine3'), ('cfm', 'Coldfusion HTML'), ('cfs', 'cfstatement'), ('chai', 'ChaiScript'), ('chapel', 'Chapel'), ('cheetah', 'Cheetah'), ('cirru', 'Cirru'), ('clay', 'Clay'), ('clean', 'Clean'), ('clojure', 'Clojure'), ('clojurescript', 'ClojureScript'), ('cmake', 'CMake'), ('cobol', 'COBOL'), ('cobolfree', 'COBOLFree'), ('coffee-script', 'CoffeeScript'), ('common-lisp', 'Common Lisp'), ('componentpascal', 'Component Pascal'), ('console', 'Bash Session'), ('control', 'Debian Control file'), ('coq', 'Coq'), ('cpp', 'C++'), ('cpp-objdump', 'cpp-objdump'), ('cpsa', 'CPSA'), ('cr', 'Crystal'), ('crmsh', 'Crmsh'), ('croc', 'Croc'), ('cryptol', 'Cryptol'), ('csharp', 'C#'), ('csound', 'Csound Orchestra'), ('csound-document', 'Csound Document'), ('csound-score', 'Csound Score'), ('css', 'CSS'), ('css+django', 'CSS+Django/Jinja'), ('css+erb', 'CSS+Ruby'), ('css+genshitext', 'CSS+Genshi Text'), ('css+lasso', 'CSS+Lasso'), ('css+mako', 'CSS+Mako'), ('css+mozpreproc', 'CSS+mozpreproc'), ('css+myghty', 'CSS+Myghty'), ('css+php', 'CSS+PHP'), ('css+smarty', 'CSS+Smarty'), ('cucumber', 'Gherkin'), ('cuda', 'CUDA'), ('cypher', 'Cypher'), ('cython', 'Cython'), ('d', 'D'), ('d-objdump', 'd-objdump'), ('dart', 'Dart'), ('delphi', 'Delphi'), ('dg', 'dg'), ('diff', 'Diff'), ('django', 'Django/Jinja'), ('docker', 'Docker'), ('doscon', 'MSDOS Session'), ('dpatch', 'Darcs Patch'), ('dtd', 'DTD'), ('duel', 'Duel'), ('dylan', 'Dylan'), ('dylan-console', 'Dylan session'), ('dylan-lid', 'DylanLID'), ('earl-grey', 'Earl Grey'), ('easytrieve', 'Easytrieve'), ('ebnf', 'EBNF'), ('ec', 'eC'), ('ecl', 'ECL'), ('eiffel', 'Eiffel'), ('elixir', 'Elixir'), ('elm', 'Elm'), ('emacs', 'EmacsLisp'), ('erb', 'ERB'), ('erl', 'Erlang erl session'), ('erlang', 'Erlang'), ('evoque', 'Evoque'), ('extempore', 'xtlang'), ('ezhil', 'Ezhil'), ('factor', 'Factor'), ('fan', 'Fantom'), ('fancy', 'Fancy'), ('felix', 'Felix'), ('fish', 'Fish'), ('flatline', 'Flatline'), ('forth', 'Forth'), ('fortran', 'Fortran'), ('fortranfixed', 'FortranFixed'), ('foxpro', 'FoxPro'), ('fsharp', 'FSharp'), ('gap', 'GAP'), ('gas', 'GAS'), ('genshi', 'Genshi'), ('genshitext', 'Genshi Text'), ('glsl', 'GLSL'), ('gnuplot', 'Gnuplot'), ('go', 'Go'), ('golo', 'Golo'), ('gooddata-cl', 'GoodData-CL'), ('gosu', 'Gosu'), ('groff', 'Groff'), ('groovy', 'Groovy'), ('gst', 'Gosu Template'), ('haml', 'Haml'), ('handlebars', 'Handlebars'), ('haskell', 'Haskell'), ('haxeml', 'Hxml'), ('hexdump', 'Hexdump'), ('hsail', 'HSAIL'), ('html', 'HTML'), ('html+cheetah', 'HTML+Cheetah'), ('html+django', 'HTML+Django/Jinja'), ('html+evoque', 'HTML+Evoque'), ('html+genshi', 'HTML+Genshi'), ('html+handlebars', 'HTML+Handlebars'), ('html+lasso', 'HTML+Lasso'), ('html+mako', 'HTML+Mako'), ('html+myghty', 'HTML+Myghty'), ('html+ng2', 'HTML + Angular2'), ('html+php', 'HTML+PHP'), ('html+smarty', 'HTML+Smarty'), ('html+twig', 'HTML+Twig'), ('html+velocity', 'HTML+Velocity'), ('http', 'HTTP'), ('hx', 'Haxe'), ('hybris', 'Hybris'), ('hylang', 'Hy'), ('i6t', 'Inform 6 template'), ('idl', 'IDL'), ('idris', 'Idris'), ('iex', 'Elixir iex session'), ('igor', 'Igor'), ('inform6', 'Inform 6'), ('inform7', 'Inform 7'), ('ini', 'INI'), ('io', 'Io'), ('ioke', 'Ioke'), ('irc', 'IRC logs'), ('isabelle', 'Isabelle'), ('j', 'J'), ('jags', 'JAGS'), ('jasmin', 'Jasmin'), ('java', 'Java'), ('javascript+mozpreproc', 'Javascript+mozpreproc'), ('jcl', 'JCL'), ('jlcon', 'Julia console'), ('js', 'JavaScript'), ('js+cheetah', 'JavaScript+Cheetah'), ('js+django', 'JavaScript+Django/Jinja'), ('js+erb', 'JavaScript+Ruby'), ('js+genshitext', 'JavaScript+Genshi Text'), ('js+lasso', 'JavaScript+Lasso'), ('js+mako', 'JavaScript+Mako'), ('js+myghty', 'JavaScript+Myghty'), ('js+php', 'JavaScript+PHP'), ('js+smarty', 'JavaScript+Smarty'), ('jsgf', 'JSGF'), ('json', 'JSON'), ('json-object', 'JSONBareObject'), ('jsonld', 'JSON-LD'), ('jsp', 'Java Server Page'), ('julia', 'Julia'), ('juttle', 'Juttle'), ('kal', 'Kal'), ('kconfig', 'Kconfig'), ('koka', 'Koka'), ('kotlin', 'Kotlin'), ('lagda', 'Literate Agda'), ('lasso', 'Lasso'), ('lcry', 'Literate Cryptol'), ('lean', 'Lean'), ('less', 'LessCss'), ('lhs', 'Literate Haskell'), ('lidr', 'Literate Idris'), ('lighty', 'Lighttpd configuration file'), ('limbo', 'Limbo'), ('liquid', 'liquid'), ('live-script', 'LiveScript'), ('llvm', 'LLVM'), ('logos', 'Logos'), ('logtalk', 'Logtalk'), ('lsl', 'LSL'), ('lua', 'Lua'), ('make', 'Makefile'), ('mako', 'Mako'), ('maql', 'MAQL'), ('mask', 'Mask'), ('mason', 'Mason'), ('mathematica', 'Mathematica'), ('matlab', 'Matlab'), ('matlabsession', 'Matlab session'), ('md', 'markdown'), ('minid', 'MiniD'), ('modelica', 'Modelica'), ('modula2', 'Modula-2'), ('monkey', 'Monkey'), ('monte', 'Monte'), ('moocode', 'MOOCode'), ('moon', 'MoonScript'), ('mozhashpreproc', 'mozhashpreproc'), ('mozpercentpreproc', 'mozpercentpreproc'), ('mql', 'MQL'), ('mscgen', 'Mscgen'), ('mupad', 'MuPAD'), ('mxml', 'MXML'), ('myghty', 'Myghty'), ('mysql', 'MySQL'), ('nasm', 'NASM'), ('ncl', 'NCL'), ('nemerle', 'Nemerle'), ('nesc', 'nesC'), ('newlisp', 'NewLisp'), ('newspeak', 'Newspeak'), ('ng2', 'Angular2'), ('nginx', 'Nginx configuration file'), ('nim', 'Nimrod'), ('nit', 'Nit'), ('nixos', 'Nix'), ('nsis', 'NSIS'), ('numpy', 'NumPy'), ('nusmv', 'NuSMV'), ('objdump', 'objdump'), ('objdump-nasm', 'objdump-nasm'), ('objective-c', 'Objective-C'), ('objective-c++', 'Objective-C++'), ('objective-j', 'Objective-J'), ('ocaml', 'OCaml'), ('octave', 'Octave'), ('odin', 'ODIN'), ('ooc', 'Ooc'), ('opa', 'Opa'), ('openedge', 'OpenEdge ABL'), ('pacmanconf', 'PacmanConf'), ('pan', 'Pan'), ('parasail', 'ParaSail'), ('pawn', 'Pawn'), ('perl', 'Perl'), ('perl6', 'Perl6'), ('php', 'PHP'), ('pig', 'Pig'), ('pike', 'Pike'), ('pkgconfig', 'PkgConfig'), ('plpgsql', 'PL/pgSQL'), ('postgresql', 'PostgreSQL SQL dialect'), ('postscript', 'PostScript'), ('pot', 'Gettext Catalog'), ('pov', 'POVRay'), ('powershell', 'PowerShell'), ('praat', 'Praat'), ('prolog', 'Prolog'), ('properties', 'Properties'), ('protobuf', 'Protocol Buffer'), ('ps1con', 'PowerShell Session'), ('psql', 'PostgreSQL console (psql)'), ('pug', 'Pug'), ('puppet', 'Puppet'), ('py3tb', 'Python 3.0 Traceback'), ('pycon', 'Python console session'), ('pypylog', 'PyPy Log'), ('pytb', 'Python Traceback'), ('python', 'Python'), ('python3', 'Python 3'), ('qbasic', 'QBasic'), ('qml', 'QML'), ('qvto', 'QVTO'), ('racket', 'Racket'), ('ragel', 'Ragel'), ('ragel-c', 'Ragel in C Host'), ('ragel-cpp', 'Ragel in CPP Host'), ('ragel-d', 'Ragel in D Host'), ('ragel-em', 'Embedded Ragel'), ('ragel-java', 'Ragel in Java Host'), ('ragel-objc', 'Ragel in Objective C Host'), ('ragel-ruby', 'Ragel in Ruby Host'), ('raw', 'Raw token data'), ('rb', 'Ruby'), ('rbcon', 'Ruby irb session'), ('rconsole', 'RConsole'), ('rd', 'Rd'), ('rebol', 'REBOL'), ('red', 'Red'), ('redcode', 'Redcode'), ('registry', 'reg'), ('resource', 'ResourceBundle'), ('rexx', 'Rexx'), ('rhtml', 'RHTML'), ('rnc', 'Relax-NG Compact'), ('roboconf-graph', 'Roboconf Graph'), ('roboconf-instances', 'Roboconf Instances'), ('robotframework', 'RobotFramework'), ('rql', 'RQL'), ('rsl', 'RSL'), ('rst', 'reStructuredText'), ('rts', 'TrafficScript'), ('rust', 'Rust'), ('sas', 'SAS'), ('sass', 'Sass'), ('sc', 'SuperCollider'), ('scala', 'Scala'), ('scaml', 'Scaml'), ('scheme', 'Scheme'), ('scilab', 'Scilab'), ('scss', 'SCSS'), ('shen', 'Shen'), ('silver', 'Silver'), ('slim', 'Slim'), ('smali', 'Smali'), ('smalltalk', 'Smalltalk'), ('smarty', 'Smarty'), ('sml', 'Standard ML'), ('snobol', 'Snobol'), ('snowball', 'Snowball'), ('sourceslist', 'Debian Sourcelist'), ('sp', 'SourcePawn'), ('sparql', 'SPARQL'), ('spec', 'RPMSpec'), ('splus', 'S'), ('sql', 'SQL'), ('sqlite3', 'sqlite3con'), ('squidconf', 'SquidConf'), ('ssp', 'Scalate Server Page'), ('stan', 'Stan'), ('stata', 'Stata'), ('swift', 'Swift'), ('swig', 'SWIG'), ('systemverilog', 'systemverilog'), ('tads3', 'TADS 3'), ('tap', 'TAP'), ('tasm', 'TASM'), ('tcl', 'Tcl'), ('tcsh', 'Tcsh'), ('tcshcon', 'Tcsh Session'), ('tea', 'Tea'), ('termcap', 'Termcap'), ('terminfo', 'Terminfo'), ('terraform', 'Terraform'), ('tex', 'TeX'), ('text', 'Text only'), ('thrift', 'Thrift'), ('todotxt', 'Todotxt'), ('trac-wiki', 'MoinMoin/Trac Wiki markup'), ('treetop', 'Treetop'), ('ts', 'TypeScript'), ('tsql', 'Transact-SQL'), ('turtle', 'Turtle'), ('twig', 'Twig'), ('typoscript', 'TypoScript'), ('typoscriptcssdata', 'TypoScriptCssData'), ('typoscripthtmldata', 'TypoScriptHtmlData'), ('urbiscript', 'UrbiScript'), ('vala', 'Vala'), ('vb.net', 'VB.net'), ('vcl', 'VCL'), ('vclsnippets', 'VCLSnippets'), ('vctreestatus', 'VCTreeStatus'), ('velocity', 'Velocity'), ('verilog', 'verilog'), ('vgl', 'VGL'), ('vhdl', 'vhdl'), ('vim', 'VimL'), ('wdiff', 'WDiff'), ('whiley', 'Whiley'), ('x10', 'X10'), ('xml', 'XML'), ('xml+cheetah', 'XML+Cheetah'), ('xml+django', 'XML+Django/Jinja'), ('xml+erb', 'XML+Ruby'), ('xml+evoque', 'XML+Evoque'), ('xml+lasso', 'XML+Lasso'), ('xml+mako', 'XML+Mako'), ('xml+myghty', 'XML+Myghty'), ('xml+php', 'XML+PHP'), ('xml+smarty', 'XML+Smarty'), ('xml+velocity', 'XML+Velocity'), ('xquery', 'XQuery'), ('xslt', 'XSLT'), ('xtend', 'Xtend'), ('xul+mozpreproc', 'XUL+mozpreproc'), ('yaml', 'YAML'), ('yaml+jinja', 'YAML+Jinja'), ('zephir', 'Zephir')], default='python', max_length=100)), + ('style', models.CharField(choices=[('abap', 'abap'), ('algol', 'algol'), ('algol_nu', 'algol_nu'), ('arduino', 'arduino'), ('autumn', 'autumn'), ('borland', 'borland'), ('bw', 'bw'), ('colorful', 'colorful'), ('default', 'default'), ('emacs', 'emacs'), ('friendly', 'friendly'), ('fruity', 'fruity'), ('igor', 'igor'), ('lovelace', 'lovelace'), ('manni', 'manni'), ('monokai', 'monokai'), ('murphy', 'murphy'), ('native', 'native'), ('paraiso-dark', 'paraiso-dark'), ('paraiso-light', 'paraiso-light'), ('pastie', 'pastie'), ('perldoc', 'perldoc'), ('rainbow_dash', 'rainbow_dash'), ('rrt', 'rrt'), ('tango', 'tango'), ('trac', 'trac'), ('vim', 'vim'), ('vs', 'vs'), ('xcode', 'xcode')], default='friendly', max_length=100)), + ('highlighted', models.TextField()), + ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='snippets', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ('created',), + }, + ), migrations.CreateModel( name='Task', fields=[ @@ -65,7 +82,7 @@ class Migration(migrations.Migration): ('title', models.CharField(max_length=30)), ('description', models.CharField(max_length=30)), ('document', models.FileField(null=True, upload_to='tasks_uploads/')), - ('duration', models.DurationField(null=True)), + ('due_date', models.DateField(null=True)), ], ), migrations.AddField( diff --git a/trainingportal/migrations/0002_auto_20180221_1304.py b/trainingportal/migrations/0002_auto_20180221_1304.py new file mode 100644 index 0000000..21f9ae8 --- /dev/null +++ b/trainingportal/migrations/0002_auto_20180221_1304.py @@ -0,0 +1,32 @@ +# Generated by Django 2.0.2 on 2018-02-21 13:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('trainingportal', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='task', + name='assignment_file_path', + ), + migrations.AddField( + model_name='assignment', + name='assignment_file_path', + field=models.FileField(null=True, upload_to='tasks_uploads/'), + ), + migrations.AddField( + model_name='assignment', + name='description', + field=models.CharField(default=' ', max_length=30), + ), + migrations.AddField( + model_name='assignment', + name='title', + field=models.CharField(default=' ', max_length=30), + ), + ] diff --git a/trainingportal/migrations/0003_assignment_status.py b/trainingportal/migrations/0003_assignment_status.py new file mode 100644 index 0000000..5f187f9 --- /dev/null +++ b/trainingportal/migrations/0003_assignment_status.py @@ -0,0 +1,18 @@ +# Generated by Django 2.0.2 on 2018-02-22 07:28 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('trainingportal', '0002_auto_20180221_1304'), + ] + + operations = [ + migrations.AddField( + model_name='assignment', + name='status', + field=models.BooleanField(default=False), + ), + ] diff --git a/trainingportal/migrations/__pycache__/0001_initial.cpython-35.pyc b/trainingportal/migrations/__pycache__/0001_initial.cpython-35.pyc deleted file mode 100644 index 2afbc62..0000000 Binary files a/trainingportal/migrations/__pycache__/0001_initial.cpython-35.pyc and /dev/null differ diff --git a/trainingportal/migrations/__pycache__/__init__.cpython-35.pyc b/trainingportal/migrations/__pycache__/__init__.cpython-35.pyc deleted file mode 100644 index 7ac2c8d..0000000 Binary files a/trainingportal/migrations/__pycache__/__init__.cpython-35.pyc and /dev/null differ diff --git a/trainingportal/models.py b/trainingportal/models.py index ad12580..53b0189 100644 --- a/trainingportal/models.py +++ b/trainingportal/models.py @@ -1,6 +1,44 @@ from django.db import models from django.contrib.auth.models import User +from pygments.lexers import get_all_lexers +from pygments.styles import get_all_styles +from pygments.formatters.html import HtmlFormatter +from pygments import highlight +from pygments.lexers import get_lexer_by_name + + +LEXERS = [item for item in get_all_lexers() if item[1]] +LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS]) +STYLE_CHOICES = sorted((item, item) for item in get_all_styles()) + + +class Snippet(models.Model): + created = models.DateTimeField(auto_now_add=True) + title = models.CharField(max_length=100, blank=True, default='') + code = models.TextField() + linenos = models.BooleanField(default=False) + language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100) + style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100) + owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE) + highlighted = models.TextField() + + class Meta: + ordering = ('created',) + + def save(self, *args, **kwargs): + """ + Use the `pygments` library to create a highlighted HTML + representation of the code snippet. + """ + lexer = get_lexer_by_name(self.language) + linenos = self.linenos and 'table' or False + options = self.title and {'title': self.title} or {} + formatter = HtmlFormatter(style=self.style, linenos=linenos, + full=True, **options) + self.highlighted = highlight(self.code, lexer, formatter) + super(Snippet, self).save(*args, **kwargs) + class Trainee(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) @@ -18,7 +56,7 @@ class Training(models.Model): title = models.CharField(max_length=30, null=False, blank=False) description = models.CharField(max_length=30, null=False, blank=False) document = models.FileField(upload_to='tasks_uploads/', null=True) - duration = models.DurationField(null=True) + due_date = models.DateField(null=True) class AssignedTraining(models.Model): @@ -31,7 +69,6 @@ class AssignedTraining(models.Model): class Task(models.Model): title = models.CharField(max_length=30, null=False, blank=False) description = models.CharField(max_length=30, null=False, blank=False) - assignment_file_path = models.FileField(upload_to='tasks_uploads/', null=True) training_id = models.ForeignKey(Training, on_delete=models.CASCADE) trainer_id = models.ForeignKey(Trainer, on_delete=models.CASCADE) trainee_id = models.ForeignKey(Trainee, on_delete=models.CASCADE) @@ -39,7 +76,11 @@ class Task(models.Model): class Assignment(models.Model): task_id = models.ForeignKey(Task, on_delete=models.CASCADE) - due_date = models.DurationField(null=True) + title = models.CharField(max_length=30, null=False, blank=False, default=" ") + description = models.CharField(max_length=30, null=False, blank=False, default=" ") + due_date = models.DateField(null=True) remarks = models.CharField(max_length=30, null=True) score = models.FloatField(null=True) - assignment_submission_path = models.FileField(upload_to='solution_uploads/', null=True) \ No newline at end of file + assignment_submission_path = models.FileField(upload_to='solution_uploads/', null=True) + assignment_file_path = models.FileField(upload_to='tasks_uploads/', null=True) + status = models.BooleanField(null=False, blank=False, default=False) diff --git a/trainingportal/serializers.py b/trainingportal/serializers.py new file mode 100644 index 0000000..f1ca9c7 --- /dev/null +++ b/trainingportal/serializers.py @@ -0,0 +1,70 @@ +from django.contrib.auth.models import User, Group +from rest_framework import serializers +from .models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES + + +class SnippetModelSerializer(serializers.ModelSerializer): + """ModelSerializing example (same as modelform class)""" + + class Meta: + model = Snippet + fields = ('id', 'title', 'code', 'linenos', 'language', 'style') + +class SnippetSerializer(serializers.HyperlinkedModelSerializer): + owner = serializers.ReadOnlyField(source='owner.username') + highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html') + + class Meta: + model = Snippet + fields = ('url', 'id', 'highlight', 'owner', + 'title', 'code', 'linenos', 'language', 'style') + + +class UserSerializer(serializers.HyperlinkedModelSerializer): + snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True) + + class Meta: + model = User + fields = ('url', 'id', 'username', 'snippets') + +# +# class SnippetSerializer(serializers.Serializer): +# """Serializing example (same as form class)""" +# +# id = serializers.IntegerField(read_only=True) +# title = serializers.CharField(required=False, allow_blank=True, max_length=100) +# code = serializers.CharField(style={'base_template': 'textarea.html'}) +# linenos = serializers.BooleanField(required=False) +# language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python') +# style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly') +# owner = serializers.ReadOnlyField(source='owner.username') +# +# def create(self, validated_data): +# """ +# Create and return a new `Snippet` instance, given the validated data. +# """ +# return Snippet.objects.create(**validated_data) +# +# def update(self, instance, validated_data): +# """ +# Update and return an existing `Snippet` instance, given the validated data. +# """ +# instance.title = validated_data.get('title', instance.title) +# instance.code = validated_data.get('code', instance.code) +# instance.linenos = validated_data.get('linenos', instance.linenos) +# instance.language = validated_data.get('language', instance.language) +# instance.style = validated_data.get('style', instance.style) +# instance.save() +# return instance + + +# class UserSerializer(serializers.HyperlinkedModelSerializer): +# class Meta: +# model = User +# fields = ('url', 'username', 'email', 'groups') + + +class GroupSerializer(serializers.HyperlinkedModelSerializer): + class Meta: + model = Group + fields = ('url', 'name') \ No newline at end of file diff --git a/trainingportal/settings.py b/trainingportal/settings.py index 4307349..38ab63e 100644 --- a/trainingportal/settings.py +++ b/trainingportal/settings.py @@ -39,8 +39,19 @@ 'django.contrib.staticfiles', 'bootstrap3', 'trainingportal', + 'rest_framework', ] +REST_FRAMEWORK = { + # Use Django's standard `django.contrib.auth` permissions, + # or allow read-only access for unauthenticated users. + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly', + 'rest_framework.permissions.DjangoModelPermissions', + + ] +} + MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -53,9 +64,9 @@ ROOT_URLCONF = 'trainingportal.urls' -MEDIA_ROOT = '/home/shafaqat/PycharmProjects/training/venv2/trainingportal/trainingportal/' +MEDIA_ROOT = os.path.join(BASE_DIR, 'trainingportal') -MEDIA_URL = 'http://media.trainingportal.com/' +MEDIA_URL = '/tasks_uploads/'#'http://media.trainingportal.com/' TEMPLATES = [ { diff --git a/trainingportal/solution_uploads/1.json b/trainingportal/solution_uploads/1.json new file mode 100644 index 0000000..856df97 --- /dev/null +++ b/trainingportal/solution_uploads/1.json @@ -0,0 +1,22 @@ +"MODULESTORE": { + "default": { + "ENGINE": "xmodule.modulestore.mixed.MixedModuleStore", + "OPTIONS": { + "mappings": {}, + "stores": [ + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore", + "NAME": "split", + "OPTIONS": {...settings...} + }, + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.mongo.DraftMongoModuleStore", + "NAME": "draft", + "OPTIONS": {...settings...} + } + ] + } + } + }, diff --git a/trainingportal/tasks_uploads/1.json b/trainingportal/tasks_uploads/1.json new file mode 100644 index 0000000..856df97 --- /dev/null +++ b/trainingportal/tasks_uploads/1.json @@ -0,0 +1,22 @@ +"MODULESTORE": { + "default": { + "ENGINE": "xmodule.modulestore.mixed.MixedModuleStore", + "OPTIONS": { + "mappings": {}, + "stores": [ + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore", + "NAME": "split", + "OPTIONS": {...settings...} + }, + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.mongo.DraftMongoModuleStore", + "NAME": "draft", + "OPTIONS": {...settings...} + } + ] + } + } + }, diff --git a/trainingportal/tasks_uploads/1_BSoUa9w.json b/trainingportal/tasks_uploads/1_BSoUa9w.json new file mode 100644 index 0000000..856df97 --- /dev/null +++ b/trainingportal/tasks_uploads/1_BSoUa9w.json @@ -0,0 +1,22 @@ +"MODULESTORE": { + "default": { + "ENGINE": "xmodule.modulestore.mixed.MixedModuleStore", + "OPTIONS": { + "mappings": {}, + "stores": [ + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore", + "NAME": "split", + "OPTIONS": {...settings...} + }, + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.mongo.DraftMongoModuleStore", + "NAME": "draft", + "OPTIONS": {...settings...} + } + ] + } + } + }, diff --git a/trainingportal/tasks_uploads/1_SJAZbi4.json b/trainingportal/tasks_uploads/1_SJAZbi4.json new file mode 100644 index 0000000..856df97 --- /dev/null +++ b/trainingportal/tasks_uploads/1_SJAZbi4.json @@ -0,0 +1,22 @@ +"MODULESTORE": { + "default": { + "ENGINE": "xmodule.modulestore.mixed.MixedModuleStore", + "OPTIONS": { + "mappings": {}, + "stores": [ + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore", + "NAME": "split", + "OPTIONS": {...settings...} + }, + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.mongo.DraftMongoModuleStore", + "NAME": "draft", + "OPTIONS": {...settings...} + } + ] + } + } + }, diff --git a/trainingportal/tasks_uploads/1_fEukKr2.json b/trainingportal/tasks_uploads/1_fEukKr2.json new file mode 100644 index 0000000..856df97 --- /dev/null +++ b/trainingportal/tasks_uploads/1_fEukKr2.json @@ -0,0 +1,22 @@ +"MODULESTORE": { + "default": { + "ENGINE": "xmodule.modulestore.mixed.MixedModuleStore", + "OPTIONS": { + "mappings": {}, + "stores": [ + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore", + "NAME": "split", + "OPTIONS": {...settings...} + }, + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.mongo.DraftMongoModuleStore", + "NAME": "draft", + "OPTIONS": {...settings...} + } + ] + } + } + }, diff --git a/trainingportal/tasks_uploads/1_i3Ss9J1.json b/trainingportal/tasks_uploads/1_i3Ss9J1.json new file mode 100644 index 0000000..856df97 --- /dev/null +++ b/trainingportal/tasks_uploads/1_i3Ss9J1.json @@ -0,0 +1,22 @@ +"MODULESTORE": { + "default": { + "ENGINE": "xmodule.modulestore.mixed.MixedModuleStore", + "OPTIONS": { + "mappings": {}, + "stores": [ + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore", + "NAME": "split", + "OPTIONS": {...settings...} + }, + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.mongo.DraftMongoModuleStore", + "NAME": "draft", + "OPTIONS": {...settings...} + } + ] + } + } + }, diff --git a/trainingportal/tasks_uploads/1_idUEwn1.json b/trainingportal/tasks_uploads/1_idUEwn1.json new file mode 100644 index 0000000..856df97 --- /dev/null +++ b/trainingportal/tasks_uploads/1_idUEwn1.json @@ -0,0 +1,22 @@ +"MODULESTORE": { + "default": { + "ENGINE": "xmodule.modulestore.mixed.MixedModuleStore", + "OPTIONS": { + "mappings": {}, + "stores": [ + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore", + "NAME": "split", + "OPTIONS": {...settings...} + }, + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.mongo.DraftMongoModuleStore", + "NAME": "draft", + "OPTIONS": {...settings...} + } + ] + } + } + }, diff --git a/trainingportal/tasks_uploads/1_nmlYtol.json b/trainingportal/tasks_uploads/1_nmlYtol.json new file mode 100644 index 0000000..856df97 --- /dev/null +++ b/trainingportal/tasks_uploads/1_nmlYtol.json @@ -0,0 +1,22 @@ +"MODULESTORE": { + "default": { + "ENGINE": "xmodule.modulestore.mixed.MixedModuleStore", + "OPTIONS": { + "mappings": {}, + "stores": [ + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore", + "NAME": "split", + "OPTIONS": {...settings...} + }, + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.mongo.DraftMongoModuleStore", + "NAME": "draft", + "OPTIONS": {...settings...} + } + ] + } + } + }, diff --git a/trainingportal/tasks_uploads/1_tRn71t2.json b/trainingportal/tasks_uploads/1_tRn71t2.json new file mode 100644 index 0000000..856df97 --- /dev/null +++ b/trainingportal/tasks_uploads/1_tRn71t2.json @@ -0,0 +1,22 @@ +"MODULESTORE": { + "default": { + "ENGINE": "xmodule.modulestore.mixed.MixedModuleStore", + "OPTIONS": { + "mappings": {}, + "stores": [ + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore", + "NAME": "split", + "OPTIONS": {...settings...} + }, + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.mongo.DraftMongoModuleStore", + "NAME": "draft", + "OPTIONS": {...settings...} + } + ] + } + } + }, diff --git a/trainingportal/tasks_uploads/Untitled_Document b/trainingportal/tasks_uploads/Untitled_Document new file mode 100644 index 0000000..bd8eb82 --- /dev/null +++ b/trainingportal/tasks_uploads/Untitled_Document @@ -0,0 +1,22 @@ +"MODULESTORE": { + "default": { + "ENGINE": "xmodule.modulestore.mixed.MixedModuleStore", + "OPTIONS": { + "mappings": {}, + "stores": [ + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.split_mongo.split_draft.DraftVersioningModuleStore", + "NAME": "split", + "OPTIONS": {...settings...} + }, + { + "DOC_STORE_CONFIG": {...settings...}, + "ENGINE": "xmodule.modulestore.mongo.DraftMongoModuleStore", + "NAME": "draft", + "OPTIONS": {...settings...} + } + ] + } + } +}, diff --git a/trainingportal/tasks_uploads/examples.desktop b/trainingportal/tasks_uploads/examples.desktop new file mode 100644 index 0000000..a9818df --- /dev/null +++ b/trainingportal/tasks_uploads/examples.desktop @@ -0,0 +1,240 @@ +[Desktop Entry] +Version=1.0 +Type=Link +Name=Examples +Name[aa]=Ceelallo +Name[ace]=Contoh +Name[af]=Voorbeelde +Name[am]=ምሳሌዎች +Name[an]=Exemplos +Name[ar]=أمثلة +Name[ast]=Exemplos +Name[az]=Nümunələr +Name[be]=Прыклады +Name[bg]=Примери +Name[bn]=উদাহরণ +Name[br]=Skouerioù +Name[bs]=Primjeri +Name[ca]=Exemples +Name[ca@valencia]=Exemples +Name[ckb]=نمونه‌كان +Name[cs]=Ukázky +Name[csb]=Przëmiôrë +Name[cy]=Enghreifftiau +Name[da]=Eksempler +Name[de]=Beispiele +Name[dv]=މިސާލުތަށް +Name[el]=Παραδείγματα +Name[en_AU]=Examples +Name[en_CA]=Examples +Name[en_GB]=Examples +Name[eo]=Ekzemploj +Name[es]=Ejemplos +Name[et]=Näidised +Name[eu]=Adibideak +Name[fa]=نمونه‌ها +Name[fi]=Esimerkkejä +Name[fil]=Mga halimbawa +Name[fo]=Dømir +Name[fr]=Exemples +Name[fur]=Esemplis +Name[fy]=Foarbylden +Name[ga]=Samplaí +Name[gd]=Buill-eisimpleir +Name[gl]=Exemplos +Name[gu]=દૃષ્ટાન્તો +Name[gv]=Sampleyryn +Name[he]=דוגמאות +Name[hi]=उदाहरण +Name[hr]=Primjeri +Name[ht]=Egzanp +Name[hu]=Minták +Name[hy]=Օրինակներ +Name[id]=Contoh +Name[is]=Sýnishorn +Name[it]=Esempi +Name[ja]=サンプル +Name[ka]=ნიმუშები +Name[kk]=Мысалдар +Name[kl]=Assersuutit +Name[km]=ឧទាហរណ៍ +Name[kn]=ಉದಾಹರಣೆಗಳು +Name[ko]=예시 +Name[ku]=Mînak +Name[kw]=Ensamplow +Name[ky]=Мисалдар +Name[lb]=Beispiller +Name[lt]=Pavyzdžių failai +Name[lv]=Paraugi +Name[mg]=Ohatra +Name[mhr]=Пример-влак +Name[mi]=Tauira +Name[mk]=Примери +Name[ml]=ഉദാഹരണങ്ങള്‍ +Name[mr]=उदाहरणे +Name[ms]=Contoh-contoh +Name[my]=ဥပမာများ +Name[nb]=Eksempler +Name[nds]=Bispelen +Name[ne]=उदाहरणहरू +Name[nl]=Voorbeeld-bestanden +Name[nn]=Døme +Name[nso]=Mehlala +Name[oc]=Exemples +Name[pa]=ਉਦਾਹਰਨਾਂ +Name[pl]=Przykłady +Name[pt]=Exemplos +Name[pt_BR]=Exemplos +Name[ro]=Exemple +Name[ru]=Примеры +Name[sc]=Esempiusu +Name[sco]=Examples +Name[sd]=مثالون +Name[se]=Ovdamearkkat +Name[shn]=တူဝ်ယၢင်ႇ +Name[si]=නිදසුන් +Name[sk]=Príklady +Name[sl]=Zgledi +Name[sml]=Saga Saupama +Name[sn]=Miyenzaniso +Name[sq]=Shembujt +Name[sr]=Примери +Name[sv]=Exempel +Name[sw]=Mifano +Name[szl]=Bajszpile +Name[ta]=உதாரணங்கள் +Name[ta_LK]=உதாரணங்கள் +Name[te]=ఉదాహరణలు +Name[tg]=Намунаҳо +Name[th]=ตัวอย่าง +Name[tr]=Örnekler +Name[tt]=Мисаллар +Name[ug]=مىساللار +Name[uk]=Приклади +Name[ur]=مثالیں +Name[uz]=Намуналар +Name[vec]=Esempi +Name[vi]=Mẫu ví dụ +Name[wae]=Bischbil +Name[zh_CN]=示例 +Name[zh_HK]=範例 +Name[zh_TW]=範例 +Comment=Example content for Ubuntu +Comment[aa]=Ubuntuh addattinoh ceelallo +Comment[ace]=Contoh aso ke Ubuntu +Comment[af]=Voorbeeld inhoud vir Ubuntu +Comment[am]=ዝርዝር ምሳሌዎች ለ ኡቡንቱ +Comment[an]=Conteniu d'exemplo ta Ubuntu +Comment[ar]=أمثلة محتوى لأوبونتو +Comment[ast]=Conteníu del exemplu pa Ubuntu +Comment[az]=Ubuntu üçün nümunə material +Comment[be]=Узоры дакументаў для Ubuntu +Comment[bg]=Примерно съдържание за Ubuntu +Comment[bn]=উবুন্টু সংক্রান্ত নমুনা তথ্য +Comment[br]=Skouerenn endalc'had evit Ubuntu +Comment[bs]=Primjer sadrzaja za Ubuntu +Comment[ca]=Continguts d'exemple per a l'Ubuntu +Comment[ca@valencia]=Continguts d'exemple per a l'Ubuntu +Comment[ckb]=نموونەی ناوەڕۆکێک بۆ ئوبوونتو +Comment[cs]=Ukázkový obsah pro Ubuntu +Comment[csb]=Przëmiôrowô zamkłosc dlô Ubuntu +Comment[cy]=Cynnwys enghraifft ar gyfer Ubuntu +Comment[da]=Eksempel indhold til Ubuntu +Comment[de]=Beispielinhalt für Ubuntu +Comment[dv]=އުބުންޓު އާއި އެކަށޭނަ މިސާލުތައް +Comment[el]=Παραδείγματα περιεχομένου για το Ubuntu +Comment[en_AU]=Example content for Ubuntu +Comment[en_CA]=Example content for Ubuntu +Comment[en_GB]=Example content for Ubuntu +Comment[eo]=Ekzempla enhavo por Ubuntu +Comment[es]=Contenido de ejemplo para Ubuntu +Comment[et]=Ubuntu näidisfailid +Comment[eu]=Adibidezko edukia Ubunturako +Comment[fa]=محتویات نمونه برای اوبونتو +Comment[fi]=Esimerkkisisältöjä Ubuntulle +Comment[fil]=Halimbawang laman para sa Ubuntu +Comment[fo]=Dømis innihald fyri Ubuntu +Comment[fr]=Contenu d'exemple pour Ubuntu +Comment[fur]=Contignûts di esempli par Ubuntu +Comment[fy]=Foarbyld fan ynhâld foar Ubuntu +Comment[ga]=Inneachar samplach do Ubuntu +Comment[gd]=Eisimpleir de shusbaint airson Ubuntu +Comment[gl]=Contido do exemplo para Ubuntu +Comment[gu]=Ubuntu માટે ઉદાહરણ સૂચી +Comment[gv]=Stoo Sanpleyr son Ubuntu +Comment[he]=תוכן לדוגמה עבור אובונטו +Comment[hi]=उबुन्टू हेतु उदाहरण सारांश +Comment[hr]=Primjeri sadržaja za Ubuntu +Comment[ht]=Kontni egzanplè pou Ubuntu +Comment[hu]=Mintatartalom Ubuntuhoz +Comment[hy]=Բովանդակության օրինակները Ubuntu֊ի համար +Comment[id]=Contoh isi bagi Ubuntu +Comment[is]=Sýnishorn fyrir Ubuntu +Comment[it]=Contenuti di esempio per Ubuntu +Comment[ja]=Ubuntuのサンプルコンテンツ +Comment[ka]=უბუნტუს სანიმუშო შიგთავსი +Comment[kk]=Ubuntu құжаттар мысалдары +Comment[kl]=Ubuntu-mut imarisaanut assersuut +Comment[km]=ឧទាហរណ៍សម្រាប់អាប់ប៊ុនធូ +Comment[kn]=ಉಬುಂಟುಗೆ ಉದಾಹರಣೆಗಳು +Comment[ko]=우분투 컨텐츠 예시 +Comment[ku]=Ji bo Ubuntu mînaka naverokê +Comment[ky]=Ubuntu-нун мисал документтери +Comment[lb]=Beispillinhalt fir Ubuntu +Comment[lt]=Įvairių dokumentų, paveikslėlių, garsų bei vaizdų pavyzdžiai +Comment[lv]=Parauga saturs Ubuntu videi +Comment[mg]=Ohatra ho an'i Ubuntu +Comment[mhr]=Ubuntu-лан документ-влакын пример-влак +Comment[mi]=Mata tauira o Ubuntu +Comment[mk]=Пример содржина за Убунту +Comment[ml]=ഉബുണ്ടുവിനു വേണ്ടിയുള്ള ഉദാഹരണങ്ങള്‍ +Comment[mr]=उबंटूसाठी घटकांची उदाहरणे +Comment[ms]=Kandungan contoh untuk Ubuntu +Comment[my]=Ubuntu အတွက် နမူနာ မာတိကာ +Comment[nb]=Eksempelinnhold for Ubuntu +Comment[ne]=उबन्टुका लागि उदाहरण सामग्री +Comment[nl]=Voorbeeldinhoud voor Ubuntu +Comment[nn]=Eksempelinnhald for Ubuntu +Comment[nso]=Mohlala wa dikagare tša Ubuntu +Comment[oc]=Exemples de contengut per Ubuntu +Comment[pa]=ਉਬਤੂੰ ਲਈ ਨਮੂਨਾ ਸਮੱਗਰੀ +Comment[pl]=Przykładowa zawartość dla Ubuntu +Comment[pt]=Conteúdo de exemplo para o Ubuntu +Comment[pt_BR]=Exemplo de conteúdo para Ubuntu +Comment[ro]=Conținut exemplu pentru Ubuntu +Comment[ru]=Примеры документов для Ubuntu +Comment[sc]=Esempiu de cabidu pro Ubuntu +Comment[sco]=Example content fur Ubuntu +Comment[sd]=اوبنٽو لاءِ مثال طور ڏنل مواد +Comment[shn]=တူဝ်ႇယၢင်ႇလမ်းၼႂ်း တႃႇ Ubuntu +Comment[si]=උබුන්ටු සඳහා උදාහරණ අන්තර්ගතයන් +Comment[sk]=Ukážkový obsah pre Ubuntu +Comment[sl]=Ponazoritvena vsebina za Ubuntu +Comment[sml]=Saupama Isina Ubuntu +Comment[sn]=Muyenzaniso wehuiswa kuitira Ubuntu +Comment[sq]=Shembull i përmbajtjes për Ubuntu +Comment[sr]=Садржај примера за Убунту +Comment[sv]=Exempelinnehåll för Ubuntu +Comment[sw]=Bidhaa mfano ya Ubuntu +Comment[szl]=Bajszpilnŏ treść dlŏ Ubuntu +Comment[ta]=உபுண்டுவிற்கான எடுத்துகாட்டு உள்ளடக்கங்கள் +Comment[ta_LK]=உபுண்டுவிற்கான எடுத்துகாட்டு உள்ளடக்கங்கள் +Comment[te]=Ubuntu వాడుక విధాన నమూనాలు +Comment[tg]=Мӯҳтавои намунавӣ барои Ubuntu +Comment[th]=ตัวอย่างข้อมูลสำหรับ Ubuntu +Comment[tr]=Ubuntu için örnek içerik +Comment[tt]=Ubuntu өчен документ мисаллары +Comment[ug]=ئۇبۇنتۇنىڭ مىساللىرى +Comment[uk]=Приклади контенту для Ubuntu +Comment[ur]=یوبنٹو کیلئے مثالی مواد +Comment[uz]=Ubuntu учун намуна таркиби +Comment[vec]=Contenuti de esempio de Ubuntu +Comment[vi]=Mẫu ví dụ cho Ubuntu +Comment[wae]=D'Ubuntu bischbildatijä +Comment[zh_CN]=Ubuntu 示例内容 +Comment[zh_HK]=Ubuntu 的範例內容 +Comment[zh_TW]=Ubuntu 的範例內容 +URL=file:///usr/share/example-content/ +Icon=folder +X-Ubuntu-Gettext-Domain=example-content + diff --git a/trainingportal/tasks_uploads/orsay_sample.txt b/trainingportal/tasks_uploads/orsay_sample.txt new file mode 100644 index 0000000..0376532 --- /dev/null +++ b/trainingportal/tasks_uploads/orsay_sample.txt @@ -0,0 +1,144 @@ +{ + 'spider_name': 'orsay-de-crawl', + 'retailer': 'orsay-de', + 'currency': 'EUR', + 'market': 'DE', + 'category': [ + + ], + 'uuid': None, + 'retailer_sk': '102026', + 'product_hash': 'ac6d5dc9cc5774109e2f2181', + 'price': 2599, + 'description': [ + 'Unser Tipp: Als Basic zum Lederrock und abgestimmter ORSAY-Clutch tragen!' + ], + 'url_original': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'brand': 'Orsay', + 'image_urls': [ + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42p.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42d_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60p_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60d_1.jpg' + ], + 'trail': [ + ('', + 'http://www.orsay.com/'), + ('UNI', + 'http://www.orsay.com/de-de/neuheiten/t-shirts/uni.html') + ], + 'crawl_id': 'orsay-de-20161107-1478509215-okfa', + 'date': 1478512866, + 'skus': { + '10202642_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXL' + }, + '10202642_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'L' + }, + '10202642_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'M' + }, + '10202642_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XL' + }, + '10202660_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXL' + }, + '10202660_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'L' + }, + '10202660_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'M' + }, + '10202660_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'XS' + }, + '10202660_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XL' + }, + '10202660_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'S' + }, + '10202660_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXS' + }, + '10202642_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'XS' + }, + '10202642_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'S' + }, + '10202642_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXS' + } + }, + 'care': [ + '99% POLYAMID, 1% ELASTHAN', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/wash-30.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/chlore-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/sharp-L.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/clean-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/linge-0.png' + ], + 'lang': 'de', + 'name': 'Top aus Spitze', + 'url': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'gender': 'women', + 'industry': None, + 'crawl_start_time': '2016-11-07T10:00:16.985826' +} \ No newline at end of file diff --git a/trainingportal/tasks_uploads/orsay_sample_bj1qPcz.txt b/trainingportal/tasks_uploads/orsay_sample_bj1qPcz.txt new file mode 100644 index 0000000..0376532 --- /dev/null +++ b/trainingportal/tasks_uploads/orsay_sample_bj1qPcz.txt @@ -0,0 +1,144 @@ +{ + 'spider_name': 'orsay-de-crawl', + 'retailer': 'orsay-de', + 'currency': 'EUR', + 'market': 'DE', + 'category': [ + + ], + 'uuid': None, + 'retailer_sk': '102026', + 'product_hash': 'ac6d5dc9cc5774109e2f2181', + 'price': 2599, + 'description': [ + 'Unser Tipp: Als Basic zum Lederrock und abgestimmter ORSAY-Clutch tragen!' + ], + 'url_original': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'brand': 'Orsay', + 'image_urls': [ + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42p.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42d_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60p_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60d_1.jpg' + ], + 'trail': [ + ('', + 'http://www.orsay.com/'), + ('UNI', + 'http://www.orsay.com/de-de/neuheiten/t-shirts/uni.html') + ], + 'crawl_id': 'orsay-de-20161107-1478509215-okfa', + 'date': 1478512866, + 'skus': { + '10202642_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXL' + }, + '10202642_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'L' + }, + '10202642_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'M' + }, + '10202642_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XL' + }, + '10202660_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXL' + }, + '10202660_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'L' + }, + '10202660_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'M' + }, + '10202660_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'XS' + }, + '10202660_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XL' + }, + '10202660_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'S' + }, + '10202660_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXS' + }, + '10202642_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'XS' + }, + '10202642_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'S' + }, + '10202642_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXS' + } + }, + 'care': [ + '99% POLYAMID, 1% ELASTHAN', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/wash-30.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/chlore-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/sharp-L.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/clean-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/linge-0.png' + ], + 'lang': 'de', + 'name': 'Top aus Spitze', + 'url': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'gender': 'women', + 'industry': None, + 'crawl_start_time': '2016-11-07T10:00:16.985826' +} \ No newline at end of file diff --git a/trainingportal/tasks_uploads/orsay_sample_cEEtYIc.txt b/trainingportal/tasks_uploads/orsay_sample_cEEtYIc.txt new file mode 100644 index 0000000..0376532 --- /dev/null +++ b/trainingportal/tasks_uploads/orsay_sample_cEEtYIc.txt @@ -0,0 +1,144 @@ +{ + 'spider_name': 'orsay-de-crawl', + 'retailer': 'orsay-de', + 'currency': 'EUR', + 'market': 'DE', + 'category': [ + + ], + 'uuid': None, + 'retailer_sk': '102026', + 'product_hash': 'ac6d5dc9cc5774109e2f2181', + 'price': 2599, + 'description': [ + 'Unser Tipp: Als Basic zum Lederrock und abgestimmter ORSAY-Clutch tragen!' + ], + 'url_original': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'brand': 'Orsay', + 'image_urls': [ + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42p.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42d_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60p_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60d_1.jpg' + ], + 'trail': [ + ('', + 'http://www.orsay.com/'), + ('UNI', + 'http://www.orsay.com/de-de/neuheiten/t-shirts/uni.html') + ], + 'crawl_id': 'orsay-de-20161107-1478509215-okfa', + 'date': 1478512866, + 'skus': { + '10202642_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXL' + }, + '10202642_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'L' + }, + '10202642_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'M' + }, + '10202642_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XL' + }, + '10202660_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXL' + }, + '10202660_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'L' + }, + '10202660_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'M' + }, + '10202660_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'XS' + }, + '10202660_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XL' + }, + '10202660_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'S' + }, + '10202660_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXS' + }, + '10202642_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'XS' + }, + '10202642_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'S' + }, + '10202642_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXS' + } + }, + 'care': [ + '99% POLYAMID, 1% ELASTHAN', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/wash-30.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/chlore-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/sharp-L.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/clean-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/linge-0.png' + ], + 'lang': 'de', + 'name': 'Top aus Spitze', + 'url': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'gender': 'women', + 'industry': None, + 'crawl_start_time': '2016-11-07T10:00:16.985826' +} \ No newline at end of file diff --git a/trainingportal/tasks_uploads/orsay_sample_kCEiIGr.txt b/trainingportal/tasks_uploads/orsay_sample_kCEiIGr.txt new file mode 100644 index 0000000..0376532 --- /dev/null +++ b/trainingportal/tasks_uploads/orsay_sample_kCEiIGr.txt @@ -0,0 +1,144 @@ +{ + 'spider_name': 'orsay-de-crawl', + 'retailer': 'orsay-de', + 'currency': 'EUR', + 'market': 'DE', + 'category': [ + + ], + 'uuid': None, + 'retailer_sk': '102026', + 'product_hash': 'ac6d5dc9cc5774109e2f2181', + 'price': 2599, + 'description': [ + 'Unser Tipp: Als Basic zum Lederrock und abgestimmter ORSAY-Clutch tragen!' + ], + 'url_original': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'brand': 'Orsay', + 'image_urls': [ + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42p.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42d_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60p_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60d_1.jpg' + ], + 'trail': [ + ('', + 'http://www.orsay.com/'), + ('UNI', + 'http://www.orsay.com/de-de/neuheiten/t-shirts/uni.html') + ], + 'crawl_id': 'orsay-de-20161107-1478509215-okfa', + 'date': 1478512866, + 'skus': { + '10202642_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXL' + }, + '10202642_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'L' + }, + '10202642_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'M' + }, + '10202642_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XL' + }, + '10202660_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXL' + }, + '10202660_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'L' + }, + '10202660_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'M' + }, + '10202660_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'XS' + }, + '10202660_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XL' + }, + '10202660_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'S' + }, + '10202660_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXS' + }, + '10202642_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'XS' + }, + '10202642_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'S' + }, + '10202642_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXS' + } + }, + 'care': [ + '99% POLYAMID, 1% ELASTHAN', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/wash-30.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/chlore-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/sharp-L.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/clean-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/linge-0.png' + ], + 'lang': 'de', + 'name': 'Top aus Spitze', + 'url': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'gender': 'women', + 'industry': None, + 'crawl_start_time': '2016-11-07T10:00:16.985826' +} \ No newline at end of file diff --git a/trainingportal/tasks_uploads/orsay_sample_pNKVgma.txt b/trainingportal/tasks_uploads/orsay_sample_pNKVgma.txt new file mode 100644 index 0000000..0376532 --- /dev/null +++ b/trainingportal/tasks_uploads/orsay_sample_pNKVgma.txt @@ -0,0 +1,144 @@ +{ + 'spider_name': 'orsay-de-crawl', + 'retailer': 'orsay-de', + 'currency': 'EUR', + 'market': 'DE', + 'category': [ + + ], + 'uuid': None, + 'retailer_sk': '102026', + 'product_hash': 'ac6d5dc9cc5774109e2f2181', + 'price': 2599, + 'description': [ + 'Unser Tipp: Als Basic zum Lederrock und abgestimmter ORSAY-Clutch tragen!' + ], + 'url_original': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'brand': 'Orsay', + 'image_urls': [ + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42p.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42d_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60p_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60d_1.jpg' + ], + 'trail': [ + ('', + 'http://www.orsay.com/'), + ('UNI', + 'http://www.orsay.com/de-de/neuheiten/t-shirts/uni.html') + ], + 'crawl_id': 'orsay-de-20161107-1478509215-okfa', + 'date': 1478512866, + 'skus': { + '10202642_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXL' + }, + '10202642_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'L' + }, + '10202642_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'M' + }, + '10202642_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XL' + }, + '10202660_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXL' + }, + '10202660_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'L' + }, + '10202660_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'M' + }, + '10202660_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'XS' + }, + '10202660_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XL' + }, + '10202660_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'S' + }, + '10202660_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXS' + }, + '10202642_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'XS' + }, + '10202642_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'S' + }, + '10202642_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXS' + } + }, + 'care': [ + '99% POLYAMID, 1% ELASTHAN', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/wash-30.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/chlore-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/sharp-L.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/clean-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/linge-0.png' + ], + 'lang': 'de', + 'name': 'Top aus Spitze', + 'url': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'gender': 'women', + 'industry': None, + 'crawl_start_time': '2016-11-07T10:00:16.985826' +} \ No newline at end of file diff --git a/trainingportal/tasks_uploads/orsay_sample_rH0qJfi.txt b/trainingportal/tasks_uploads/orsay_sample_rH0qJfi.txt new file mode 100644 index 0000000..0376532 --- /dev/null +++ b/trainingportal/tasks_uploads/orsay_sample_rH0qJfi.txt @@ -0,0 +1,144 @@ +{ + 'spider_name': 'orsay-de-crawl', + 'retailer': 'orsay-de', + 'currency': 'EUR', + 'market': 'DE', + 'category': [ + + ], + 'uuid': None, + 'retailer_sk': '102026', + 'product_hash': 'ac6d5dc9cc5774109e2f2181', + 'price': 2599, + 'description': [ + 'Unser Tipp: Als Basic zum Lederrock und abgestimmter ORSAY-Clutch tragen!' + ], + 'url_original': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'brand': 'Orsay', + 'image_urls': [ + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42p.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42d_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60p_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60d_1.jpg' + ], + 'trail': [ + ('', + 'http://www.orsay.com/'), + ('UNI', + 'http://www.orsay.com/de-de/neuheiten/t-shirts/uni.html') + ], + 'crawl_id': 'orsay-de-20161107-1478509215-okfa', + 'date': 1478512866, + 'skus': { + '10202642_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXL' + }, + '10202642_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'L' + }, + '10202642_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'M' + }, + '10202642_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XL' + }, + '10202660_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXL' + }, + '10202660_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'L' + }, + '10202660_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'M' + }, + '10202660_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'XS' + }, + '10202660_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XL' + }, + '10202660_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'S' + }, + '10202660_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXS' + }, + '10202642_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'XS' + }, + '10202642_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'S' + }, + '10202642_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXS' + } + }, + 'care': [ + '99% POLYAMID, 1% ELASTHAN', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/wash-30.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/chlore-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/sharp-L.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/clean-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/linge-0.png' + ], + 'lang': 'de', + 'name': 'Top aus Spitze', + 'url': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'gender': 'women', + 'industry': None, + 'crawl_start_time': '2016-11-07T10:00:16.985826' +} \ No newline at end of file diff --git a/trainingportal/tasks_uploads/orsay_sample_xwW2d2V.txt b/trainingportal/tasks_uploads/orsay_sample_xwW2d2V.txt new file mode 100644 index 0000000..0376532 --- /dev/null +++ b/trainingportal/tasks_uploads/orsay_sample_xwW2d2V.txt @@ -0,0 +1,144 @@ +{ + 'spider_name': 'orsay-de-crawl', + 'retailer': 'orsay-de', + 'currency': 'EUR', + 'market': 'DE', + 'category': [ + + ], + 'uuid': None, + 'retailer_sk': '102026', + 'product_hash': 'ac6d5dc9cc5774109e2f2181', + 'price': 2599, + 'description': [ + 'Unser Tipp: Als Basic zum Lederrock und abgestimmter ORSAY-Clutch tragen!' + ], + 'url_original': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'brand': 'Orsay', + 'image_urls': [ + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42p.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42d_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60p_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60d_1.jpg' + ], + 'trail': [ + ('', + 'http://www.orsay.com/'), + ('UNI', + 'http://www.orsay.com/de-de/neuheiten/t-shirts/uni.html') + ], + 'crawl_id': 'orsay-de-20161107-1478509215-okfa', + 'date': 1478512866, + 'skus': { + '10202642_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXL' + }, + '10202642_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'L' + }, + '10202642_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'M' + }, + '10202642_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XL' + }, + '10202660_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXL' + }, + '10202660_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'L' + }, + '10202660_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'M' + }, + '10202660_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'XS' + }, + '10202660_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XL' + }, + '10202660_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'S' + }, + '10202660_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXS' + }, + '10202642_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'XS' + }, + '10202642_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'S' + }, + '10202642_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXS' + } + }, + 'care': [ + '99% POLYAMID, 1% ELASTHAN', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/wash-30.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/chlore-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/sharp-L.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/clean-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/linge-0.png' + ], + 'lang': 'de', + 'name': 'Top aus Spitze', + 'url': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'gender': 'women', + 'industry': None, + 'crawl_start_time': '2016-11-07T10:00:16.985826' +} \ No newline at end of file diff --git a/trainingportal/tasks_uploads/orsay_sample_zbCJtlu.txt b/trainingportal/tasks_uploads/orsay_sample_zbCJtlu.txt new file mode 100644 index 0000000..0376532 --- /dev/null +++ b/trainingportal/tasks_uploads/orsay_sample_zbCJtlu.txt @@ -0,0 +1,144 @@ +{ + 'spider_name': 'orsay-de-crawl', + 'retailer': 'orsay-de', + 'currency': 'EUR', + 'market': 'DE', + 'category': [ + + ], + 'uuid': None, + 'retailer_sk': '102026', + 'product_hash': 'ac6d5dc9cc5774109e2f2181', + 'price': 2599, + 'description': [ + 'Unser Tipp: Als Basic zum Lederrock und abgestimmter ORSAY-Clutch tragen!' + ], + 'url_original': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'brand': 'Orsay', + 'image_urls': [ + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42p.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42d_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60p_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60d_1.jpg' + ], + 'trail': [ + ('', + 'http://www.orsay.com/'), + ('UNI', + 'http://www.orsay.com/de-de/neuheiten/t-shirts/uni.html') + ], + 'crawl_id': 'orsay-de-20161107-1478509215-okfa', + 'date': 1478512866, + 'skus': { + '10202642_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXL' + }, + '10202642_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'L' + }, + '10202642_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'M' + }, + '10202642_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XL' + }, + '10202660_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXL' + }, + '10202660_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'L' + }, + '10202660_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'M' + }, + '10202660_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'XS' + }, + '10202660_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XL' + }, + '10202660_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'S' + }, + '10202660_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXS' + }, + '10202642_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'XS' + }, + '10202642_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'S' + }, + '10202642_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXS' + } + }, + 'care': [ + '99% POLYAMID, 1% ELASTHAN', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/wash-30.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/chlore-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/sharp-L.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/clean-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/linge-0.png' + ], + 'lang': 'de', + 'name': 'Top aus Spitze', + 'url': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'gender': 'women', + 'industry': None, + 'crawl_start_time': '2016-11-07T10:00:16.985826' +} \ No newline at end of file diff --git a/trainingportal/tasks_uploads/orsay_sample_zl4390Q.txt b/trainingportal/tasks_uploads/orsay_sample_zl4390Q.txt new file mode 100644 index 0000000..0376532 --- /dev/null +++ b/trainingportal/tasks_uploads/orsay_sample_zl4390Q.txt @@ -0,0 +1,144 @@ +{ + 'spider_name': 'orsay-de-crawl', + 'retailer': 'orsay-de', + 'currency': 'EUR', + 'market': 'DE', + 'category': [ + + ], + 'uuid': None, + 'retailer_sk': '102026', + 'product_hash': 'ac6d5dc9cc5774109e2f2181', + 'price': 2599, + 'description': [ + 'Unser Tipp: Als Basic zum Lederrock und abgestimmter ORSAY-Clutch tragen!' + ], + 'url_original': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'brand': 'Orsay', + 'image_urls': [ + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42p.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_42d_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60f_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60b_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60p_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60s_1.jpg', + 'http://images.orsay.com/media/catalog/product/cache/allstores/image/9df78eab33525d08d6e5fb8d27136e95/1/0/102026_60d_1.jpg' + ], + 'trail': [ + ('', + 'http://www.orsay.com/'), + ('UNI', + 'http://www.orsay.com/de-de/neuheiten/t-shirts/uni.html') + ], + 'crawl_id': 'orsay-de-20161107-1478509215-okfa', + 'date': 1478512866, + 'skus': { + '10202642_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXL' + }, + '10202642_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'L' + }, + '10202642_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'M' + }, + '10202642_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XL' + }, + '10202660_XXL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXL' + }, + '10202660_L': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'L' + }, + '10202660_M': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'M' + }, + '10202660_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'XS' + }, + '10202660_XL': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XL' + }, + '10202660_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Schwarz', + 'size': 'S' + }, + '10202660_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Schwarz', + 'size': 'XXS' + }, + '10202642_XS': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'XS' + }, + '10202642_S': { + 'currency': 'EUR', + 'price': 2599, + 'colour': 'Rot', + 'size': 'S' + }, + '10202642_XXS': { + 'currency': 'EUR', + 'price': 2599, + 'out_of_stock': True, + 'colour': 'Rot', + 'size': 'XXS' + } + }, + 'care': [ + '99% POLYAMID, 1% ELASTHAN', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/wash-30.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/chlore-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/sharp-L.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/clean-0.png', + 'http://www.orsay.com/skin/frontend/enterprise/orsay/images/caresymbols/linge-0.png' + ], + 'lang': 'de', + 'name': 'Top aus Spitze', + 'url': 'http://www.orsay.com/de-de/top-aus-spitze-10202642.html', + 'gender': 'women', + 'industry': None, + 'crawl_start_time': '2016-11-07T10:00:16.985826' +} \ No newline at end of file diff --git a/trainingportal/tasks_uploads/pip-selfcheck.json b/trainingportal/tasks_uploads/pip-selfcheck.json new file mode 100644 index 0000000..7ccb058 --- /dev/null +++ b/trainingportal/tasks_uploads/pip-selfcheck.json @@ -0,0 +1 @@ +{"last_check":"2018-01-15T04:57:06Z","pypi_version":"9.0.1"} \ No newline at end of file diff --git a/trainingportal/templates/trainingportal/assignments.html b/trainingportal/templates/trainingportal/assignments.html new file mode 100644 index 0000000..29dc404 --- /dev/null +++ b/trainingportal/templates/trainingportal/assignments.html @@ -0,0 +1,116 @@ +{% extends "trainingportal/base.html" %} +{% load bootstrap3 %} +{% load static %} +{% bootstrap_css %} +{% block content %} + + +
+ {% if is_staff %} +
+ +
+ {% endif %} +
+ {% if no_assignments %} +

{{ no_assignments }}

+ {% else %} +

Assignments Assigned

+
+ + + + + + + + + + + + + {% for assignment in assignments %} + + + + + + + + + {% endfor %} + +
IDTitleDescriptionAssignment PathDue Date + {% if is_staff %} + Evaluate Assignment + {% else %} + Submit Assignment + {% endif %}
{{ assignment.id }}{{ assignment.title }}{{ assignment.description }}{{ assignment.assignment_file_path }}{{ assignment.due_date }} + {% if is_staff %} + {% if assignment.status == True %} + {% if not assignment.score %} + + {% else %} + + {% endif %} + {% else %} + + {% endif %} + {% else %} + {% if assignment.status == True %} + + {% else %} + + {% endif %} + {% endif %} +
+
+ {% endif %} +
+
+ + + + + + +{% endblock %} \ No newline at end of file diff --git a/trainingportal/templates/trainingportal/base.html b/trainingportal/templates/trainingportal/base.html new file mode 100644 index 0000000..0f9638f --- /dev/null +++ b/trainingportal/templates/trainingportal/base.html @@ -0,0 +1,45 @@ + + + + {% load static %} + + + + + + Title + + + +
+ {% block content %} + {% endblock %} +
+ + \ No newline at end of file diff --git a/trainingportal/templates/trainingportal/contact.html b/trainingportal/templates/trainingportal/contact.html index 6e84221..30f7a5a 100644 --- a/trainingportal/templates/trainingportal/contact.html +++ b/trainingportal/templates/trainingportal/contact.html @@ -12,16 +12,16 @@ {% bootstrap_label "HELLO" %} {% bootstrap_alert "Something went wrong" alert_type='danger' %} -
{% csrf_token %} - {% bootstrap_form form %} - {% bootstrap_button "Submit" button_type="submit" button_class="btn-primary" %} +{% csrf_token %} + {% bootstrap_form form %} + {% bootstrap_button "Submit" button_type="submit" button_class="btn-primary" %} -{# {% buttons %}#} -{# #} -{# {% endbuttons %}#} -
+ {# {% buttons %}#} + {# #} + {# {% endbuttons %}#} + {% bootstrap_javascript jquery=1 %} {% bootstrap_messages %} diff --git a/trainingportal/templates/trainingportal/edit_training.html b/trainingportal/templates/trainingportal/edit_training.html new file mode 100644 index 0000000..0b49c3f --- /dev/null +++ b/trainingportal/templates/trainingportal/edit_training.html @@ -0,0 +1,33 @@ +{% extends "trainingportal/base.html" %} +{% load bootstrap3 %} +{% load static %} +{% bootstrap_css %} +{% block content %} +

Edit Training

+
+
+

+ {% csrf_token %} + {% for field in training_form %} +
+ + {{ field.errors }} + + + {{ field }} + {% if field.help_text %} +

{{ field.help_text|safe }}

+ {% endif %} +
+ {% endfor %} +
+ +
+
+
+ +{% endblock %} \ No newline at end of file diff --git a/trainingportal/templates/trainingportal/enroll_training.html b/trainingportal/templates/trainingportal/enroll_training.html new file mode 100644 index 0000000..bde9b7e --- /dev/null +++ b/trainingportal/templates/trainingportal/enroll_training.html @@ -0,0 +1,45 @@ +{% extends "trainingportal/base.html" %} +{% load bootstrap3 %} +{% load static %} +{% bootstrap_css %} +{% block content %} +

Evaluate Assignment

+
+
+ {% if already_enrolled %} +

{{ already_enrolled }}

+ {% endif %} + {% csrf_token %} +{# {% for field in assignment_form %}#} +{#
#} +{# #} +{# {{ field.errors }}#} +{# #} +{# #} +{# {{ field }}#} +{# {% if field.help_text %}#} +{#

{{ field.help_text|safe }}

#} +{# {% endif %}#} +{#
#} +{# {% endfor %}#} + + + + +
+ +
+
+
+{% endblock %} \ No newline at end of file diff --git a/trainingportal/templates/trainingportal/evaluate_assignment.html b/trainingportal/templates/trainingportal/evaluate_assignment.html new file mode 100644 index 0000000..956dae5 --- /dev/null +++ b/trainingportal/templates/trainingportal/evaluate_assignment.html @@ -0,0 +1,34 @@ +{% extends "trainingportal/base.html" %} +{% load bootstrap3 %} +{% load static %} +{% bootstrap_css %} +{% block content %} +

Evaluate Assignment

+
+
+

+ + {% csrf_token %} + {% for field in assignment_form %} +
+ + {{ field.errors }} + + + {{ field }} + {% if field.help_text %} +

{{ field.help_text|safe }}

+ {% endif %} +
+ {% endfor %} +
+ +
+
+
+ + +{% endblock %} \ No newline at end of file diff --git a/trainingportal/templates/trainingportal/home.html b/trainingportal/templates/trainingportal/home.html index 1286220..a12917f 100644 --- a/trainingportal/templates/trainingportal/home.html +++ b/trainingportal/templates/trainingportal/home.html @@ -1,39 +1,89 @@ - - - - - {% block title %}Home | Training Portal{% endblock %} - +{% extends "trainingportal/base.html" %} +{% block content %} + {% if user.is_authenticated %} + {% if user.is_staff %} +
+
+ {% if no_trainee %} +

{{ no_trainee }}

+ {% else %} +

Assigned Trainees

+
+ + + + + + + + + + + + {% for training in assigned_trainings %} + + + + + + + + {% endfor %} + +
Trainee IDNameTraining NameDue DateStatus
{{ training.trainee_id }}{{ training.trainee_name }}{{ training.training_name }}{{ training.training_due_date }}{{ training.status }}
+
+ {% endif %} +
+
+ {% else %} +
- - {% load bootstrap3 %} - {% load static %} - {% bootstrap_css %} -
-
- {% if user.is_authenticated %} - {% buttons %} - Welcome, {{ user.username }} -     - - {% endbuttons %} - {% else %} - {% buttons %} - - - {% endbuttons %} - {% endif %} +
+ {% if no_training %} +

{{ no_training }}

+ {% else %} +

Assigned Trainings

+
+ + + + + + + + + + + + + + {% for training in assigned_trainings %} + + + + + + + + + + {% endfor %} + +
IDTitleDescriptionDue DateStatusTasksTraining Document
{{ training.training_id }}{{ training.training_name }}{{ training.training_description }}{{ training.training_due_date }}{{ training.status }} + + + +
+
+ {% endif %} +
+
+ {% endif %} + {% else %} +
+

Hi, please login or register to enroll into trainings.

-
-
-

Welcome Home :)

-
- - - \ No newline at end of file + {% endif %} +{% endblock %} diff --git a/trainingportal/templates/trainingportal/login.html b/trainingportal/templates/trainingportal/login.html index 6819c16..5246f42 100644 --- a/trainingportal/templates/trainingportal/login.html +++ b/trainingportal/templates/trainingportal/login.html @@ -1,27 +1,16 @@ - - - - {% load static %} - - - - - {% block title %}Login | Training Portal{% endblock %} - - -{# {% load bootstrap3 %}#} -{# {% bootstrap_css %}#} -

Login Form

+{% extends "trainingportal/base.html" %} +{% load static %} +{% block content %} +

Login Form

-

- {% if login_failed %} -
- Login Failed. -
- {% endif %} +
+ Login Failed. +
{% csrf_token %} {% for field in login_form %} @@ -30,7 +19,7 @@

Login {{ field }} {% if field.help_text %} -

{{ field.help_text|safe }}

+

{{ field.help_text|safe }}

{% endif %}

{% endfor %} @@ -42,7 +31,5 @@

Login

- - - - \ No newline at end of file + +{% endblock %} diff --git a/trainingportal/templates/trainingportal/registration.html b/trainingportal/templates/trainingportal/registration.html index 7bfb8be..66bb66c 100644 --- a/trainingportal/templates/trainingportal/registration.html +++ b/trainingportal/templates/trainingportal/registration.html @@ -1,64 +1,9 @@ - - - - - {# #} - {% block title %}Register | Training Portal{% endblock %} - - - - {% load bootstrap3 %} - {% load static %} - {% bootstrap_css %} -{#{% bootstrap_javascript %}#} -{#{% extends "base.html" %}#} -{# It is {% now "jS F Y H:i" %} now#} -{##} -{# {{ value|add:"2" }}#} -{##} -{# {{ data|default:"This is a string literal." }}#} -{##} -{# {{ None|default_if_none:"nothing" }}#} - -{# {% filter force_escape|upper %}#} -{# This text will be HTML-escaped, and will appear in all lowercase.#} -{# {% endfilter %}#} - -{# #} -{##} -{# {% if athlete_list %}#} -{# Number of athletes: {{ athlete_list|length }}#} -{# {% elif athlete_in_locker_room_list %}#} -{# Athletes should be out of the locker room soon!#} -{# {% else %}#} -{# No athletes.#} -{# {% endif %}#} - -{# {% if "Hello"|length >= 5 %}#} -{# You have lots of messages today!#} -{# {% endif %}#} - -{# #} -{##} -{#
#} -{# {% block content %}{% endblock %}#} -{#
#} -

Signup Form

+{% extends "trainingportal/base.html" %} +{% load bootstrap3 %} +{% load static %} +{% bootstrap_css %} +{% block content %} +

Signup Form

@@ -74,6 +19,5 @@

Signup {% endbuttons %}

- - \ No newline at end of file +{% endblock %} diff --git a/trainingportal/templates/trainingportal/submit_assignment.html b/trainingportal/templates/trainingportal/submit_assignment.html new file mode 100644 index 0000000..f06b499 --- /dev/null +++ b/trainingportal/templates/trainingportal/submit_assignment.html @@ -0,0 +1,33 @@ +{% extends "trainingportal/base.html" %} +{% load bootstrap3 %} +{% load static %} +{% bootstrap_css %} +{% block content %} +

Submit Assignment

+
+
+ + {% csrf_token %} + {% for field in assignment_form %} +
+ + {{ field.errors }} + + + {{ field }} + {% if field.help_text %} +

{{ field.help_text|safe }}

+ {% endif %} +
+ {% endfor %} +
+ +
+
+
+ + +{% endblock %} \ No newline at end of file diff --git a/trainingportal/templates/trainingportal/tasks.html b/trainingportal/templates/trainingportal/tasks.html new file mode 100644 index 0000000..2cfcb3a --- /dev/null +++ b/trainingportal/templates/trainingportal/tasks.html @@ -0,0 +1,87 @@ +{% extends "trainingportal/base.html" %} +{% load bootstrap3 %} +{% load static %} +{% bootstrap_css %} +{% block content %} + + +
+ {% if is_staff %} +
+ +
+ {% endif %} +
+ {% if no_tasks %} +

{{ no_tasks }}

+ {% else %} +

Tasks Assigned

+
+ + + + + + + + + + {% for task in tasks %} + + + + + + + {% endfor %} + +
IDTitleDescription
{{ task.id }}{{ task.title }}{{ task.description }} + +
+
+ {% endif %} +
+
+ + + + + +{% endblock %} \ No newline at end of file diff --git a/trainingportal/templates/trainingportal/trainees.html b/trainingportal/templates/trainingportal/trainees.html new file mode 100644 index 0000000..8fffed9 --- /dev/null +++ b/trainingportal/templates/trainingportal/trainees.html @@ -0,0 +1,87 @@ +{% extends "trainingportal/base.html" %} +{% load bootstrap3 %} +{% load static %} +{% bootstrap_css %} +{% block content %} +
+
+ {% if no_trainee %} +

{{ no_trainee }}

+ {% else %} +

Trainees Assigned

+
+ + + + + + + + + + + + {% for training in assigned_trainings %} + + + + + + + + + {% endfor %} + +
Trainee IDNameTraining NameStatusChange Status
{{ training.training_id }}{{ training.trainee_name }}{{ training.training_name }}{{ training.status }} + {% if training.status == 'Completed' %} + + {% else %} + + {% endif %} +
+
+ {% endif %} +
+
+ + + + + + +{% endblock %} \ No newline at end of file diff --git a/trainingportal/templates/trainingportal/trainings.html b/trainingportal/templates/trainingportal/trainings.html new file mode 100644 index 0000000..6bc9b04 --- /dev/null +++ b/trainingportal/templates/trainingportal/trainings.html @@ -0,0 +1,79 @@ +{% extends "trainingportal/base.html" %} +{% load bootstrap3 %} +{% load static %} +{% bootstrap_css %} +{% block content %} + + +
+
+ +
+
+

Assigned Trainings

+
+ + + + + + + + + + + + {% for training in trainings %} + + + + + + + + + + {% endfor %} + +
IDTitleDescriptionDocument PathDue Date
{{ training.id }}{{ training.title }}{{ training.description }}{{ training.document }}{{ training.due_date }}EditDelete
+
+
+
+ + + + + +{% endblock %} \ No newline at end of file diff --git a/trainingportal/urls.py b/trainingportal/urls.py index b11923d..45c7497 100644 --- a/trainingportal/urls.py +++ b/trainingportal/urls.py @@ -16,19 +16,71 @@ from django.contrib import admin from django.urls import path -from django.conf.urls import url -from . import views +from django.conf.urls import url, include from django.conf import settings from django.conf.urls.static import static from django.views.generic import RedirectView +# from django.contrib.auth.models import User + +from rest_framework.routers import DefaultRouter +# from rest_framework import routers +# from rest_framework import renderers +from rest_framework.schemas import get_schema_view + +#from .views import SnippetViewSet, UserViewSet +from . import views + +# snippet_list = SnippetViewSet.as_view({ +# 'get': 'list', +# 'post': 'create' +# }) +# snippet_detail = SnippetViewSet.as_view({ +# 'get': 'retrieve', +# 'put': 'update', +# 'patch': 'partial_update', +# 'delete': 'destroy' +# }) +# snippet_highlight = SnippetViewSet.as_view({ +# 'get': 'highlight' +# }, renderer_classes=[renderers.StaticHTMLRenderer]) +# user_list = UserViewSet.as_view({ +# 'get': 'list' +# }) +# user_detail = UserViewSet.as_view({ +# 'get': 'retrieve' +# }) + +app_name = 'trainingportal' + +# router = DefaultRouter() +# router.register(r'snippets', views.SnippetViewSet) +# router.register(r'users', views.UserViewSet) + +schema_view = get_schema_view(title='Pastebin API') urlpatterns = [ + #url(r'^', include(router.urls)), + # url(r'^schema/$', schema_view), + # url(r'^', include(router.urls)), + #url(r'^snippets/$', views.snippet_list), path('admin/', admin.site.urls), + #url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), url(r'^$', RedirectView.as_view(url='home/')), url(r'^home/', views.home, name='home'), url(r'^register/', views.register, name='register'), + url(r'^trainings/', views.training, name='training'), + url(r'^trainees/', views.trainees, name='trainees'), + path('edit//', views.edit_training, name='edit_training'), + path('delete_training/', views.delete_training, name='delete_training'), + path('training_status/', views.update_training_status, name='update_training_status'), + path('tasks/', views.tasks, name='tasks'), + path('assignments/', views.assignments, name='assignments'), + path('evaluate_assignment//', views.evaluate_assignment, name='evaluate_assignment'), + path('submit_assignment//', views.submit_assignment, name='submit_assignment'), + path('enroll_training/', views.enroll_training, name='enroll_training'), url(r'^login/', views.LoginView.as_view(), name='login'), url(r'^logout/', views.logout_view, name='logout'), url(r'^contact/', views.contact_us), -] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) +] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + \ + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ No newline at end of file diff --git a/trainingportal/views.py b/trainingportal/views.py index 9acccae..8004ea2 100644 --- a/trainingportal/views.py +++ b/trainingportal/views.py @@ -1,34 +1,191 @@ from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render, redirect -from trainingportal.forms import LoginForm, ProfileForm, UserForm from django.views.generic import View -from django.contrib.auth.models import User -from django.utils.translation import ugettext as _ +from django.contrib.auth.models import User, Group +from django.core.exceptions import PermissionDenied +#from django.utils.translation import ugettext as _ from django.contrib.auth.decorators import login_required -from django.contrib import auth +from django.views.decorators.csrf import csrf_exempt +from django.utils.decorators import method_decorator from django.contrib.auth import authenticate, login, logout -import pdb +#from django.core.files.storage import FileSystemStorage + +#import pdb +import json + +from rest_framework.renderers import JSONRenderer +from rest_framework.parsers import JSONParser +from rest_framework.response import Response +from rest_framework import permissions, generics, status, viewsets +from rest_framework.views import APIView +from rest_framework.decorators import api_view, permission_classes, detail_route +from rest_framework.reverse import reverse +from rest_framework import renderers + +from .serializers import SnippetSerializer, SnippetModelSerializer, UserSerializer, GroupSerializer +from .models import Training, Snippet, AssignedTraining, Trainee, Trainer, Task, Assignment +from .forms import LoginForm, ProfileForm, UserForm, AddTrainingForm, AssignmentForm, TaskForm, \ + EvaluateAssignmentForm, SubmitAssignmentForm +from django.http import QueryDict + + +# class UserViewSet(viewsets.ReadOnlyModelViewSet): +# """ +# This viewset automatically provides `list` and `detail` actions. +# """ +# queryset = User.objects.all() +# serializer_class = UserSerializer +# +# +# class SnippetViewSet(viewsets.ModelViewSet): +# """ +# This viewset automatically provides `list`, `create`, `retrieve`, +# `update` and `destroy` actions. +# +# Additionally we also provide an extra `highlight` action. +# """ +# queryset = Snippet.objects.all() +# serializer_class = SnippetSerializer +# permission_classes = (permissions.IsAuthenticatedOrReadOnly,) +# +# @detail_route(renderer_classes=[renderers.StaticHTMLRenderer]) +# def highlight(self, request, *args, **kwargs): +# snippet = self.get_object() +# return Response(snippet.highlighted) +# +# def perform_create(self, serializer): +# serializer.save(owner=self.request.user) + +# +# @api_view(['GET', 'POST']) +# @permission_classes((permissions.AllowAny,)) +# def snippet_list(request): +# """ +# List all code snippets, or create a new snippet. +# """ +# if request.method == 'GET': +# snippets = Snippet.objects.all() +# serializer = SnippetSerializer(snippets, many=True) +# return Response(serializer.data) +# +# elif request.method == 'POST': +# data = JSONParser().parse(request) +# serializer = SnippetSerializer(data=data) +# if serializer.is_valid(): +# serializer.save() +# return Response(serializer.data, status=status.HTTP_201_CREATED) +# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) +# + +# @api_view(['GET', 'PUT', 'DELETE']) +# @permission_classes((permissions.AllowAny,)) +# def snippet_detail(request, pk): +# """ +# Retrieve, update or delete a code snippet. +# """ +# +# permission_classes = (permissions.IsAuthenticatedOrReadOnly,) +# try: +# snippet = Snippet.objects.get(pk=pk) +# except Snippet.DoesNotExist: +# return Response(status=status.HTTP_404_NOT_FOUND) +# +# if request.method == 'GET': +# serializer = SnippetSerializer(snippet) +# return Response(serializer.data) +# +# elif request.method == 'PUT': +# serializer = SnippetSerializer(snippet, data=request.data) +# if serializer.is_valid(): +# serializer.save() +# return Response(serializer.data) +# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) +# +# elif request.method == 'DELETE': +# snippet.delete() +# return Response(status=status.HTTP_204_NO_CONTENT) + + +class GroupViewSet(viewsets.ModelViewSet): + """ + API endpoint that allows groups to be viewed or edited. + """ + queryset = Group.objects.all() + serializer_class = GroupSerializer def home(request): data ={} + + if request.user.id: + user_instance = User.objects.get(pk=request.user.id) + if (user_instance.is_staff): + trainer = Trainer.objects.get(user_id=user_instance.id) + assigned_trainings = AssignedTraining.objects.filter(trainer_id=trainer.id) + trainee_ids = [training.trainee_id.id for training in assigned_trainings] + trainees = Trainee.objects.filter(id__in=trainee_ids) + trainee_user_ids = [trainee.user_id for trainee in trainees] + trainees_user = User.objects.filter(id__in=trainee_user_ids) + + if assigned_trainings: + trainings = [] + for training in assigned_trainings: + assigned_training = { + 'trainee_id': training.trainee_id.id, + 'trainee_name': get_trainee_name(trainees_user, training), + 'training_name': training.training_id.title, + 'training_due_date': training.training_id.due_date, + 'status': 'Completed' if training.status else 'In Progress', + } + trainings.append(assigned_training) + + data['assigned_trainings'] = trainings + else: + data['no_trainee'] = 'No trainees assigned.' + else: + trainee = Trainee.objects.get(user_id=user_instance.id) + assigned_trainings = AssignedTraining.objects.filter(trainee_id=trainee.id) + + if assigned_trainings: + trainings = [] + for training in assigned_trainings: + assigned_training = { + 'id': training.id, + 'trainee_id': training.trainee_id.id, + 'trainer_id': training.trainer_id.id, + 'training_id': training.training_id.id, + 'training_description': training.training_id.description, + 'training_name': training.training_id.title, + 'training_due_date': training.training_id.due_date, + 'status': 'Completed' if training.status else 'In Progress', + } + trainings.append(assigned_training) + + data['assigned_trainings'] = trainings + else: + data['no_training'] = 'No enrolled trainings.' return render(request, 'trainingportal/home.html', data) + def logout_view(request): logout(request) return redirect(home) + class LoginView(View): + """ handles requests for login form and redirection """ + template_name = 'trainingportal/login.html' form_class = LoginForm - #initial = {'username': 'BRO!!'} - # success_url = '/thanks/' def get(self, request, *args, **kwargs): - login_form = self.form_class()#self.form_class(initial=self.initial) + login_form = self.form_class() return render(request, self.template_name, {'login_form': login_form}) def post(self, request, *args, **kwargs): login_form = self.form_class(request.POST) + data = { + 'failure_message': 'Login Failed', + } if login_form.is_valid(): try: user = authenticate( @@ -37,24 +194,21 @@ def post(self, request, *args, **kwargs): password=login_form.cleaned_data['password'] ) if user: - #request.session["remote_session_key"] = user.session_key login(request, user) - response = redirect(home) - return response + data['redirect_path'] = '/home/' + data.pop('failure_message', None) + return HttpResponse(json.dumps(data)) else: - return render(request, self.template_name, { - 'login_form': login_form, - 'login_failed': True - }) + return HttpResponse(json.dumps(data)) - except: - return render(request, self.template_name, {'login_form': login_form}) + except PermissionDenied: + return HttpResponse(json.dumps(data)) return render(request, self.template_name, {'login_form': login_form}) def register(request): - ''' handles requests for registeration form and its submission ''' + """ handles requests for registration form and its submission """ data = {} user_form = None profile_form = None @@ -75,11 +229,10 @@ def register(request): user_form.cleaned_data['email'], user_form.cleaned_data['password'] ) - #user = user_form.save() user.first_name = user_form.cleaned_data['first_name'] user.last_name = user_form.cleaned_data['last_name'] user.save() - profile_form.save(user) + profile_form.save(user=user) try: login_user = authenticate( request, @@ -89,13 +242,309 @@ def register(request): if login_user: login(request, login_user) return redirect(home) - except: + except PermissionDenied: return redirect(home) data["user_form"] = user_form or UserForm() data["profile_form"] = profile_form or ProfileForm() return render(request, 'trainingportal/registration.html', data) + +@login_required +def training(request): + """ handles requests for registration form and its submission """ + training_form = None + data = { + 'failure_message': 'Failed to add training.', + } + if request.method == 'POST': + training_form = AddTrainingForm(request.POST, request.FILES) + if training_form.is_valid(): + training_form.save() + data.pop('failure_message', None) + return HttpResponse(json.dumps(data)) + else: + return HttpResponse(json.dumps(data)) + + trainings = Training.objects.all() + data["training_form"] = training_form or AddTrainingForm() + data['trainings'] = trainings + return render(request, 'trainingportal/trainings.html', data) + + +@login_required +def edit_training(request, training_id): + """ handles requests for registration form and its submission """ + data = {} + training_form = None + data = { + 'failure_message': 'Error in form.', + 'delete_path': '/delete_training/' + } + training = Training.objects.get(pk=training_id) + if request.method == 'POST': + training_form = AddTrainingForm(request.POST, request.FILES, instance=training) + if training_form.is_valid(): + training_form.save() + data.pop('failure_message', None) + data['redirect_path'] = '/trainings/' + return HttpResponse(json.dumps(data)) + else: + return HttpResponse(json.dumps(data)) + + data["training_form"] = training_form or AddTrainingForm(instance=training) + data["training_id"] = training_id + return render(request, 'trainingportal/edit_training.html', data) + + +@login_required +def delete_training(request): + """ handles requests for deletion of a training """ + data = {} + if request.method == 'DELETE': + request.DELETE = QueryDict(request.body) + training_id = request.DELETE['training_id'] + print(training_id) + training = Training.objects.get(pk=training_id) + if training: + training.delete() + + data['success_message'] = 'Training deleted.' + data['redirect_path'] = '/trainings/' + return HttpResponse(json.dumps(data)) + + +@login_required +def trainees(request): + """ handles requests for populating trainees """ + data = {} + trainer_id = request.user.id + + assigned_trainings = AssignedTraining.objects.filter(trainer_id=trainer_id) + + if assigned_trainings: + #training_ids = [training.training_id.id for training in assigned_trainings] + trainee_ids = [training.trainee_id.id for training in assigned_trainings] + trainees = Trainee.objects.filter(id__in=trainee_ids) + trainee_user_ids = [trainee.user_id for trainee in trainees] + print(trainee_user_ids) + trainees_user = User.objects.filter(id__in=trainee_user_ids) + + trainees_training = [] + for training in assigned_trainings: + assigned_training = { + 'id': training.id, + 'training_id': training.training_id.id, + 'trainee_id': training.trainee_id.id, + 'trainer_id': training.trainer_id.id, + 'trainee_name': get_trainee_name(trainees_user, training), + 'training_name': training.training_id.title, + 'status': 'Completed' if training.status else 'In Progress', + } + trainees_training.append(assigned_training) + + data['assigned_trainings'] = trainees_training + else: + data['no_trainee'] = 'No trainees assigned.' + return render(request, 'trainingportal/trainees.html', data) + + +def get_trainee_name(trainees_user, training): + return "{} {}".format(trainees_user.get(pk=training.trainee_id.user_id).first_name, + trainees_user.get(pk=training.trainee_id.user_id).last_name) + + +@login_required +def update_training_status(request): + """ handles requests for populating trainees """ + + data = { + 'failure_message': 'Error Occured.', + } + if request.method == 'POST': + training_id = request.POST['training_id'] + print(training_id) + training = AssignedTraining.objects.get(pk=training_id) + if training: + training.status = True + training.save() + data['success_message'] = 'Status Updated.' + data.pop('failure_message', None) + return HttpResponse(json.dumps(data)) + else: + return HttpResponse(json.dumps(data)) + + +@login_required +def tasks(request): + """ handles requests for populating tasks """ + + task_form = None + data = { + 'failure_message': 'Failed to add Task.', + 'training_id': request.GET.get('training_id'), + 'trainer_id': request.GET.get('trainer_id'), + 'trainee_id': request.GET.get('trainee_id'), + } + + if request.method == 'POST': + training = Training.objects.get(pk=data['training_id']) + trainee = Trainee.objects.get(pk=data['trainee_id']) + trainer = Trainer.objects.get(pk=data['trainer_id']) + + task_form = TaskForm(request.POST) + if task_form.is_valid(): + task = task_form.save(commit=False) + task.training_id = training + task.trainee_id = trainee + task.trainer_id = trainer + task.save() + data.pop('failure_message', None) + return HttpResponse(json.dumps(data)) + else: + return HttpResponse(json.dumps(data)) + + tasks = Task.objects.filter(training_id=data['training_id']) + data["task_form"] = task_form or TaskForm() + + if tasks: + data['tasks'] = tasks + else: + data['no_tasks'] = 'No tasks assigned.' + + user_instance = User.objects.get(pk=request.user.id) + + if (user_instance.is_staff): + data['is_staff'] = 'Trainer' + + return render(request, 'trainingportal/tasks.html', data) + + +@login_required +def assignments(request): + """ handles requests for populating assignments """ + + assignment_form = None + data = { + 'failure_message': 'Failed to add Task.', + 'task_id': request.GET.get('task_id'), + } + + if request.method == 'POST': + task = Task.objects.get(pk=data['task_id']) + + assignment_form = AssignmentForm(request.POST, request.FILES) + if assignment_form.is_valid(): + assignment = assignment_form.save(commit=False) + assignment.task_id = task + assignment.save() + data.pop('failure_message', None) + return HttpResponse(json.dumps(data)) + else: + return HttpResponse(json.dumps(data)) + + assignments = Assignment.objects.filter(task_id=data['task_id']) + data["assignment_form"] = assignment_form or AssignmentForm() + + if assignments: + data['assignments'] = assignments + else: + data['no_assignments'] = 'No assignments assigned.' + + user_instance = User.objects.get(pk=request.user.id) + + if (user_instance.is_staff): + data['is_staff'] = 'Trainer' + + return render(request, 'trainingportal/assignments.html', data) + + +@login_required +def evaluate_assignment(request, assignment_id): + + assignment_form = None + data = { + 'failure_message': 'Failed to add Task.', + 'assignment_id': assignment_id + } + assignment = Assignment.objects.get(pk=assignment_id) + print("\n\nID:") + print(assignment.task_id.id) + if request.method == 'POST': + assignment_form = EvaluateAssignmentForm(request.POST, request.FILES, instance=assignment) + if assignment_form.is_valid(): + assignment_form.save() + data.pop('failure_message', None) + data["redirect_path"] = '/assignments/?task_id={}'.format(assignment.task_id.id) + return HttpResponse(json.dumps(data)) + else: + return HttpResponse(json.dumps(data)) + + data["assignment_form"] = assignment_form or EvaluateAssignmentForm(instance=assignment) + + return render(request, 'trainingportal/evaluate_assignment.html', data) + + +@login_required +def submit_assignment(request, assignment_id): + + assignment_form = None + data = { + 'failure_message': 'Failed to add Task.', + 'assignment_id': assignment_id + } + assignment = Assignment.objects.get(pk=assignment_id) + print("\n\nID:") + print(assignment.task_id.id) + if request.method == 'POST': + assignment_form = SubmitAssignmentForm(request.POST, request.FILES, instance=assignment) + if assignment_form.is_valid(): + assignment = assignment_form.save(commit=False) + assignment.status = True + assignment.save() + data.pop('failure_message', None) + data["redirect_path"] = '/assignments/?task_id={}'.format(assignment.task_id.id) + return HttpResponse(json.dumps(data)) + else: + return HttpResponse(json.dumps(data)) + + data["assignment_form"] = assignment_form or SubmitAssignmentForm(instance=assignment) + + return render(request, 'trainingportal/submit_assignment.html', data) + + +@login_required +def enroll_training(request): + """ handles requests for registration form and its submission """ + data = { + 'failure_message': 'Failed to add training.', + } + if request.method == 'POST': + selected_training_id = request.POST.get('training') + selected_trainer_id = request.POST.get('trainer') + training = Training.objects.get(pk=selected_training_id) + trainer = Trainer.objects.get(user_id=selected_trainer_id) + trainee = Trainee.objects.get(user_id=request.user.id) + + if AssignedTraining.objects.filter(trainee_id=trainee.id, training_id=training.id).exists(): + data['already_enrolled'] = "You are already enrolled in this training." + else: + assigned_training = AssignedTraining ( + training_id=training, + trainer_id=trainer, + trainee_id=trainee + ) + assigned_training.save() + return redirect(home) + + trainings = Training.objects.all() + data['trainings'] = trainings + + trainers = User.objects.filter(is_staff=True) + data['trainers'] = trainers + return render(request, 'trainingportal/enroll_training.html', data) + + @login_required def contact_us(request): - return render(request, 'trainingportal/contact.html') + return render(request, 'trainingportal/contact.html') \ No newline at end of file