From 43b0b06dbe374444e4e9a7cb939b4661f8d98815 Mon Sep 17 00:00:00 2001 From: wad Date: Tue, 19 Dec 2017 18:17:01 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=BE=D1=80=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BB=20=D0=B3=D0=B8=D1=82=D0=BB=D0=B0=D0=B1=20?= =?UTF-8?q?=D0=B2=D1=80=D0=B0=D0=BF=D0=BF=D0=B5=D1=80,=20=D0=BD=D0=B0?= =?UTF-8?q?=D0=BA=D0=B8=D0=B4=D0=B0=D0=BB=20=D0=90=D0=9F=D0=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gitlab_service/admin.py | 2 + gitlab_service/api.py | 52 +++++++++++++++ gitlab_service/apps.py | 2 + gitlab_service/gitlab_wrapper.py | 106 +++++++++++++++++++++++++++++++ gitlab_service/models.py | 20 +++++- gitlab_service/tests.py | 1 + gitlab_service/views.py | 2 + requirements.txt | 2 + 8 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 gitlab_service/api.py create mode 100644 gitlab_service/gitlab_wrapper.py diff --git a/gitlab_service/admin.py b/gitlab_service/admin.py index 8c38f3f..ab35bfd 100644 --- a/gitlab_service/admin.py +++ b/gitlab_service/admin.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + from django.contrib import admin # Register your models here. diff --git a/gitlab_service/api.py b/gitlab_service/api.py new file mode 100644 index 0000000..c974732 --- /dev/null +++ b/gitlab_service/api.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- + + +def create_user(email, name): + """ Создает пользователя в GitLab и возвращает токен пользователя для последующей работы """ + user_token = '...' + return user_token + + +def get_user(email, name): + """ Выбирает пользователя GitLab и возвращает токен пользователя для последующей работы """ + user_token = '...' + return user_token + + +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): + """ Принять домашку у студента, копировать новые файлы """ + # TODO возможно это на уровне LMS надо делать, а с гитлабом вызвать copy_files_to_repository + pass + + +def make_save_point(teacher, students): + """ зафиксировать точку в репах с принятыми домашками """ + pass + + +def get_last_changes(teacher, students, save_point=None): + """ показать последние изменения в репах учеников относительно save point (последнего, если None) """ + pass + diff --git a/gitlab_service/apps.py b/gitlab_service/apps.py index 79dbccb..51bc2d4 100644 --- a/gitlab_service/apps.py +++ b/gitlab_service/apps.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + from django.apps import AppConfig diff --git a/gitlab_service/gitlab_wrapper.py b/gitlab_service/gitlab_wrapper.py new file mode 100644 index 0000000..514f33d --- /dev/null +++ b/gitlab_service/gitlab_wrapper.py @@ -0,0 +1,106 @@ +# -*- 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 diff --git a/gitlab_service/models.py b/gitlab_service/models.py index 71a8362..dd796bb 100644 --- a/gitlab_service/models.py +++ b/gitlab_service/models.py @@ -1,3 +1,21 @@ +# -*- 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) + -# Create your models here. diff --git a/gitlab_service/tests.py b/gitlab_service/tests.py index 7ce503c..3c38043 100644 --- a/gitlab_service/tests.py +++ b/gitlab_service/tests.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- from django.test import TestCase # Create your tests here. diff --git a/gitlab_service/views.py b/gitlab_service/views.py index 91ea44a..050a3d8 100644 --- a/gitlab_service/views.py +++ b/gitlab_service/views.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + from django.shortcuts import render # Create your views here. diff --git a/requirements.txt b/requirements.txt index fa16d4f..b08a518 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,6 +14,7 @@ django-phonenumber-field==1.3.0 django-redis==4.8.0 django-redis-sessions==0.6.1 django-yandex-money==1.1.2 +django-model-utils==3.0.0 djangorestframework==3.7.0 environ==1.0 flower==0.9.2 @@ -25,6 +26,7 @@ olefile==0.44 Pillow==4.3.0 # pkg-resources==0.0.0 psycopg2==2.7.3.1 +python-gitlab==1.1.0 pytz==2017.2 raven==6.2.1 redis==2.10.6