from functools import cached_property from os.path import exists from shutil import rmtree from subprocess import call from django.contrib.auth.models import User from django.db.models import JSONField from django.db import models from django.utils import timezone from Main.models import Set, SetTask from Main.models.solution_file import SolutionFile from Main.models.task import Task from Sprint.settings import CONSTS from SprintLib.language import languages class Solution(models.Model): task = models.ForeignKey(Task, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE) language_id = models.IntegerField(default=0) time_sent = models.DateTimeField(default=timezone.now) result = models.TextField(default=CONSTS["in_queue_status"]) test = models.IntegerField(default=None, null=True, blank=True) set = models.ForeignKey(Set, null=True, blank=True, on_delete=models.SET_NULL) extras = JSONField(default=dict) class Meta: indexes = [ models.Index(fields=['task', 'user', '-time_sent']), models.Index(fields=['task', '-time_sent']), models.Index(fields=['set', '-time_sent']), ] @cached_property def settask(self): return SetTask.objects.filter(set=self.set, task=self.task).first() @property def percentage_done(self): if self.test is None: return 0 return self.test * 100 // self.task.tests_count @property def language(self): return languages[self.language_id] def delete(self, using=None, keep_parents=False): if exists(self.directory): rmtree(self.directory) super().delete(using=using, keep_parents=keep_parents) @cached_property def files(self): data = [] for file in SolutionFile.objects.filter(solution=self): try: text = file.text except: continue entity = {"filename": file.path, "text": text} end = file.path.split(".")[-1] language = None for l in languages: if l.file_type == end: language = l break if language is None: highlight = "nohighlight" else: highlight = "language-" + language.highlight entity["highlight"] = highlight data.append(entity) data.sort(key=lambda x: x["filename"]) return data @property def directory(self): return "solutions/" + str(self.id) @property def number_result(self): if self.test is None: return self.result return f"{self.result} ({self.test})" @property def badge_style(self): if self.result == CONSTS["in_queue_status"]: return "secondary" if self.result == CONSTS["ok_status"]: return "success" if self.result == CONSTS["testing_status"]: return "info" return "danger" @property def testing_directory(self): return self.directory @property def volume_directory(self): return "/sprint-data/worker/" + str(self.id) def exec_command(self, command, working_directory="app", timeout=None): return call( f'docker exec -i solution_{self.id} sh -c "cd {working_directory} && {command}"', shell=True, timeout=timeout, )