This commit is contained in:
Egor Matveev 2022-02-23 00:15:58 +03:00
parent cdb5157471
commit 4e9c195d9d
4 changed files with 172 additions and 12 deletions

View File

@ -3,19 +3,30 @@ from random import sample
from django.db.models import Count, Max, Q from django.db.models import Count, Max, Q
from django.utils import timezone from django.utils import timezone
from Checker.models import Checker
from Main.models import Task, UserInfo, Solution, Group from Main.models import Task, UserInfo, Solution, Group
from SprintLib.BaseView import BaseView from SprintLib.BaseView import BaseView, AccessError
from SprintLib.language import languages
class MainView(BaseView): class MainView(BaseView):
view_file = "main.html"
required_login = True
endpoint = "" endpoint = ""
def get(self): @property
self.context['top_tasks_today'] = Task.objects.filter(public=True, solution__time_sent__date=timezone.now().date()).annotate(count=Count('solution__task_id')).order_by('-count')[:5] def view_file(self):
if self.request.user.is_authenticated:
return "main.html"
return "landing.html"
def get_main(self):
self.context['top_tasks_today'] = Task.objects.filter(public=True,
solution__time_sent__date=timezone.now().date()).annotate(
count=Count('solution__task_id')).order_by('-count')[:5]
if len(self.context['top_tasks_today']) < 5: if len(self.context['top_tasks_today']) < 5:
self.context['top_tasks_today'] = Task.objects.filter(public=True, solution__time_sent__isnull=False).annotate(time_sent=Max('solution__time_sent'), count=Count('solution__task_id')).order_by('-count', '-time_sent')[:5] self.context['top_tasks_today'] = Task.objects.filter(public=True,
solution__time_sent__isnull=False).annotate(
time_sent=Max('solution__time_sent'), count=Count('solution__task_id')).order_by('-count',
'-time_sent')[:5]
if len(self.context['top_tasks_today']) < 5: if len(self.context['top_tasks_today']) < 5:
self.context['top_tasks_today'] = Task.objects.filter(public=True).order_by('name')[:5] self.context['top_tasks_today'] = Task.objects.filter(public=True).order_by('name')[:5]
for task in self.context['top_tasks_today']: for task in self.context['top_tasks_today']:
@ -29,8 +40,25 @@ class MainView(BaseView):
setattr(task, 'solution', Solution.objects.filter(user=self.request.user, task=task).last()) setattr(task, 'solution', Solution.objects.filter(user=self.request.user, task=task).last())
new_tasks = set(Task.objects.filter(public=True)) - set(all_tasks) new_tasks = set(Task.objects.filter(public=True)) - set(all_tasks)
self.context['new_tasks'] = sample(new_tasks, k=min(5, len(new_tasks))) self.context['new_tasks'] = sample(new_tasks, k=min(5, len(new_tasks)))
self.context['groups'] = Group.objects.filter(Q(editors__in=self.request.user.username) | Q(creator=self.request.user) | Q(users=self.request.user)).distinct() self.context['groups'] = Group.objects.filter(
Q(editors__in=self.request.user.username) | Q(creator=self.request.user) | Q(
users=self.request.user)).distinct()
def get_landing(self):
self.context['solutions'] = len(Solution.objects.all())
self.context['tasks'] = len(Task.objects.all())
self.context['users'] = len(UserInfo.objects.all())
self.context['languages'] = len(languages)
self.context['groups'] = len(Group.objects.all())
self.context['runners'] = len(Checker.objects.all())
def get(self):
if self.request.user.is_authenticated:
return self.get_main()
return self.get_landing()
def post(self): def post(self):
if not self.request.user.userinfo.teacher:
raise AccessError()
group = Group.objects.create(name=self.request.POST['name'], creator=self.request.user) group = Group.objects.create(name=self.request.POST['name'], creator=self.request.user)
return '/group?group_id=' + str(group.id) return '/group?group_id=' + str(group.id)

View File

@ -20,9 +20,10 @@ class BaseView:
view_file: Optional[str] = None view_file: Optional[str] = None
endpoint: Optional[str] = None endpoint: Optional[str] = None
def __init__(self): def __init__(self, request):
self.context = {} self.context = {}
self.entities = EntityStorage() self.entities = EntityStorage()
self.request = request
@classmethod @classmethod
def as_view(cls): def as_view(cls):
@ -31,14 +32,13 @@ class BaseView:
user_info = request.user.userinfo user_info = request.user.userinfo
user_info.last_request = timezone.now() user_info.last_request = timezone.now()
user_info.save() user_info.save()
c = cls() c = cls(request)
if c.required_login is not None: if c.required_login is not None:
if c.required_login and not request.user.is_authenticated: if c.required_login and not request.user.is_authenticated:
return HttpResponseRedirect("/enter") return HttpResponseRedirect("/enter")
if not c.required_login and request.user.is_authenticated: if not c.required_login and request.user.is_authenticated:
return HttpResponseRedirect("/") return HttpResponseRedirect("/")
request_method = request.method.lower() request_method = request.method.lower()
c.request = request
exec("from Main.models import *") exec("from Main.models import *")
for key in request.GET.keys(): for key in request.GET.keys():
if key.endswith("_id"): if key.endswith("_id"):

View File

@ -1,6 +1,5 @@
from os import listdir, mkdir, chmod from os import listdir, mkdir
from os.path import join, exists from os.path import join, exists
from shutil import copyfile
from subprocess import call, TimeoutExpired from subprocess import call, TimeoutExpired
from Main.management.commands.bot import bot from Main.management.commands.bot import bot

133
templates/landing.html Normal file
View File

@ -0,0 +1,133 @@
{% load static %}
<html lang="en"><head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
<meta name="generator" content="Hugo 0.88.1">
<title>Sprint welcome</title>
<link rel="canonical" href="https://getbootstrap.com/docs/5.1/examples/product/">
<!-- Bootstrap core CSS -->
<link href="https://getbootstrap.com/docs/5.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<!-- Favicons -->
<link rel="shortcut icon" href="{% static "img/icon.svg" %}" />
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
@media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
.container {
max-width: 960px;
}
/*
* Extra utilities
*/
.flex-equal > * {
flex: 1;
}
@media (min-width: 768px) {
.flex-md-equal > * {
flex: 1;
}
}
</style>
</head>
<body>
<main>
<div class="position-relative overflow-hidden p-3 p-md-5 m-md-3 text-center bg-light">
<div class="col-md-5 p-lg-5 mx-auto my-5">
<h1 class="display-4 fw-normal">Добро пожаловать в Sprint!</h1>
<p class="lead fw-normal">Sprint - система, позволяющая проводить олимпиады и уроки по программированию, а также обучаться этому ремеслу самостоятельно.</p>
<a class="btn btn-outline-secondary" href="/enter">Войти</a>
</div>
<div class="product-device shadow-sm d-none d-md-block"></div>
<div class="product-device product-device-2 shadow-sm d-none d-md-block"></div>
</div>
<div class="d-md-flex flex-md-equal w-100 my-md-3 ps-md-3">
<div class="bg-dark me-md-3 pt-3 px-3 pt-md-5 px-md-5 text-center text-white overflow-hidden">
<div class="my-3 py-3">
<h2 class="display-5">Sprint - это {{ users }} пользователей</h2>
<p class="lead">А с тобой будет еще больше</p>
</div>
</div>
<div class="bg-light me-md-3 pt-3 px-3 pt-md-5 px-md-5 text-center overflow-hidden">
<div class="my-3 p-3">
<h2 class="display-5">Sprint - это {{ tasks }} задач</h2>
<p class="lead">А с тобой будет еще больше</p>
</div>
</div>
</div>
<div class="d-md-flex flex-md-equal w-100 my-md-3 ps-md-3">
<div class="bg-light me-md-3 pt-3 px-3 pt-md-5 px-md-5 text-center overflow-hidden">
<div class="my-3 p-3">
<h2 class="display-5">Sprint - это {{ solutions }} решений</h2>
<p class="lead">А с тобой будет еще больше</p>
</div>
</div>
<div class="bg-dark me-md-3 pt-3 px-3 pt-md-5 px-md-5 text-center text-white overflow-hidden">
<div class="my-3 py-3">
<h2 class="display-5">Sprint - это {{ languages }} языков</h2>
<p class="lead">А с тобой будет еще больше</p>
</div>
</div>
</div>
<div class="d-md-flex flex-md-equal w-100 my-md-3 ps-md-3">
<div class="bg-dark me-md-3 pt-3 px-3 pt-md-5 px-md-5 text-center text-white overflow-hidden">
<div class="my-3 p-3">
<h2 class="display-5">Sprint - это {{ groups }} групп пользователей</h2>
<p class="lead">А с тобой будет еще больше</p>
</div>
</div>
<div class="bg-light me-md-3 pt-3 px-3 pt-md-5 px-md-5 text-center overflow-hidden">
<div class="my-3 py-3">
<h2 class="display-5">Sprint - это {{ runners }} независимых чекеров</h2>
<p class="lead">А с тобой будет еще больше</p>
</div>
</div>
</div>
<div class="position-relative overflow-hidden p-3 p-md-5 m-md-3 text-center bg-light">
<div class="col-md-5 p-lg-5 mx-auto my-5">
<h1 class="display-4 fw-normal">Попробуй Sprint сегодня и стань частью большой команды</h1>
<p class="lead fw-normal">Бесплатно, быстро и просто.</p>
<a class="btn btn-outline-secondary" href="/enter">Войти</a>
</div>
<div class="product-device shadow-sm d-none d-md-block"></div>
<div class="product-device product-device-2 shadow-sm d-none d-md-block"></div>
</div>
</main>
<script src="https://getbootstrap.com/docs/5.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
</body></html>