Открыть боковую панель
peteroshkvarkov
Project-38
Коммиты
a48aef2d
Коммит
a48aef2d
создал
Авг 31, 2023
по автору
Кабанин Денис Андреевич
Просмотр файлов
мерж с 160
владельцы
67f4d02a
3639501d
Изменения
32
Скрыть пробелы
Построчно
Рядом
portal/announcements/decorators.py
Просмотр файла @
a48aef2d
...
...
@@ -7,9 +7,7 @@ def allowed_users(allowed_roles=None):
def
decorator
(
view_func
):
def
wrapper_func
(
request
,
*
args
,
**
kwargs
):
group
=
None
if
request
.
user
.
groups
.
exists
():
group
=
request
.
user
.
groups
.
all
()[
0
].
name
group
=
request
.
user
.
role
if
group
in
allowed_roles
:
return
view_func
(
request
,
*
args
,
**
kwargs
)
return
HttpResponsePermanentRedirect
(
'/announcements'
)
...
...
portal/announcements/forms.py
Просмотр файла @
a48aef2d
...
...
@@ -6,15 +6,16 @@ from .models import Announcement
class
AnnouncementForm
(
forms
.
Form
):
date_of_expiring
=
forms
.
DateField
(
label
=
''
,
widget
=
forms
.
DateInput
(
attrs
=
{
'class'
:
'date'
,
'type'
:
'date'
}),
required
=
False
)
title
=
forms
.
CharField
(
label
=
''
,
required
=
True
,
widget
=
forms
.
Text
Input
(
attrs
=
{
'class'
:
'
title
'
,
'placeholder'
:
'Заголовок объявления'
}))
body
=
forms
.
CharField
(
label
=
''
,
widget
=
forms
.
Textarea
(
attrs
=
{
'class'
:
'
body
'
}))
date_of_expiring
=
forms
.
DateField
(
label
=
''
,
widget
=
forms
.
DateInput
(
attrs
=
{
'class'
:
'date'
,
'type'
:
'date'
,
'onchange'
:
'preview_update(this,
\'
date
\'
)'
}),
required
=
False
)
title
=
forms
.
CharField
(
label
=
''
,
required
=
True
,
widget
=
forms
.
Text
area
(
attrs
=
{
'class'
:
'
label-textarea
'
,
'placeholder'
:
'Заголовок объявления'
,
'onkeyup'
:
'textarea_size(this); preview_update(this,
\'
title
\'
)'
,
'cols'
:
'none'
,
'rows'
:
'none'
}))
body
=
forms
.
CharField
(
label
=
''
,
required
=
True
,
widget
=
forms
.
Textarea
(
attrs
=
{
'class'
:
'
label-textarea'
,
'onkeyup'
:
'textarea_size(this); preview_update(this,
\'
descr
\'
)'
,
'cols'
:
'none'
,
'rows'
:
'none
'
}))
is_pinned
=
forms
.
BooleanField
(
label
=
'Закрепить'
,
required
=
False
)
image_url
=
forms
.
FilePath
Field
(
label
=
'
Выбрать обложку'
,
path
=
finders
.
find
(
"img/announcements/covers"
),
required
=
False
,
widget
=
forms
.
TextInput
(
attrs
=
{
'class'
:
'imurl'
}
))
files
=
forms
.
FileField
(
label
=
'Прикрепить файлы'
,
widget
=
forms
.
FileInput
(
attrs
=
{
'class'
:
"file
s"
}),
required
=
False
)
file_id_to_delete
=
forms
.
IntegerField
(
widget
=
forms
.
HiddenInput
(
attrs
=
{
'class'
:
'fitd'
}),
required
=
False
)
image_url
=
forms
.
Char
Field
(
label
=
'
'
,
required
=
False
,
widget
=
forms
.
HiddenInput
(
))
files
=
forms
.
FileField
(
label
=
'Прикрепить файлы'
,
widget
=
forms
.
FileInput
(
attrs
=
{
'class'
:
"file
-input"
,
"id"
:
'file'
,
"multiple"
:
''
}),
required
=
False
)
file_id_to_delete
=
forms
.
IntegerField
(
widget
=
forms
.
HiddenInput
(
attrs
=
{
'class'
:
'fitd'
,
'value'
:
'-1'
}),
required
=
False
)
def
clean_date_of_expiring
(
self
):
exdate
=
self
.
cleaned_data
.
get
(
'date_of_expiring'
)
if
exdate
is
not
None
and
datetime
.
now
().
date
()
>
exdate
:
raise
ValidationError
(
'Неверная дата'
)
return
exdate
portal/announcements/management/commands/delete_expired_values.py
Просмотр файла @
a48aef2d
...
...
@@ -4,7 +4,7 @@ from announcements.models import Announcement
class
Command
(
BaseCommand
):
help
=
'Deletes expired announcements and their related images
, files
and
tag
s'
help
=
'Deletes expired announcements and their related images and
file
s'
def
handle
(
self
,
*
args
,
**
options
):
now
=
datetime
.
now
(
timezone
.
utc
)
...
...
portal/announcements/templates/announcements/editor.html
удалено
100644 → 0
Просмотр файла @
67f4d02a
<!-- Временный файл. Нужен для проверки работы -->
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"UTF-8"
>
<title>
Редактор объявлений
</title>
</head>
<body>
<form
method=
"post"
action=
"editannouncement/{{ announcement.id }}"
enctype=
"multipart/form-data"
>
{% csrf_token %}
{{ form.as_p }}
<p>
Удалить файлы:
</p>
{% for file in announcement.files.all %}
<div
class=
"file-item"
>
<a
href=
"{{ file.file.url }}"
>
{{ file.file }}
</a>
<input
type=
"checkbox"
name=
"file_id_to_delete[]"
value=
"{{ file.id }}"
>
</div>
{% endfor %}
<input
type=
"submit"
value=
"Изменить"
/>
</form>
</body>
</html>
\ Нет новой строки в конце файла
portal/announcements/templates/announcements/redactor.html
удалено
100644 → 0
Просмотр файла @
67f4d02a
<!-- Временный файл. Нужен для проверки работы -->
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"UTF-8"
>
<title>
Редактор объявлений
</title>
</head>
<body>
<form
method=
"post"
action=
"createannouncement"
enctype=
"multipart/form-data"
>
{% csrf_token %}
{{ form.as_p }}
<input
type=
"submit"
value=
"Разместить"
/>
</form>
</body>
</html>
\ Нет новой строки в конце файла
portal/announcements/templates/__init__.py
→
portal/announcements/template
tag
s/__init__.py
Просмотр файла @
a48aef2d
Файл перемещен
portal/announcements/templatetags/split_filter.py
0 → 100644
Просмотр файла @
a48aef2d
from
django
import
template
register
=
template
.
Library
()
@
register
.
filter
def
split
(
value
):
return
value
.
split
(
'/'
)[
-
1
]
portal/announcements/urls.py
Просмотр файла @
a48aef2d
...
...
@@ -7,6 +7,7 @@ urlpatterns = [
path
(
'createannouncement'
,
views
.
createannouncement
,
name
=
'createannouncement'
),
path
(
'redactor/<int:id>'
,
views
.
editor
,
name
=
'editor'
),
path
(
'redactor/editannouncement/<int:id>'
,
views
.
editannouncement
,
name
=
'editannouncement'
),
path
(
'search'
,
views
.
search
,
name
=
'search'
),
path
(
'search
/
'
,
views
.
search
,
name
=
'search'
),
path
(
'<int:id>'
,
views
.
announcement
,
name
=
'announcement'
),
path
(
'delete/<int:id>'
,
views
.
delete_announcement
,
name
=
'delete'
)
]
\ Нет новой строки в конце файла
portal/announcements/views.py
Просмотр файла @
a48aef2d
...
...
@@ -6,56 +6,60 @@ from datetime import date
from
.decorators
import
allowed_users
from
.models
import
File
from
.forms
import
AnnouncementForm
from
django.core.paginator
import
Paginator
from
django.conf
import
settings
from
pathlib
import
Path
import
os
# Добавить проверку форм при удалении тестовых шаблонов
# В функию index надо передавать anid - максимальное количество следующих объявлений на странице, начиная с 40
# Функция redactor отвечает за рендер шаблона редактора со всеми формами
# Функция createannouncement Создает объявление
# Функция editor отвечает за рендер шаблона эдитора объявлений со всеми формами и прошлыми данными
# Функция editannouncement отвечает за редактирование объявления
# Функция search отвечает за поиск
def
index
(
request
,
anid
=
None
):
def
index
(
request
):
group
=
None
superuser
=
False
ann_list
=
[]
anns
=
Announcement
.
objects
.
all
()
if
request
.
method
==
'GET'
and
anid
!=
None
:
for
ann
in
range
(
anid
-
20
,
anid
):
try
:
ann_list
.
append
(
anns
[
ann
])
except
IndexError
:
break
else
:
for
ann
in
range
(
anns
.
count
()):
ann_list
.
append
(
anns
[
ann
])
paginator
=
Paginator
(
anns
,
20
)
# Сколько объявлений на странице
page_number
=
request
.
GET
.
get
(
'page'
)
page_announcements
=
paginator
.
get_page
(
page_number
)
if
request
.
user
.
groups
.
exists
():
group
=
request
.
user
.
groups
.
all
()[
0
].
name
if
group
in
[
'Teacher'
,
'admin'
]:
superuser
=
True
data
=
{
'superuser'
:
superuser
,
'announcements'
:
ann_list
}
data
=
{
'superuser'
:
superuser
,
'
page_
announcements'
:
page_announcements
,
'count'
:
anns
.
count
()
}
return
render
(
request
,
'dec/dec.html'
,
context
=
data
)
#
@allowed_users(allowed_roles=['
Teacher', 'admin
'])
@
allowed_users
(
allowed_roles
=
[
'
Учитель'
,
'Администратор
'
])
def
redactor
(
request
):
"""Отвечает за рендер шаблона редактора со всеми формами"""
covers_dir
=
settings
.
BASE_DIR
/
"media"
/
"covers"
covers
=
[]
for
cover
in
os
.
listdir
(
covers_dir
):
covers
.
append
(
"/media/covers/"
+
cover
)
form
=
AnnouncementForm
()
return
render
(
request
,
"dec/red.html"
,
context
=
{
'form'
:
form
})
return
render
(
request
,
"dec/red.html"
,
context
=
{
'form'
:
form
,
'covers'
:
covers
})
#
@allowed_users(allowed_roles=['
Teacher', 'admin
'])
@
allowed_users
(
allowed_roles
=
[
'
Учитель'
,
'Администратор
'
])
def
createannouncement
(
request
):
"""Создает объявление (Записывает в БД)"""
if
request
.
method
!=
"POST"
:
return
HttpResponsePermanentRedirect
(
"/announcements"
)
form
=
AnnouncementForm
(
request
.
POST
)
if
form
.
is_valid
():
pass
else
:
return
render
(
request
,
'WrongData.html'
)
title
=
request
.
POST
.
get
(
"title"
)
body
=
request
.
POST
.
get
(
"body"
)
is_pinned
=
request
.
POST
.
get
(
"is_pinned"
)
...
...
@@ -77,8 +81,10 @@ def createannouncement(request):
return
HttpResponsePermanentRedirect
(
'/announcements'
)
#
@allowed_users(allowed_roles=['
Teacher', 'admin
'])
@
allowed_users
(
allowed_roles
=
[
'
Учитель'
,
'Администратор
'
])
def
editor
(
request
,
id
):
"""Отвечает за рендер шаблона эдитора объявлений со всеми формами и прошлыми данными"""
try
:
announcement
=
Announcement
.
objects
.
get
(
id
=
id
)
initial_data
=
{
...
...
@@ -89,12 +95,19 @@ def editor(request, id):
'image_url'
:
announcement
.
image_url
,
}
covers_dir
=
settings
.
BASE_DIR
/
"media"
/
"covers"
covers
=
[]
for
cover
in
os
.
listdir
(
covers_dir
):
covers
.
append
(
"/media/covers/"
+
cover
)
form
=
AnnouncementForm
(
initial
=
initial_data
)
data
=
{
'form'
:
form
,
'announcement_id'
:
id
,
'announcement'
:
announcement
,
'covers'
:
covers
}
return
render
(
request
,
'dec/ed.html'
,
context
=
data
)
...
...
@@ -103,8 +116,9 @@ def editor(request, id):
return
render
(
request
,
'WrongData.html'
)
#
@allowed_users(allowed_roles=['
Teacher', 'admin
'])
@
allowed_users
(
allowed_roles
=
[
'
Учитель'
,
'Администратор
'
])
def
editannouncement
(
request
,
id
):
"""Отвечает за редактирование объявления (изменение существующих значений в БД)"""
try
:
...
...
@@ -118,13 +132,20 @@ def editannouncement(request, id):
is_pinned
=
request
.
POST
.
get
(
"is_pinned"
,
False
)
if
is_pinned
:
is_pinned
=
True
files_to_add
=
request
.
FILES
.
getlist
(
'files'
)
files_to_delete
=
request
.
POST
.
get
list
(
'file_id_to_delete
[]
'
)
image_url
=
request
.
POST
.
get
(
'image_url'
)
files_to_delete
=
request
.
POST
.
get
(
'file_id_to_delete'
)
image_url
=
request
.
POST
.
get
(
'image_url'
)
for
file_id
in
files_to_delete
:
file
=
File
.
objects
.
get
(
pk
=
int
(
file_id
))
file
.
file
.
delete
()
file
.
delete
()
if
int
(
files_to_delete
)
is
not
-
1
:
if
','
in
files_to_delete
:
files_to_delete
=
files_to_delete
.
split
(
','
)
else
:
files_to_delete
=
[
files_to_delete
]
for
file_id
in
files_to_delete
:
file
=
File
.
objects
.
get
(
pk
=
int
(
file_id
))
file
.
file
.
delete
()
file
.
delete
()
for
file
in
files_to_add
:
File
.
objects
.
create
(
announcement
=
announcement
,
file
=
file
)
...
...
@@ -146,47 +167,28 @@ def editannouncement(request, id):
return
render
(
request
,
'WrongData.html'
)
def
search
(
request
,
anid
=
None
):
def
search
(
request
):
"""Отвечает за функциональную часть поиска"""
query
=
request
.
GET
.
get
(
'q'
)
ann_list
=
[]
if
query
:
query_words
=
query
.
split
()
query_filter
=
Q
()
query_words
=
query
.
split
()
query_filter
=
Q
()
for
word
in
query_words
:
query_filter
|=
Q
(
title__icontains
=
word
)
|
Q
(
body__icontains
=
word
)
|
Q
(
author__first_name__icontains
=
word
)
|
Q
(
author__last_name__icontains
=
word
)
for
word
in
query_words
:
query_filter
|=
Q
(
title__icontains
=
word
)
|
Q
(
body__icontains
=
word
)
|
Q
(
author__first_name__icontains
=
word
)
|
Q
(
author__last_name__icontains
=
word
)
anns
=
Announcement
.
objects
.
filter
(
query_filter
)
anns
=
Announcement
.
objects
.
filter
(
query_filter
)
if
request
.
method
==
'GET'
and
anid
!=
None
:
for
ann
in
range
(
anid
-
20
,
anid
):
try
:
ann_list
.
append
(
anns
[
ann
])
except
IndexError
:
break
else
:
for
ann
in
range
(
anns
.
count
()):
ann_list
.
append
(
anns
[
ann
])
else
:
query_words
=
query
.
split
()
query_filter
=
Q
()
for
word
in
query_words
:
query_filter
|=
Q
(
title__icontains
=
word
)
|
Q
(
body__icontains
=
word
)
|
Q
(
author__first_name__icontains
=
word
)
|
Q
(
author__last_name__icontains
=
word
)
paginator
=
Paginator
(
anns
,
20
)
# Сколько объявлений на странице
page_number
=
request
.
GET
.
get
(
'page'
)
page_announcements
=
paginator
.
get_page
(
page_number
)
anns
=
Announcement
.
objects
.
filter
(
query_filter
)
for
ann
in
range
(
anns
.
count
()):
ann_list
.
append
(
anns
[
ann
])
context
=
{
'announcements'
:
ann_list
,
data
=
{
'page_announcements'
:
page_announcements
,
'search_value'
:
query
,
}
return
render
(
request
,
'dec/dec.html'
,
context
=
context
)
return
render
(
request
,
'dec/dec.html'
,
context
=
data
)
def
announcement
(
request
,
id
):
...
...
@@ -200,4 +202,24 @@ def announcement(request, id):
'announcement'
:
announcement
,
}
return
render
(
request
,
'dec/ann.html'
,
context
=
context
)
\ Нет новой строки в конце файла
return
render
(
request
,
'dec/ann.html'
,
context
=
context
)
@
allowed_users
(
allowed_roles
=
[
'Учитель'
,
'Администратор'
])
def
delete_announcement
(
request
,
id
):
"""Удаляет просроченные объявления и связанные с ними файлы"""
if
request
.
method
!=
'GET'
:
return
render
(
request
,
'WrongData.html'
)
announcement
=
Announcement
.
objects
.
get
(
id
=
id
)
files
=
announcement
.
files
.
all
()
for
file
in
files
:
file
.
file
.
delete
()
file
.
delete
()
announcement
.
delete
()
return
HttpResponsePermanentRedirect
(
'/announcements'
)
portal/management/forms.py
Просмотр файла @
a48aef2d
from
django
import
forms
from
django.core.exceptions
import
ValidationError
from
django.contrib.auth
import
get_user_model
from
django.contrib
import
messages
User
=
get_user_model
()
...
...
portal/management/models.py
Просмотр файла @
a48aef2d
...
...
@@ -19,8 +19,8 @@ class User(AbstractUser):
def
set_full_name
(
self
):
self
.
full_Name
=
self
.
last_name
+
self
.
first_name
+
self
.
middle_name
def
save
(
self
,
*
args
,
**
kwargs
):
def
save
_photo
(
self
,
*
args
,
**
kwargs
):
super
().
save
()
img
=
Image
.
open
(
self
.
avatar
.
path
)
width
,
height
=
img
.
size
# Get dimensions
...
...
portal/management/urls.py
Просмотр файла @
a48aef2d
...
...
@@ -3,7 +3,7 @@ from .views import register, admin_menu, token_page, profile
urlpatterns
=
[
path
(
''
,
include
(
'django.contrib.auth.urls'
),
name
=
'management'
),
path
(
'register/'
,
register
,
name
=
'register'
),
path
(
'register/
<str:token>/
'
,
register
,
name
=
'register'
),
path
(
'token_page/'
,
token_page
,
name
=
'token_page'
),
path
(
'admin_menu/'
,
admin_menu
,
name
=
'admin_menu'
),
path
(
'profile/'
,
profile
,
name
=
'profile'
),
...
...
portal/management/views.py
Просмотр файла @
a48aef2d
import
string
import
random
import
time
import
os
from
dataclasses
import
dataclass
,
field
from
django.contrib.auth
import
authenticate
,
login
...
...
@@ -12,7 +14,12 @@ from .models import User, Tokens
from
projects.models
import
Project
from
django.core.paginator
import
Paginator
,
EmptyPage
def
register
(
request
):
def
register
(
request
,
token
):
temp_token
=
False
if
Tokens
.
objects
.
filter
(
token
=
token
).
exists
():
temp_token
=
True
if
request
.
method
==
'POST'
:
user_form
=
UserRegistrationForm
(
request
.
POST
)
if
user_form
.
is_valid
():
...
...
@@ -23,17 +30,21 @@ def register(request):
messages
.
success
(
request
,
'Аккаунт успешно создан'
)
authenticate_user
=
authenticate
(
request
,
username
=
new_user
.
username
,
password
=
user_form
.
cleaned_data
[
'password'
])
login
(
request
,
authenticate_user
)
if
temp_token
:
Tokens
.
objects
.
get
(
token
=
token
).
delete
()
return
redirect
(
'profile'
)
elif
request
.
POST
.
get
(
'register_submit'
)
and
not
user_form
.
is_valid
():
messages
.
error
(
request
,
'Что-то введено неправильно, проверьте пароли. Так же возможно такой логин или мейл уже существует!'
)
else
:
user_form
=
UserRegistrationForm
()
return
render
(
request
,
'registration/register.html'
,
{
'user_form'
:
user_form
})
return
render
(
request
,
'registration/register.html'
,
{
'user_form'
:
user_form
,
"is_token"
:
temp_token
,
"token"
:
token
})
def
token_page
(
request
):
if
request
.
method
==
"POST"
:
token
=
request
.
POST
.
get
(
"token"
)
if
Tokens
.
objects
.
filter
(
token
=
token
).
exists
():
temp_token
=
Tokens
.
objects
.
get
(
token
=
token
).
delete
()
return
redirect
(
'register'
)
return
redirect
(
f
'/management/register/
{
token
}
/'
)
else
:
messages
.
error
(
request
,
'Неправильный токен!'
)
...
...
@@ -160,6 +171,7 @@ def admin_menu(request):
user
.
is_superuser
=
True
elif
role
==
"Учитель"
:
user
.
group
=
0
user
.
is_superuser
=
False
else
:
user
.
is_superuser
=
False
...
...
@@ -213,7 +225,6 @@ def profile(request):
request_projects_packs
=
[
ProjectsPack
(
project
)
for
project
in
request_projects_T
]
user_full
=
request
.
user
.
getPName
()
if
request
.
method
==
"POST"
:
new_password
=
request
.
POST
.
get
(
'new_password'
)
old_password
=
request
.
POST
.
get
(
'old_password'
)
...
...
@@ -243,8 +254,9 @@ def profile(request):
if
request
.
POST
.
get
(
'avatar_submit'
)
and
request
.
FILES
:
os
.
remove
(
request
.
user
.
avatar
.
path
,
dir_fd
=
None
)
request
.
user
.
avatar
=
new_avatar
request
.
user
.
save
()
request
.
user
.
save
_photo
()
return
redirect
(
'profile'
)
context
=
{
"open_projects_packs"
:
open_projects_packs
,
...
...
portal/media/covers/1.jpg
0 → 100644
Просмотр файла @
a48aef2d
269,9 КБ
portal/media/covers/2.jpg
0 → 100644
Просмотр файла @
a48aef2d
1,7 МБ
portal/media/covers/3.jpg
0 → 100644
Просмотр файла @
a48aef2d
233,3 КБ
portal/media/covers/4.jpg
0 → 100644
Просмотр файла @
a48aef2d
185,6 КБ
portal/media/temp_tokens/tokens4.txt
Просмотр файла @
a48aef2d
y7ZK0xnBh2UFouPi
bZSCdiOshj8KcIo5
portal/projects/views.py
Просмотр файла @
a48aef2d
...
...
@@ -110,13 +110,14 @@ def index(request: HttpRequest):
# отправка страницы с формой для подачи заявки на проект
def
send_create_form
(
request
:
HttpRequest
,
context_theme
=
{}):
def
send_create_form
(
request
:
HttpRequest
,
context_data
=
{}):
print
(
context_data
)
if
request
.
user
.
is_authenticated
:
if
request
.
user
.
role
==
"Ученик"
:
teachers
=
User
.
objects
.
filter
(
role
=
"Учитель"
,
is_other_teacher
=
True
)
data
=
{
"teachers"
:
teachers
,
"subjects_names"
:
[
subject
.
name
for
subject
in
Subject
.
objects
.
all
()]}
data
.
update
(
context_
theme
)
data
.
update
(
context_
data
)
return
render
(
request
,
"projects/create.html"
,
data
)
return
render
(
request
,
"NotEnoughPermissions.html"
)
...
...
@@ -148,12 +149,15 @@ def create(request: HttpRequest):
subject
=
request
.
POST
.
get
(
"subject"
)
name
=
request
.
POST
.
get
(
"name"
)
is_another_teacher
=
request
.
POST
.
get
(
'teacher-checkbox'
)
description
=
request
.
POST
.
get
(
'description'
,
''
)
try
:
if
is_another_teacher
==
'on'
:
# если учитель не из лицея
another_teacher
=
request
.
POST
.
get
(
"new-teacher"
,
-
1
)
if
another_teacher
==
-
1
:
messages
.
error
(
request
,
'Неверно введённые данные'
)
return
r
end
er
(
request
,
"projects/create.html"
)
return
s
end
_create_form
(
request
,
context_data
=
{
'name'
:
name
,
'description'
:
description
}
)
last_user
=
User
.
objects
.
last
()
if
last_user
is
None
:
new_id
=
1
...
...
@@ -168,11 +172,12 @@ def create(request: HttpRequest):
else
:
if
teacher_id
==
-
1
:
messages
.
error
(
request
,
'Неверно введённые данные'
)
return
render
(
request
,
"projects/create.html"
)
print
({
'name'
:
name
,
'description'
:
description
})
return
send_create_form
(
request
,
context_data
=
{
'name'
:
name
,
'description'
:
description
})
teacher
=
User
.
objects
.
get
(
id
=
teacher_id
)
if
teacher
.
role
!=
"Учитель"
:
return
render
(
request
,
"WrongData.html"
)
description
=
request
.
POST
.
get
(
'description'
,
''
)
return
send_create_form
(
request
,
context_data
=
{
'name'
:
name
,
'description'
:
description
})
project
=
Project
.
objects
.
create
(
name
=
name
,
teacher
=
teacher
,
student
=
request
.
user
)
if
description
!=
-
1
:
project
.
description
=
description
...
...
@@ -186,7 +191,8 @@ def create(request: HttpRequest):
return
render
(
request
,
"projects/success.html"
)
except
User
.
DoesNotExist
:
# если не удалось получить пользователя из бд
return
render
(
request
,
"WrongData.html"
)
except
BaseException
:
# если возникла непредвиденная ошибка
except
BaseException
as
e
:
# если возникла непредвиденная ошибка
print
(
e
)
return
render
(
request
,
"FatalError.html"
)
...
...
portal/static/css/dec/dec.css
Просмотр файла @
a48aef2d
html
{
box-sizing
:
border-box
;
width
:
100%
;
height
:
100%
;
}
*,
*
::before
,
*
::after
{
box-sizing
:
inherit
;
}
a
{
color
:
inherit
;
text-decoration
:
none
;
}
img
{
max-width
:
100%
;
}
body
{
margin
:
0
;
font-family
:
'Roboto'
,
Verdana
,
sans-serif
;
min-width
:
100%
;
min-height
:
100%
;
background-color
:
#E8F1FF
;
}
.main-nav
{
position
:
relative
;
display
:
block
;
width
:
6
0%
;
width
:
8
0%
;
margin
:
0
auto
;
}
...
...
@@ -39,45 +10,19 @@ body {
margin
:
0
auto
;
margin-top
:
100px
;
width
:
80%
;
margin-left
:
10%
;
overflow
:
scroll
;
/*убираем полосу прокрутки*/
-ms-overflow-style
:
none
;
/* IE and Edge */
scrollbar-width
:
none
;
/* Firefox */
}
/*Настройки скроллбара в Chrome*/
.main
::-webkit-scrollbar
{
display
:
none
;
/* Hide scrollbar for Chrome, Safari and Opera */
}
::-webkit-scrollbar
{
width
:
10px
;
}
::-webkit-scrollbar-track
{
-webkit-box-shadow
:
5px
5px
5px
-5px
rgba
(
8
,
42
,
70
,
0.2
)
inset
;
background-color
:
#e8f1ff
;
}
::-webkit-scrollbar-thumb
{
background-color
:
rgb
(
4
,
0
,
80
);
background-image
:
-webkit-linear-gradient
(
45deg
,
rgba
(
4
,
0
,
80
,
1
)
0%
,
rgba
(
9
,
9
,
121
,
1
)
31%
,
rgba
(
0
,
162
,
195
,
1
)
100%
);
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
}
.
nav
{
position
:
relative
;
display
:
block
;
width
:
50%
;
margin
:
0
auto
;
.
search-form
{
display
:
flex
;
column-gap
:
10px
;
align-items
:
center
;
margin
-bottom
:
20px
;
}
.search
{
margin-bottom
:
20px
;
width
:
100%
;
display
:
flex
;
justify-content
:
center
;
...
...
@@ -109,212 +54,261 @@ body {
}
.decorate
{
background-color
:
#E8F1FF
;
width
:
14em
;
height
:
3em
;
border-radius
:
10px
;
text-align
:
center
;
display
:
grid
;
margin
:
auto
;
z-index
:
5
;
.create-link
{
padding
:
10px
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
white-space
:
nowrap
;
font-size
:
16px
;
border-radius
:
25px
;
cursor
:
pointer
;
background
:
#103A84
;
color
:
#fff
;
transition
:
background
0.3s
linear
;
}
.Adecorate
{
display
:
block
;
width
:
100%
;
height
:
3em
;
z-index
:
10
;
grid-row
:
1
;
grid-column
:
1
;
.create-link
:hover
{
overflow
:
visible
;
background
:
#0d306d
;
transition
:
background
0.3s
linear
;
}
.Tdecorate
{
align-self
:
center
;
z-index
:
0
;
grid-row
:
1
;
grid-column
:
1
;
.create-link
:active
{
background
:
#3e5e96
;
}
.Tdecorate
:hover
,
.Tdecorate.hover
{
cursor
:
pointer
;
.create-link
>
span
{
padding-right
:
0px
;
max-width
:
0
;
overflow
:
hidden
;
transition
:
max-width
0.3s
cubic-bezier
(
0
,
1
,
0
,
1
);
}
.decorate
:hover
,
.decorate.hover
{
background-color
:
white
;
.create-link
:hover
>
span
{
padding-right
:
5px
;
max-width
:
500px
;
transition
:
max-width
0.3s
cubic-bezier
(
1
,
0
,
1
,
0
);
}
/* FSL settings */
.FSL
{
background-color
:
#E8F1FF
;
.content
{
width
:
100%
;
}
/* grid-area: o; */
/* grid-auto-rows: auto; */
.announ
{
display
:
flex
;
/* flex-flow: column wrap; */
flex-flow
:
row
wrap
;
justify-content
:
space-around
;
/* background: #FFFFFF; */
/* border: 1px solid #999999; */
border-radius
:
9px
;
max-width
:
1000px
;
margin
:
0
auto
;
}
.flex
{
display
:
grid
;
grid-template-columns
:
repeat
(
5
,
20%
);
grid-template-rows
:
repeat
(
20
,
5%
);
width
:
45%
;
min-height
:
150px
;
margin
:
2%
;
max-height
:
250px
;
background
:
#FFFFFF
;
/* Back shadow */
box-shadow
:
0px
0px
4px
3px
rgba
(
63
,
63
,
63
,
0.55
);
border-radius
:
9px
;
.announ
:not
(
:last-child
)
{
margin-bottom
:
20px
;
}
.IB
{
background-color
:
#051A3F
;
height
:
100%
;
width
:
100%
;
border-radius
:
0
9px
9px
0
;
grid-area
:
1
/
5
/
21
/
6
;
.announ-content
{
padding
:
16px
27px
;
border-top-left-radius
:
9px
;
border-bottom-left-radius
:
9px
;
display
:
flex
;
flex-direction
:
column
;
align-items
:
stretch
;
justify-content
:
space-between
;
width
:
750px
;
min-height
:
250px
;
background
:
#fff
;
}
.cap
{
grid-area
:
2
/
1
/
3
/
5
;
padding-bottom
:
1%
;
font-size
:
32px
;
margin-top
:
0
;
padding-left
:
4%
;
font-weight
:
700
;
.top-info
{
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
margin-bottom
:
20px
;
}
.text
{
grid-area
:
3
/
1
/
19
/
5
;
padding-top
:
10px
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
padding-left
:
4%
;
max-height
:
9.5em
;
.top-info-text
{
color
:
#A3A4A6
;
font-size
:
15px
;
font-style
:
normal
;
}
@media
(
max-width
:
2000px
){
/* стили для xs-устройств */
.flex
{
width
:
80%
;
min-height
:
9em
;
max-height
:
15em
;
margin
:
2%
;
border-radius
:
8px
;
}
.Fother
{
justify-content
:
center
;
}
.IB
{
border-radius
:
0
8px
8px
0
;
}
.favourite-btn
{
background
:
none
;
border
:
none
;
outline
:
none
;
width
:
20px
;
height
:
20px
;
cursor
:
pointer
;
fill
:
#DBDBDB
;
}
ul
{
list-style
:
none
;
margin
:
0
;
padding
:
0
;
.favourite-svg
>
path
{
transition
:
fill
.3s
linear
;
}
.btn
{
border
:
none
;
outline
:
none
;
background
:
none
;
cursor
:
pointer
;
.favourite-btn
:hover
{
fill
:
#bdbdbd
;
}
.dec
{
position
:
relative
;
width
:
600px
;
background
:
#fff
;
border-radius
:
30px
;
.middle-info
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
flex-start
;
justify-content
:
space-between
;
padding
:
0
30px
;
align-items
:
flex-start
;
}
.
btn-dec
{
display
:
block
;
width
:
52em
;
.
middle-info
>
a
{
border-radius
:
5px
;
transition
:
background
0.3s
linear
;
}
.btn-dec
::after
{
content
:
""
;
position
:
absolute
;
z-index
:
2
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
border-radius
:
30px
;
.announ-title
{
margin
:
0
;
margin-bottom
:
10px
;
color
:
#000
;
font-size
:
36px
;
font-weight
:
700
;
line-height
:
normal
;
}
.dec-list
{
width
:
100%
;
transition
:
max-height
0.3s
cubic-bezier
(
0
,
1
,
0
,
1
);
.announ-descr
{
margin
:
0
;
margin-bottom
:
10px
;
color
:
#000
;
font-size
:
15px
;
font-weight
:
300
;
line-height
:
normal
;
overflow
:
hidden
;
max-height
:
0
;
}
.ul-open
{
.announ-descr-close
{
max-height
:
250px
;
transition
:
max-height
0.3s
cubic-bezier
(
0
,
1
,
0
,
1
);
}
.announ-descr-open
{
max-height
:
3000px
;
transition
:
max-height
0.3s
cubic-bezier
(
1
,
0
,
1
,
0
);
max-height
:
2000px
;
position
:
relative
;
z-index
:
3
;
}
.dec-item
{
padding
:
10px
10px
;
.announ-btn
{
position
:
absolute
;
z-index
:
-10
;
padding
:
0
;
margin-bottom
:
20px
;
background
:
none
;
border
:
none
;
outline
:
none
;
color
:
#000
;
font-size
:
15px
;
font-weight
:
700
;
line-height
:
normal
;
cursor
:
pointer
;
align-self
:
flex-start
;
opacity
:
0
;
}
.announ-btn-active
{
position
:
relative
;
background
:
url('../../img/profile/arrow-right.svg')
no-repeat
center
right
;
background-size
:
30px
30px
;
border-radius
:
5px
;
transition
:
0.3s
background-color
;
z-index
:
1
;
opacity
:
1
;
}
.dec-item
:last-child
{
margin-bottom
:
20px
;
.announ-bottom
{
display
:
flex
;
align-items
:
flex-start
;
/* justify-content: flex-start; */
}
.dec-item
:hover
{
background-color
:
#ebebeb
;
.announ-author
{
display
:
flex
;
flex-wrap
:
nowrap
;
margin-right
:
20px
;
font-weight
:
400
;
font-size
:
15px
;
line-height
:
20px
;
color
:
#5A88FF
;
}
.dec-item
:active
{
background-color
:
#fff
;
.announ-files-list
{
max-width
:
80%
;
list-style
:
none
;
display
:
flex
;
flex-wrap
:
wrap
;
row-gap
:
10px
;
column-gap
:
20px
;
}
.dec-name
{
padding
:
0
;
font-size
:
18px
;
display
:
block
;
.announ-files-item
{
position
:
relative
;
padding
:
6px
10px
;
border
:
1px
solid
#103A84
;
border-radius
:
3px
;
}
.announ-files-link
{
color
:
#103A84
;
}
.
dec-name
::after
{
.
announ-files-link
::after
{
content
:
""
;
position
:
absolute
;
top
:
0
;
left
:
0
;
right
:
0
;
bottom
:
0
;
left
:
0
;
}
.dec-span
{
font-size
:
15px
;
font-weight
:
300
;
.announ-img
{
overflow
:
hidden
;
width
:
calc
(
100%
-
750px
);
background
:
#103A84
;
background-repeat
:
no-repeat
;
background-position
:
center
center
;
background-size
:
cover
;
border-top-right-radius
:
9px
;
border-bottom-right-radius
:
9px
;
}
.load-btn
{
padding
:
10px
30px
;
margin-top
:
20px
;
display
:
flex
;
justify-content
:
space-between
;
align-items
:
center
;
border
:
none
;
outline
:
none
;
font-size
:
16px
;
border-radius
:
5px
;
cursor
:
pointer
;
background
:
#103A84
;
color
:
#fff
;
transition
:
background
0.3s
linear
;
}
.
dec-span
:not
(
:last-child
)
{
margin-right
:
2px
;
.
load-btn
:hover
{
background
:
#0d306d
;
}
.load-btn
:active
{
background
:
#3e5e96
;
}
@media
(
max-width
:
2000px
){
/* стили для xs-устройств */
.flex
{
width
:
80%
;
min-height
:
9em
;
max-height
:
15em
;
margin
:
2%
;
border-radius
:
8px
;
}
.Fother
{
justify-content
:
center
;
}
.IB
{
border-radius
:
0
8px
8px
0
;
}
}
\ Нет новой строки в конце файла
Пред
1
2
След
Редактирование
Предварительный просмотр
Поддерживает Markdown
0%
Попробовать снова
или
прикрепить новый файл
.
Отмена
You are about to add
0
people
to the discussion. Proceed with caution.
Сначала завершите редактирование этого сообщения!
Отмена
Пожалуйста,
зарегистрируйтесь
или
войдите
чтобы прокомментировать