diff --git a/Pipfile b/Pipfile index 6a7009047..19f720a83 100644 --- a/Pipfile +++ b/Pipfile @@ -31,6 +31,8 @@ docs="mkdocs serve --livereload" generate_docs="mkdocs build" doctor="python -m scripts.doctor" docs_deploy="mkdocs gh-deploy -c" +sign_jwt="python manage.py sign_jwt" +sign_request="python manage.py sign_request" [dev-packages] pytest-cov = "*" diff --git a/README.md b/README.md index a66af11d0..dbe112fa3 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,10 @@
@@ -43,111 +41,95 @@ Check out the [Postman docs](https://documenter.getpostman.com/view/2432393/T1LP
The documentation is divided into several sections:
-- [No Installation (with gitpod)](#working-inside-gitpod-no-instalation)
- - [How to work Gitpod](#how-to-work-gitpod)
- - [Add the browser extension](#add-the-browser-extension)
- - [How to use Gitpod browser extension](#how-to-use-gitpod-browser-extension)
-- [Installation inside Docker (easier)](#working-inside-docker-easier)
- - [Build BreatheCode Dev docker image](#build-breathecode-dev-docker-image)
- - [Testing inside BreatheCode Dev](#testing-inside-breathecode-dev)
- - [Run BreatheCode API as docker service](#run-breathecode-api-as-docker-service)
-- [Installation in your local machine (a bit harder but more performant)](#working-in-your-local-machine-recomended)
- - [Installation in your local machine](#installation-in-your-local-machine)
- - [Testing in your local machine](#testing-in-your-local-machine)
- - [Run BreatheCode API in your local machine](#run-breathecode-api-in-your-local-machine)
-
-## Working inside Gitpod (no installation)
-
-### `How to work Gitpod`
-Creating a workspace is as easy as prefixing any GitHub URL with `gitpod.io/#`.
+- [Run 4Geeks in Codespaces (no installation)](#run-4geeks-in-codespaces-no-instalation)
+- [Install Docker](#install-docker)
+- [Run 4Geeks API as docker service](#run-4geeks-api-as-docker-service)
+- [Run 4Geeks in your local machine](#run-4geeks-api-in-your-local-machine)
+ - [Installation](#installation)
+ - [Run 4Geeks API](#run-4geeks-api)
+- [Run tests](#run-tests)
-### `Add the browser extension`
+## Run 4Geeks in Codespaces (no installation)
-Gitpod provide the extension for:
+Click `Code` -> `Codespaces` -> `Create namespace on {BRANCH_NAME}`.
-- [Chrome](https://chrome.google.com/webstore/detail/gitpod-online-ide/dodmmooeoklaejobgleioelladacbeki) - also works for Edge, Brave and other Chromium-based browsers.
-- [Firefox](https://addons.mozilla.org/firefox/addon/gitpod/)
+![Codespaces](docs/images/codespaces.png)
-### `How to use Gitpod browser extension`
+## Install Docker
-For convenience, Gitpod developed a Gitpod browser extension. It adds a button to GitHub, GitLab or Bitbucket that does the prefixing for you - as simple as that.
+Install [docker desktop](https://www.docker.com/products/docker-desktop) in your Windows, else find a guide to install Docker and Docker Compose in your linux distribution `uname -a`.
-![How to use gitpod extension](https://www.gitpod.io/images/docs/browser-extension-lense.png)
+## Running 4geeks
-## Working inside Docker (easier)
+### `Run 4Geeks API as docker service`
-### `Build BreatheCode Dev docker image`
+```bash
+# open 4Geeks API as a service and export the port 8000
+docker-compose up -d
-For mac and pc users install [docker desktop](https://www.docker.com/products/docker-desktop), else, for linux find a guide to install Docker and Docker Compose in your linux distribution `uname -a`.
+# create super user
+sudo docker compose run 4geeks python manage.py createsuperuser
-```bash
-# Check which dependencies you need install in you operating system
-python -m scripts.doctor
+# See the output of Django
+docker-compose logs -f 4geeks
-# Generate the BreatheCode Dev docker image
-docker-compose build bc-dev
+# open localhost:8000 to view the api
+# open localhost:8000/admin to view the admin
```
-### `Testing inside BreatheCode Dev`
+### `Run 4Geeks in your local machine`
-```bash
-# Open the BreatheCode Dev, this shell don't export the port 8000
-docker-compose run bc-dev fish
+#### Installation
-# Testing
-pipenv run test ./breathecode/activity # path
-
-# Testing in parallel
-pipenv run ptest ./breathecode/activity # path
+```bash
+# Check which dependencies you need install in your operating system
+python -m scripts.doctor
-# Coverage
-pipenv run cov breathecode.activity # python module path
+# Setting up the redis and postgres database, you also can install manually in your local machine this databases
+docker-compose up -d redis postgres
-# Coverage in parallel
-pipenv run pcov breathecode.activity # python module path
+# Install and setting up your development environment (this command replace your .env file)
+python -m scripts.install
```
-### `Run BreatheCode API as docker service`
+#### Run 4Geeks API
+
+You must up Redis and Postgres before open 4Geeks.
```bash
-# open BreatheCode API as a service and export the port 8000
-docker-compose up -d bc-dev
+# Collect statics
+pipenv run python manage.py collectstatic --noinput
-# open the BreatheCode Dev, this shell don't export the port 8000
-docker-compose run bc-dev fish
+# Run migrations
+pipenv run python manage.py migrate
-# create super user
-pipenv run python manage.py createsuperuser
+# Load fixtures (populate the database)
+pipenv run python manage.py loaddata breathecode/*/fixtures/dev_*.json
-# Close the BreatheCode Dev
-exit
+# Create super user
+pipenv run python manage.py createsuperuser
-# See the output of Django
-docker-compose logs -f bc-dev
+# Run server
+pipenv run start
# open localhost:8000 to view the api
# open localhost:8000/admin to view the admin
```
-## Working in your local machine (recommended)
-
-### `Installation in your local machine`
+### `Testing in your local machine`
-Install [docker desktop](https://www.docker.com/products/docker-desktop) in your Windows, else find a guide to install Docker and Docker Compose in your linux distribution `uname -a`.
+#### Installation
```bash
# Check which dependencies you need install in your operating system
python -m scripts.doctor
-# Setting up the redis and postgres database, you also can install manually in your local machine this databases
-docker-compose up -d redis postgres
-
# Install and setting up your development environment (this command replace your .env file)
python -m scripts.install
```
-### `Testing in your local machine`
+#### Run tests
```bash
# Testing
@@ -162,25 +144,3 @@ pipenv run cov breathecode.activity # python module path
# Coverage in parallel
pipenv run pcov breathecode.activity # python module path
```
-
-### `Run BreatheCode API in your local machine`
-
-```bash
-# Collect statics
-pipenv run python manage.py collectstatic --noinput
-
-# Run migrations
-pipenv run python manage.py migrate
-
-# Load fixtures (populate the database)
-pipenv run python manage.py loaddata breathecode/*/fixtures/dev_*.json
-
-# Create super user
-pipenv run python manage.py createsuperuser
-
-# Run server
-pipenv run start
-
-# open localhost:8000 to view the api
-# open localhost:8000/admin to view the admin
-```
diff --git a/breathecode/admissions/migrations/0059_alter_cohortuser_history_log.py b/breathecode/admissions/migrations/0059_alter_cohortuser_history_log.py
new file mode 100644
index 000000000..1ee76ae70
--- /dev/null
+++ b/breathecode/admissions/migrations/0059_alter_cohortuser_history_log.py
@@ -0,0 +1,22 @@
+# Generated by Django 3.2.20 on 2023-08-05 03:23
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('admissions', '0058_alter_cohort_available_as_saas'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='cohortuser',
+ name='history_log',
+ field=models.JSONField(
+ blank=True,
+ default=dict,
+ help_text=
+ 'The cohort user log will save attendancy and information about progress on each class'),
+ ),
+ ]
diff --git a/breathecode/admissions/models.py b/breathecode/admissions/models.py
index b3a6b427f..cc5b8e400 100644
--- a/breathecode/admissions/models.py
+++ b/breathecode/admissions/models.py
@@ -476,7 +476,7 @@ def __init__(self, *args, **kwargs):
default=False, help_text='You can active students to the watch list and monitor them closely')
history_log = models.JSONField(
- default=dict(),
+ default=dict,
blank=True,
null=False,
help_text='The cohort user log will save attendancy and information about progress on each class')
diff --git a/breathecode/assignments/tasks.py b/breathecode/assignments/tasks.py
index ac38a4850..5b77d8329 100644
--- a/breathecode/assignments/tasks.py
+++ b/breathecode/assignments/tasks.py
@@ -7,6 +7,7 @@
from breathecode.assignments.actions import task_is_valid_for_notifications, NOTIFICATION_STRINGS
import breathecode.notify.actions as actions
+from breathecode.utils.service import Service
from .models import Task
# Get an instance of a logger
@@ -115,4 +116,25 @@ def serialize_task(task):
cohort_user.history_log = user_history_log
cohort_user.save()
+ s = None
+ try:
+ if hasattr(task.user, 'credentialsgithub') and task.github_url:
+ s = Service('rigobot', task.user.id)
+
+ if s and task.task_status == 'DONE':
+ s.post('/v1/finetuning/me/repository/',
+ json={
+ 'url': task.github_url,
+ 'watchers': task.user.credentialsgithub.username,
+ })
+
+ elif s:
+ s.put('/v1/finetuning/me/repository/',
+ json={
+ 'url': task.github_url,
+ 'activity_status': 'INACTIVE',
+ })
+ except:
+ logger.error('App Rigobot not found')
+
logger.info('History log saved')
diff --git a/breathecode/assignments/tests/tasks/tests_set_cohort_user_assignments.py b/breathecode/assignments/tests/tasks/tests_set_cohort_user_assignments.py
index 61dd9a552..06164c5e2 100644
--- a/breathecode/assignments/tests/tasks/tests_set_cohort_user_assignments.py
+++ b/breathecode/assignments/tests/tasks/tests_set_cohort_user_assignments.py
@@ -10,6 +10,7 @@
from ..mixins import AssignmentsTestCase
from ...tasks import set_cohort_user_assignments
+from breathecode.utils.service import Service
class MediaTestSuite(AssignmentsTestCase):
@@ -260,6 +261,229 @@ def test__with_one_task__task_is_pending__with_log__from_different_items(self):
])
self.assertEqual(Logger.error.call_args_list, [])
+ @patch('logging.Logger.info', MagicMock())
+ @patch('logging.Logger.error', MagicMock())
+ @patch('breathecode.assignments.signals.assignment_created.send', MagicMock())
+ @patch('breathecode.assignments.signals.assignment_status_updated.send', MagicMock())
+ @patch('breathecode.activity.tasks.get_attendancy_log.delay', MagicMock())
+ @patch('django.db.models.signals.pre_delete.send', MagicMock(return_value=None))
+ @patch('breathecode.admissions.signals.student_edu_status_updated.send', MagicMock(return_value=None))
+ def test__rigobot_not_found(self):
+ task_type = random.choice(['LESSON', 'QUIZ', 'PROJECT', 'EXERCISE'])
+ task = {
+ 'task_status': 'PENDING',
+ 'task_type': task_type,
+ 'github_url': self.bc.fake.url(),
+ }
+ cohort_user = {
+ 'history_log': {
+ 'delivered_assignments': [
+ {
+ 'id': 3,
+ 'type': task_type,
+ },
+ ],
+ 'pending_assignments': [
+ {
+ 'id': 2,
+ 'type': task_type,
+ },
+ ],
+ }
+ }
+ model = self.bc.database.create(task=task, cohort_user=cohort_user, credentials_github=1)
+
+ Logger.info.call_args_list = []
+
+ set_cohort_user_assignments.delay(1)
+
+ self.assertEqual(self.bc.database.list_of('assignments.Task'), [self.bc.format.to_dict(model.task)])
+ self.assertEqual(self.bc.database.list_of('admissions.CohortUser'), [
+ {
+ **self.bc.format.to_dict(model.cohort_user),
+ 'history_log': {
+ 'delivered_assignments': [
+ {
+ 'id': 3,
+ 'type': task_type,
+ },
+ ],
+ 'pending_assignments': [
+ {
+ 'id': 2,
+ 'type': task_type,
+ },
+ {
+ 'id': 1,
+ 'type': task_type,
+ },
+ ],
+ },
+ },
+ ])
+ self.assertEqual(Logger.info.call_args_list, [
+ call('Executing set_cohort_user_assignments'),
+ call('History log saved'),
+ ])
+ self.assertEqual(Logger.error.call_args_list, [call('App Rigobot not found')])
+
+ @patch('logging.Logger.info', MagicMock())
+ @patch('logging.Logger.error', MagicMock())
+ @patch('breathecode.assignments.signals.assignment_created.send', MagicMock())
+ @patch('breathecode.assignments.signals.assignment_status_updated.send', MagicMock())
+ @patch('breathecode.activity.tasks.get_attendancy_log.delay', MagicMock())
+ @patch('django.db.models.signals.pre_delete.send', MagicMock(return_value=None))
+ @patch('breathecode.admissions.signals.student_edu_status_updated.send', MagicMock(return_value=None))
+ @patch.multiple('breathecode.utils.service.Service',
+ __init__=MagicMock(return_value=None),
+ post=MagicMock(return_value=None),
+ put=MagicMock(return_value=None))
+ def test__rigobot_cancelled_revision(self):
+ task_type = random.choice(['LESSON', 'QUIZ', 'PROJECT', 'EXERCISE'])
+ task = {
+ 'task_status': 'PENDING',
+ 'task_type': task_type,
+ 'github_url': self.bc.fake.url(),
+ }
+ cohort_user = {
+ 'history_log': {
+ 'delivered_assignments': [
+ {
+ 'id': 3,
+ 'type': task_type,
+ },
+ ],
+ 'pending_assignments': [
+ {
+ 'id': 2,
+ 'type': task_type,
+ },
+ ],
+ }
+ }
+ model = self.bc.database.create(task=task, cohort_user=cohort_user, credentials_github=1)
+
+ Logger.info.call_args_list = []
+
+ set_cohort_user_assignments.delay(1)
+
+ self.assertEqual(self.bc.database.list_of('assignments.Task'), [self.bc.format.to_dict(model.task)])
+ self.assertEqual(self.bc.database.list_of('admissions.CohortUser'), [
+ {
+ **self.bc.format.to_dict(model.cohort_user),
+ 'history_log': {
+ 'delivered_assignments': [
+ {
+ 'id': 3,
+ 'type': task_type,
+ },
+ ],
+ 'pending_assignments': [
+ {
+ 'id': 2,
+ 'type': task_type,
+ },
+ {
+ 'id': 1,
+ 'type': task_type,
+ },
+ ],
+ },
+ },
+ ])
+ self.assertEqual(Logger.info.call_args_list, [
+ call('Executing set_cohort_user_assignments'),
+ call('History log saved'),
+ ])
+ self.assertEqual(Logger.error.call_args_list, [])
+ self.bc.check.calls(Service.__init__.call_args_list, [call('rigobot', 1)])
+ self.bc.check.calls(Service.post.call_args_list, [])
+ self.bc.check.calls(Service.put.call_args_list, [
+ call('/v1/finetuning/me/repository/',
+ json={
+ 'url': model.task.github_url,
+ 'activity_status': 'INACTIVE'
+ })
+ ])
+
+ @patch('logging.Logger.info', MagicMock())
+ @patch('logging.Logger.error', MagicMock())
+ @patch('breathecode.assignments.signals.assignment_created.send', MagicMock())
+ @patch('breathecode.assignments.signals.assignment_status_updated.send', MagicMock())
+ @patch('breathecode.activity.tasks.get_attendancy_log.delay', MagicMock())
+ @patch('django.db.models.signals.pre_delete.send', MagicMock(return_value=None))
+ @patch('breathecode.admissions.signals.student_edu_status_updated.send', MagicMock(return_value=None))
+ @patch.multiple('breathecode.utils.service.Service',
+ __init__=MagicMock(return_value=None),
+ post=MagicMock(return_value=None),
+ put=MagicMock(return_value=None))
+ def test__rigobot_schedule_revision(self):
+ task_type = random.choice(['LESSON', 'QUIZ', 'PROJECT', 'EXERCISE'])
+ task = {
+ 'task_status': 'DONE',
+ 'task_type': task_type,
+ 'github_url': self.bc.fake.url(),
+ }
+ cohort_user = {
+ 'history_log': {
+ 'delivered_assignments': [
+ {
+ 'id': 3,
+ 'type': task_type,
+ },
+ ],
+ 'pending_assignments': [
+ {
+ 'id': 2,
+ 'type': task_type,
+ },
+ ],
+ }
+ }
+ model = self.bc.database.create(task=task, cohort_user=cohort_user, credentials_github=1)
+
+ Logger.info.call_args_list = []
+
+ set_cohort_user_assignments.delay(1)
+
+ self.assertEqual(self.bc.database.list_of('assignments.Task'), [self.bc.format.to_dict(model.task)])
+ self.assertEqual(self.bc.database.list_of('admissions.CohortUser'), [
+ {
+ **self.bc.format.to_dict(model.cohort_user),
+ 'history_log': {
+ 'delivered_assignments': [
+ {
+ 'id': 3,
+ 'type': task_type,
+ },
+ {
+ 'id': 1,
+ 'type': task_type,
+ },
+ ],
+ 'pending_assignments': [
+ {
+ 'id': 2,
+ 'type': task_type,
+ },
+ ],
+ },
+ },
+ ])
+ self.assertEqual(Logger.info.call_args_list, [
+ call('Executing set_cohort_user_assignments'),
+ call('History log saved'),
+ ])
+ self.assertEqual(Logger.error.call_args_list, [])
+ self.bc.check.calls(Service.__init__.call_args_list, [call('rigobot', 1)])
+ self.bc.check.calls(
+ Service.post.call_args_list,
+ [call('/v1/finetuning/me/repository/', json={
+ 'url': model.task.github_url,
+ 'watchers': None
+ })])
+ self.bc.check.calls(Service.put.call_args_list, [])
+
@patch('logging.Logger.info', MagicMock())
@patch('logging.Logger.error', MagicMock())
@patch('breathecode.assignments.signals.assignment_created.send', MagicMock())
diff --git a/breathecode/assignments/tests/urls/tests_academy_task_id_coderevision.py b/breathecode/assignments/tests/urls/tests_academy_task_id_coderevision.py
new file mode 100644
index 000000000..281769e48
--- /dev/null
+++ b/breathecode/assignments/tests/urls/tests_academy_task_id_coderevision.py
@@ -0,0 +1,93 @@
+"""
+Test /answer
+"""
+import json
+import random
+from unittest.mock import MagicMock, call, patch
+
+from django.urls.base import reverse_lazy
+from rest_framework import status
+
+from breathecode.utils.service import Service
+
+from ..mixins import AssignmentsTestCase
+
+
+class MediaTestSuite(AssignmentsTestCase):
+
+ # When: no auth
+ # Then: response 401
+ def test_no_auth(self):
+ url = reverse_lazy('assignments:academy_task_id_coderevision', kwargs={'task_id': 1})
+ response = self.client.get(url)
+
+ json = response.json()
+ expected = {'detail': 'Authentication credentials were not provided.', 'status_code': 401}
+
+ self.assertEqual(json, expected)
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+ self.assertEqual(self.bc.database.list_of('assignments.Task'), [])
+
+ # When: no capability
+ # Then: response 403
+ def test_no_capability(self):
+ model = self.bc.database.create(user=1)
+
+ self.bc.request.set_headers(academy=1)
+ self.bc.request.authenticate(model.user)
+
+ url = reverse_lazy('assignments:academy_task_id_coderevision', kwargs={'task_id': 1})
+ response = self.client.get(url)
+
+ json = response.json()
+ expected = {
+ 'detail': 'You (user: 1) don\'t have this capability: read_assignment for academy 1',
+ 'status_code': 403,
+ }
+
+ self.assertEqual(json, expected)
+ self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
+ self.assertEqual(self.bc.database.list_of('assignments.Task'), [])
+
+ # When: auth
+ # Then: response 200
+ def test_auth(self):
+ self.bc.request.set_headers(academy=1)
+
+ expected = {'data': {'getTask': {'id': random.randint(1, 100)}}}
+ query = {
+ self.bc.fake.slug(): self.bc.fake.slug(),
+ self.bc.fake.slug(): self.bc.fake.slug(),
+ self.bc.fake.slug(): self.bc.fake.slug(),
+ }
+
+ mock = MagicMock()
+ mock.raw = iter([json.dumps(expected).encode()])
+ mock.headers = {'Content-Type': 'application/json'}
+ code = random.randint(200, 299)
+ mock.status_code = code
+ mock.reason = 'OK'
+
+ task = {'github_url': self.bc.fake.url()}
+ model = self.bc.database.create(profile_academy=1, task=task, role=1, capability='read_assignment')
+ self.bc.request.authenticate(model.user)
+
+ url = reverse_lazy('assignments:academy_task_id_coderevision',
+ kwargs={'task_id': 1}) + '?' + self.bc.format.querystring(query)
+
+ with patch.multiple('breathecode.utils.service.Service',
+ __init__=MagicMock(return_value=None),
+ get=MagicMock(return_value=mock)):
+ response = self.client.get(url)
+ self.bc.check.calls(Service.get.call_args_list, [
+ call('/v1/finetuning/coderevision',
+ params={
+ **query,
+ 'repo': model.task.github_url,
+ },
+ stream=True),
+ ])
+
+ self.assertEqual(response.getvalue().decode('utf-8'), json.dumps(expected))
+ self.assertEqual(response.status_code, code)
+ self.assertEqual(self.bc.database.list_of('assignments.Task'), [self.bc.format.to_dict(model.task)])
diff --git a/breathecode/assignments/tests/urls/tests_me_coderevision.py b/breathecode/assignments/tests/urls/tests_me_coderevision.py
new file mode 100644
index 000000000..a1796543b
--- /dev/null
+++ b/breathecode/assignments/tests/urls/tests_me_coderevision.py
@@ -0,0 +1,64 @@
+"""
+Test /answer
+"""
+import json
+import random
+from unittest.mock import MagicMock, call, patch
+
+from django.urls.base import reverse_lazy
+from rest_framework import status
+
+from breathecode.utils.service import Service
+
+from ..mixins import AssignmentsTestCase
+
+
+class MediaTestSuite(AssignmentsTestCase):
+
+ # When: no auth
+ # Then: response 401
+ def test_no_auth(self):
+ url = reverse_lazy('assignments:me_coderevision')
+ response = self.client.get(url)
+
+ json = response.json()
+ expected = {'detail': 'Authentication credentials were not provided.', 'status_code': 401}
+
+ self.assertEqual(json, expected)
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+ self.assertEqual(self.bc.database.list_of('assignments.Task'), [])
+
+ # When: auth
+ # Then: response 200
+ def test_auth(self):
+ expected = {'data': {'getTask': {'id': random.randint(1, 100)}}}
+ query = {
+ self.bc.fake.slug(): self.bc.fake.slug(),
+ self.bc.fake.slug(): self.bc.fake.slug(),
+ self.bc.fake.slug(): self.bc.fake.slug(),
+ }
+
+ mock = MagicMock()
+ mock.raw = iter([json.dumps(expected).encode()])
+ mock.headers = {'Content-Type': 'application/json'}
+ code = random.randint(200, 299)
+ mock.status_code = code
+ mock.reason = 'OK'
+
+ task = {'github_url': self.bc.fake.url()}
+ model = self.bc.database.create(profile_academy=1, task=task)
+ self.bc.request.authenticate(model.user)
+
+ url = reverse_lazy('assignments:me_coderevision') + '?' + self.bc.format.querystring(query)
+
+ with patch.multiple('breathecode.utils.service.Service',
+ __init__=MagicMock(return_value=None),
+ get=MagicMock(return_value=mock)):
+ response = self.client.get(url)
+ self.bc.check.calls(Service.get.call_args_list, [
+ call('/v1/finetuning/me/coderevision', params=query, stream=True),
+ ])
+
+ self.assertEqual(response.getvalue().decode('utf-8'), json.dumps(expected))
+ self.assertEqual(response.status_code, code)
+ self.assertEqual(self.bc.database.list_of('assignments.Task'), [self.bc.format.to_dict(model.task)])
diff --git a/breathecode/assignments/tests/urls/tests_me_task_id_coderevision.py b/breathecode/assignments/tests/urls/tests_me_task_id_coderevision.py
new file mode 100644
index 000000000..7188ea4e1
--- /dev/null
+++ b/breathecode/assignments/tests/urls/tests_me_task_id_coderevision.py
@@ -0,0 +1,70 @@
+"""
+Test /answer
+"""
+import json
+import random
+from unittest.mock import MagicMock, call, patch
+
+from django.urls.base import reverse_lazy
+from rest_framework import status
+
+from breathecode.utils.service import Service
+
+from ..mixins import AssignmentsTestCase
+
+
+class MediaTestSuite(AssignmentsTestCase):
+
+ # When: no auth
+ # Then: response 401
+ def test_no_auth(self):
+ url = reverse_lazy('assignments:me_task_id_coderevision', kwargs={'task_id': 1})
+ response = self.client.get(url)
+
+ json = response.json()
+ expected = {'detail': 'Authentication credentials were not provided.', 'status_code': 401}
+
+ self.assertEqual(json, expected)
+ self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
+ self.assertEqual(self.bc.database.list_of('assignments.Task'), [])
+
+ # When: auth
+ # Then: response 200
+ def test_auth(self):
+ expected = {'data': {'getTask': {'id': random.randint(1, 100)}}}
+ query = {
+ self.bc.fake.slug(): self.bc.fake.slug(),
+ self.bc.fake.slug(): self.bc.fake.slug(),
+ self.bc.fake.slug(): self.bc.fake.slug(),
+ }
+
+ mock = MagicMock()
+ mock.raw = iter([json.dumps(expected).encode()])
+ mock.headers = {'Content-Type': 'application/json'}
+ code = random.randint(200, 299)
+ mock.status_code = code
+ mock.reason = 'OK'
+
+ task = {'github_url': self.bc.fake.url()}
+ model = self.bc.database.create(profile_academy=1, task=task)
+ self.bc.request.authenticate(model.user)
+
+ url = reverse_lazy('assignments:me_task_id_coderevision',
+ kwargs={'task_id': 1}) + '?' + self.bc.format.querystring(query)
+
+ with patch.multiple('breathecode.utils.service.Service',
+ __init__=MagicMock(return_value=None),
+ get=MagicMock(return_value=mock)):
+ response = self.client.get(url)
+ self.bc.check.calls(Service.get.call_args_list, [
+ call('/v1/finetuning/coderevision',
+ params={
+ **query,
+ 'repo': model.task.github_url,
+ },
+ stream=True),
+ ])
+
+ self.assertEqual(response.getvalue().decode('utf-8'), json.dumps(expected))
+ self.assertEqual(response.status_code, code)
+ self.assertEqual(self.bc.database.list_of('assignments.Task'), [self.bc.format.to_dict(model.task)])
diff --git a/breathecode/assignments/urls.py b/breathecode/assignments/urls.py
index 654517562..cf3074183 100644
--- a/breathecode/assignments/urls.py
+++ b/breathecode/assignments/urls.py
@@ -1,9 +1,8 @@
-from django.contrib import admin
-from django.urls import path, include
-from rest_framework import routers
-from .views import (TaskMeView, sync_cohort_tasks_view, TaskTeacherView, deliver_assignment_view,
- TaskMeDeliverView, FinalProjectMeView, CohortTaskView, SubtaskMeView,
- TaskMeAttachmentView, FinalProjectScreenshotView)
+from django.urls import path
+from .views import (AcademyTaskCodeRevisionView, MeCodeRevisionView, MeTaskCodeRevisionView, TaskMeView,
+ sync_cohort_tasks_view, TaskTeacherView, deliver_assignment_view, TaskMeDeliverView,
+ FinalProjectMeView, CohortTaskView, SubtaskMeView, TaskMeAttachmentView,
+ FinalProjectScreenshotView)
app_name = 'assignments'
urlpatterns = [
@@ -16,6 +15,13 @@
path('user/me/final_project/
+
+
+