parent
f7ea328315
commit
7f9f579d53
21 changed files with 104 additions and 265 deletions
@ -0,0 +1,31 @@ |
|||||||
|
# -*- coding: utf-8 -*- |
||||||
|
# Generated by Django 1.11.6 on 2018-01-23 10:11 |
||||||
|
from __future__ import unicode_literals |
||||||
|
|
||||||
|
from django.conf import settings |
||||||
|
import django.contrib.postgres.fields |
||||||
|
from django.db import migrations, models |
||||||
|
import django.db.models.deletion |
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration): |
||||||
|
|
||||||
|
dependencies = [ |
||||||
|
('access', '0002_init_group'), |
||||||
|
] |
||||||
|
|
||||||
|
operations = [ |
||||||
|
migrations.CreateModel( |
||||||
|
name='UserActivity', |
||||||
|
fields=[ |
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||||
|
('ip_list', django.contrib.postgres.fields.ArrayField(base_field=models.GenericIPAddressField(editable=False, verbose_name='Ip адресс'), default=[], size=None)), |
||||||
|
('last_request', models.DateTimeField(auto_now=True, verbose_name='Был в сети')), |
||||||
|
('owner', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), |
||||||
|
], |
||||||
|
options={ |
||||||
|
'verbose_name': 'Пользовательская активность', |
||||||
|
'verbose_name_plural': 'Пользовательская активность', |
||||||
|
}, |
||||||
|
), |
||||||
|
] |
||||||
@ -1,5 +0,0 @@ |
|||||||
# -*- coding: utf-8 -*- |
|
||||||
|
|
||||||
from django.contrib import admin |
|
||||||
|
|
||||||
# Register your models here. |
|
||||||
@ -1,88 +0,0 @@ |
|||||||
# -*- coding: utf-8 -*- |
|
||||||
|
|
||||||
# Сервис может |
|
||||||
# интерфейс учителя: |
|
||||||
# - логин |
|
||||||
# - выбор курса для работы |
|
||||||
# - привязка (или создание) репы для курса (можно через веб) |
|
||||||
# - прописывание соответствий ДЗ курса <-> путь в репе (можно через веб) |
|
||||||
# - clone всех реп учеников данного курса и базовой репы |
|
||||||
# - pull всех изменений реп студентов данного курса |
|
||||||
# - push всех новых коммитов учителя в репы студентов (+ save point опционально) |
|
||||||
# - changes по всем репам студентов данного курса с момента последнего save point (можно через веб) |
|
||||||
# - save point состояния реп студентов (можно через веб) |
|
||||||
# - разнесение изменений в базовой репе по репам студентов |
|
||||||
|
|
||||||
# соотвтествие путей в гите к курсам/домашкам храним у себя, какая домашка следующая для ученика - спрашиваем ЛМС |
|
||||||
|
|
||||||
# запросы к ЛМС |
|
||||||
# - get по токену получить ИД учителя, емейл и имя |
|
||||||
# - get по ИД учителя список его курсов (ИД, название) |
|
||||||
# - get по ИД курса список всех опубликованных домашек (ИД, название) |
|
||||||
# - get по ИД учителя и ИД курса список всех его студентов (ИД, емейл, имя) |
|
||||||
# - get по ИД курса + ИД студента + ИД домашки дай следующую доамашку (ИД, название) |
|
||||||
# - post ИД студента, ИД домашки - ДЗ принято |
|
||||||
|
|
||||||
|
|
||||||
# запросы к сервису |
|
||||||
# - get получение пользователя |
|
||||||
# - get |
|
||||||
|
|
||||||
def register_user(email, name): |
|
||||||
""" Создает пользователя в сервисе и возвращает токен пользователя для последующей работы """ |
|
||||||
user_token = '...' |
|
||||||
return user_token |
|
||||||
|
|
||||||
|
|
||||||
def get_user(email): |
|
||||||
""" Выбирает пользователя сервиса возвращает токен пользователя для последующей работы """ |
|
||||||
user_token = '...' |
|
||||||
return user_token |
|
||||||
|
|
||||||
|
|
||||||
def create_git_user(user): |
|
||||||
""" Создает пользователя в GitLab""" |
|
||||||
pass |
|
||||||
|
|
||||||
|
|
||||||
def get_users(emails): |
|
||||||
""" Выбирает пользователей GitLab и возвращает токены для последующей работы """ |
|
||||||
tokens = ['...', '...', '...', ] |
|
||||||
return tokens |
|
||||||
|
|
||||||
|
|
||||||
def create_repository(user, project_name): |
|
||||||
""" Создает проект (репу) в GitLab и возвращает токен репу """ |
|
||||||
repository_token = '...' |
|
||||||
return repository_token |
|
||||||
|
|
||||||
|
|
||||||
def get_repository(user, project_name): |
|
||||||
""" Возвращает токен репы """ |
|
||||||
repository_token = '...' |
|
||||||
return repository_token |
|
||||||
|
|
||||||
|
|
||||||
def make_user_project_master(user, project): |
|
||||||
""" Делает пользователя мастером в проекте """ |
|
||||||
pass |
|
||||||
|
|
||||||
|
|
||||||
def copy_files_to_repository(base_repository, files_path, target_repository, autor): |
|
||||||
""" Копирует файлы из базовой репы в целевую от имени автора """ |
|
||||||
pass |
|
||||||
|
|
||||||
|
|
||||||
def approve_homework(teacher, base_repository, student, target_repository, files_path): |
|
||||||
""" Принять домашку у студента, копировать новые файлы """ |
|
||||||
pass |
|
||||||
|
|
||||||
|
|
||||||
def make_save_point(teacher, students): |
|
||||||
""" зафиксировать точку в репах с принятыми домашками """ |
|
||||||
pass |
|
||||||
|
|
||||||
|
|
||||||
def get_last_changes(teacher, students, save_point=None): |
|
||||||
""" показать последние изменения в репах учеников относительно save point (последнего, если None) """ |
|
||||||
pass |
|
||||||
@ -1,7 +0,0 @@ |
|||||||
# -*- coding: utf-8 -*- |
|
||||||
|
|
||||||
from django.apps import AppConfig |
|
||||||
|
|
||||||
|
|
||||||
class GitlabServiceConfig(AppConfig): |
|
||||||
name = 'gitlab_service' |
|
||||||
@ -1,106 +0,0 @@ |
|||||||
# -*- coding: utf-8 -*- |
|
||||||
import gitlab |
|
||||||
|
|
||||||
|
|
||||||
class GitlabWrapperException(Exception): |
|
||||||
pass |
|
||||||
|
|
||||||
|
|
||||||
class GitlabWrapperFilesExists(GitlabWrapperException): |
|
||||||
pass |
|
||||||
|
|
||||||
|
|
||||||
class GitlabWrapper: |
|
||||||
API_VERSION = '4' |
|
||||||
|
|
||||||
def __init__(self, url, token, ssl_verify=True): |
|
||||||
self.url = url |
|
||||||
self.token = token |
|
||||||
self.gl = gitlab.Gitlab( |
|
||||||
url=self.url, private_token=self.token, api_version=self.API_VERSION, ssl_verify=ssl_verify) |
|
||||||
|
|
||||||
def get_user(self, email): |
|
||||||
exists_users = self.gl.users.list(search=email) |
|
||||||
if exists_users: |
|
||||||
return exists_users[0] |
|
||||||
|
|
||||||
def create_user(self, email, name): |
|
||||||
username = email[:email.find('@')].replace('.', '_') |
|
||||||
# TODO can contain only letters, digits, '_', '-' and '.'. |
|
||||||
# TODO Cannot start with '-' or end in '.', '.git' or '.atom'." |
|
||||||
exists_users = self.gl.users.list(username=username) |
|
||||||
if len(exists_users): |
|
||||||
username = username + '_{}'.format(len(exists_users) + 1) |
|
||||||
user_data = dict( |
|
||||||
email=email, |
|
||||||
username=username, |
|
||||||
name=name, |
|
||||||
reset_password=True, |
|
||||||
) |
|
||||||
new_user = self.gl.users.create(user_data) |
|
||||||
return new_user |
|
||||||
|
|
||||||
def get_or_create_user(self, email, name): |
|
||||||
user = self.get_user(email) |
|
||||||
if user is None: |
|
||||||
user = self.create_user(email, name) |
|
||||||
return user |
|
||||||
|
|
||||||
def get_user_project(self, user, project_name): |
|
||||||
try: |
|
||||||
exists_project = self.gl.projects.get('{}/{}'.format(user.username, project_name)) |
|
||||||
return exists_project |
|
||||||
except gitlab.GitlabGetError: |
|
||||||
return None |
|
||||||
|
|
||||||
def create_user_project(self, user, project_name): |
|
||||||
user.projects.create(data={'name': project_name}) |
|
||||||
# делаем еще запрос, для получения проекта со всеми аттрибутами |
|
||||||
new_project = self.gl.projects.get('{}/{}'.format(user.username, project_name)) |
|
||||||
return new_project |
|
||||||
|
|
||||||
def get_or_create_user_project(self, user, project_name): |
|
||||||
project = self.get_user_project(user, project_name) |
|
||||||
if project is None: |
|
||||||
project = self.create_user_project(user, project_name) |
|
||||||
return project |
|
||||||
|
|
||||||
def make_user_project_master(self, user, project): |
|
||||||
try: |
|
||||||
project.members.create(data=dict( |
|
||||||
user_id=user.id, |
|
||||||
access_level=40, |
|
||||||
)) |
|
||||||
except gitlab.GitlabCreateError: |
|
||||||
pass |
|
||||||
|
|
||||||
def copy_files_to_repository(self, base_project, files_path, target_project, autor): |
|
||||||
commit_actions = [] |
|
||||||
items = base_project.repository_tree(path=files_path, recursive=True) |
|
||||||
for item in items: |
|
||||||
# item = {'name': '__init__.py', 'path': 'module_01/lesson_01/__init__.py', 'type': 'blob', |
|
||||||
# 'id': '633f866158ac742cf754a2c43edcb07e3a094f3c', 'mode': '100644'} |
|
||||||
if item['type'] == 'blob': |
|
||||||
file_sha = item['id'] |
|
||||||
file_info = base_project.repository_blob(sha=file_sha) |
|
||||||
# file_info = {'content': 'IyAtKi0gY29kaW5nOiB1dGYtOCAtKi0KCg==', 'size': 25, |
|
||||||
# 'sha': '633f866158ac742cf754a2c43edcb07e3a094f3c', 'encoding': 'base64'} |
|
||||||
action = dict( |
|
||||||
action='create', |
|
||||||
file_path=item['path'], |
|
||||||
content=file_info['content'], |
|
||||||
encoding='base64', |
|
||||||
) |
|
||||||
commit_actions.append(action) |
|
||||||
commit_data = { |
|
||||||
'branch': 'master', |
|
||||||
'commit_message': 'Add {}'.format(files_path), |
|
||||||
'actions': commit_actions |
|
||||||
} |
|
||||||
try: |
|
||||||
commit = target_project.commits.create(commit_data, sudo=autor) |
|
||||||
return commit |
|
||||||
except gitlab.GitlabCreateError as exc: |
|
||||||
if exc.response_code == 400: |
|
||||||
raise GitlabWrapperFilesExists() |
|
||||||
raise |
|
||||||
@ -1,21 +0,0 @@ |
|||||||
# -*- coding: utf-8 -*- |
|
||||||
|
|
||||||
from django.db import models |
|
||||||
from model_utils import Choices |
|
||||||
|
|
||||||
|
|
||||||
class User(models.Model): |
|
||||||
ROLES = Choices( |
|
||||||
('student', 'Студент'), |
|
||||||
('teacher', 'Преподователь'), |
|
||||||
) |
|
||||||
|
|
||||||
token = models.CharField(max_length=256) |
|
||||||
role = models.CharField(max_length=32, choices=ROLES, default=ROLES.student) |
|
||||||
|
|
||||||
|
|
||||||
class Repository(models.Model): |
|
||||||
user = models.ForeignKey(User) |
|
||||||
name = models.CharField(max_length=256) |
|
||||||
|
|
||||||
|
|
||||||
@ -1,4 +0,0 @@ |
|||||||
# -*- coding: utf-8 -*- |
|
||||||
from django.test import TestCase |
|
||||||
|
|
||||||
# Create your tests here. |
|
||||||
@ -1,5 +0,0 @@ |
|||||||
# -*- coding: utf-8 -*- |
|
||||||
|
|
||||||
from django.shortcuts import render |
|
||||||
|
|
||||||
# Create your views here. |
|
||||||
Loading…
Reference in new issue