mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-22 13:16:33 +03:00
added folders
This commit is contained in:
parent
24ef17bde3
commit
83ea171886
|
@ -0,0 +1,223 @@
|
||||||
|
# Generated by Django 4.2 on 2023-04-22 09:07
|
||||||
|
|
||||||
|
import akarpov.files.services.files
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
import model_utils.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
replaces = [
|
||||||
|
("files", "0001_initial"),
|
||||||
|
("files", "0002_alter_basefile_options_alter_folder_options_and_more"),
|
||||||
|
("files", "0003_basefile_short_link_folder_short_link"),
|
||||||
|
("files", "0004_alter_basefile_short_link_alter_folder_short_link"),
|
||||||
|
("files", "0005_alter_basefile_description_alter_basefile_folder_and_more"),
|
||||||
|
("files", "0006_alter_basefile_slug"),
|
||||||
|
("files", "0007_file_alter_folder_parent_delete_basefile_file_folder_and_more"),
|
||||||
|
("files", "0008_file_completed_on_file_created_on_file_filename_and_more"),
|
||||||
|
("files", "0009_remove_file_completed_on_remove_file_created_on_and_more"),
|
||||||
|
("files", "0010_fileintrash"),
|
||||||
|
("files", "0011_file_file_type_alter_file_description_and_more"),
|
||||||
|
("files", "0012_alter_file_options_alter_file_file"),
|
||||||
|
("files", "0013_alter_file_options"),
|
||||||
|
("files", "0014_alter_fileintrash_file"),
|
||||||
|
("files", "0015_fileintrash_name"),
|
||||||
|
("files", "0016_alter_file_file_type_alter_file_name"),
|
||||||
|
]
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
("shortener", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Folder",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"created",
|
||||||
|
model_utils.fields.AutoCreatedField(
|
||||||
|
default=django.utils.timezone.now,
|
||||||
|
editable=False,
|
||||||
|
verbose_name="created",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"modified",
|
||||||
|
model_utils.fields.AutoLastModifiedField(
|
||||||
|
default=django.utils.timezone.now,
|
||||||
|
editable=False,
|
||||||
|
verbose_name="modified",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=100)),
|
||||||
|
("slug", models.SlugField(blank=True, max_length=20)),
|
||||||
|
(
|
||||||
|
"parent",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="children",
|
||||||
|
to="files.folder",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="files_folders",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"short_link",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
to="shortener.link",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"abstract": False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="FileInTrash",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"created",
|
||||||
|
model_utils.fields.AutoCreatedField(
|
||||||
|
default=django.utils.timezone.now,
|
||||||
|
editable=False,
|
||||||
|
verbose_name="created",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"modified",
|
||||||
|
model_utils.fields.AutoLastModifiedField(
|
||||||
|
default=django.utils.timezone.now,
|
||||||
|
editable=False,
|
||||||
|
verbose_name="modified",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"file",
|
||||||
|
models.FileField(
|
||||||
|
upload_to=akarpov.files.services.files.trash_file_upload
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="trash_files",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(blank=True, max_length=200)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"abstract": False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="File",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("slug", models.SlugField(blank=True, max_length=20, unique=True)),
|
||||||
|
(
|
||||||
|
"created",
|
||||||
|
model_utils.fields.AutoCreatedField(
|
||||||
|
default=django.utils.timezone.now,
|
||||||
|
editable=False,
|
||||||
|
verbose_name="created",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"modified",
|
||||||
|
model_utils.fields.AutoLastModifiedField(
|
||||||
|
default=django.utils.timezone.now,
|
||||||
|
editable=False,
|
||||||
|
verbose_name="modified",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(blank=True, max_length=255, null=True)),
|
||||||
|
("description", models.TextField(blank=True, null=True)),
|
||||||
|
("private", models.BooleanField(default=True)),
|
||||||
|
("preview", models.FileField(blank=True, upload_to="file/previews/")),
|
||||||
|
(
|
||||||
|
"file",
|
||||||
|
models.FileField(
|
||||||
|
upload_to=akarpov.files.services.files.user_unique_file_upload
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"folder",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="files",
|
||||||
|
to="files.folder",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"short_link",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
to="shortener.link",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="files",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("file_type", models.CharField(blank=True, max_length=255, null=True)),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"abstract": False,
|
||||||
|
"ordering": ["-modified"],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,106 @@
|
||||||
|
# Generated by Django 4.2 on 2023-04-22 09:13
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("contenttypes", "0002_remove_content_type_name"),
|
||||||
|
("files", "0001_squashed_0016_alter_file_file_type_alter_file_name"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name="folder",
|
||||||
|
options={"base_manager_name": "objects"},
|
||||||
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name="file",
|
||||||
|
old_name="file",
|
||||||
|
new_name="file_obj",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="file",
|
||||||
|
name="folder",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="file",
|
||||||
|
name="id",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="folder",
|
||||||
|
name="id",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="folder",
|
||||||
|
name="parent",
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="BaseFileItem",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"parent",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="children",
|
||||||
|
to="files.basefileitem",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"polymorphic_ctype",
|
||||||
|
models.ForeignKey(
|
||||||
|
editable=False,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="polymorphic_%(app_label)s.%(class)s_set+",
|
||||||
|
to="contenttypes.contenttype",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"abstract": False,
|
||||||
|
"base_manager_name": "objects",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="file",
|
||||||
|
name="basefileitem_ptr",
|
||||||
|
field=models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
default=1,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="files.basefileitem",
|
||||||
|
),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="folder",
|
||||||
|
name="basefileitem_ptr",
|
||||||
|
field=models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
default=2,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="files.basefileitem",
|
||||||
|
),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,49 @@
|
||||||
|
# Generated by Django 4.2 on 2023-04-22 09:21
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
import django.utils.timezone
|
||||||
|
import model_utils.fields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("files", "0017_alter_folder_options_rename_file_file_file_obj_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="file",
|
||||||
|
name="created",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="file",
|
||||||
|
name="modified",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="folder",
|
||||||
|
name="created",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="folder",
|
||||||
|
name="modified",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="basefileitem",
|
||||||
|
name="created",
|
||||||
|
field=model_utils.fields.AutoCreatedField(
|
||||||
|
default=django.utils.timezone.now,
|
||||||
|
editable=False,
|
||||||
|
verbose_name="created",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="basefileitem",
|
||||||
|
name="modified",
|
||||||
|
field=model_utils.fields.AutoLastModifiedField(
|
||||||
|
default=django.utils.timezone.now,
|
||||||
|
editable=False,
|
||||||
|
verbose_name="updated",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,54 @@
|
||||||
|
# Generated by Django 4.2 on 2023-04-22 09:24
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
("files", "0018_remove_file_created_remove_file_modified_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name="basefileitem",
|
||||||
|
options={"ordering": ["-modified"]},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name="file",
|
||||||
|
options={"base_manager_name": "objects"},
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="file",
|
||||||
|
name="user",
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name="folder",
|
||||||
|
name="user",
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="basefileitem",
|
||||||
|
name="user",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
default=1,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="files",
|
||||||
|
to=settings.AUTH_USER_MODEL,
|
||||||
|
),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="basefileitem",
|
||||||
|
name="parent",
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name="children",
|
||||||
|
to="files.folder",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
18
akarpov/files/migrations/0020_folder_size.py
Normal file
18
akarpov/files/migrations/0020_folder_size.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 4.2 on 2023-04-22 09:33
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("files", "0019_alter_basefileitem_options_alter_file_options_and_more"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="folder",
|
||||||
|
name="size",
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 4.2 on 2023-04-22 09:57
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("files", "0020_folder_size"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="folder",
|
||||||
|
name="amount",
|
||||||
|
field=models.IntegerField(default=0),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="folder",
|
||||||
|
name="private",
|
||||||
|
field=models.BooleanField(default=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -7,28 +7,60 @@
|
||||||
CharField,
|
CharField,
|
||||||
FileField,
|
FileField,
|
||||||
ForeignKey,
|
ForeignKey,
|
||||||
|
IntegerField,
|
||||||
SlugField,
|
SlugField,
|
||||||
TextField,
|
TextField,
|
||||||
)
|
)
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from model_utils.fields import AutoCreatedField, AutoLastModifiedField
|
||||||
from model_utils.models import TimeStampedModel
|
from model_utils.models import TimeStampedModel
|
||||||
|
from polymorphic.models import PolymorphicModel
|
||||||
|
|
||||||
from akarpov.files.services.files import trash_file_upload, user_unique_file_upload
|
from akarpov.files.services.files import trash_file_upload, user_unique_file_upload
|
||||||
from akarpov.tools.shortener.models import ShortLink
|
from akarpov.tools.shortener.models import ShortLink
|
||||||
|
|
||||||
|
|
||||||
class File(TimeStampedModel, ShortLink):
|
class BaseFileItem(PolymorphicModel):
|
||||||
|
parent = ForeignKey(
|
||||||
|
to="files.Folder",
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
on_delete=CASCADE,
|
||||||
|
related_name="children",
|
||||||
|
)
|
||||||
|
user = ForeignKey("users.User", related_name="files", on_delete=CASCADE)
|
||||||
|
created = AutoCreatedField("created")
|
||||||
|
modified = AutoLastModifiedField("updated")
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ["-modified"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_file(self):
|
||||||
|
return type(self) is File
|
||||||
|
|
||||||
|
def get_folder_chain(self):
|
||||||
|
folders = [self]
|
||||||
|
obj = self
|
||||||
|
while obj.parent:
|
||||||
|
folders.append(obj.parent)
|
||||||
|
obj = obj.parent
|
||||||
|
return folders
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
update_fields = kwargs.get("update_fields", None)
|
||||||
|
if update_fields:
|
||||||
|
kwargs["update_fields"] = set(update_fields).union({"modified"})
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class File(BaseFileItem, TimeStampedModel, ShortLink):
|
||||||
"""model to store user's files"""
|
"""model to store user's files"""
|
||||||
|
|
||||||
private = BooleanField(default=True)
|
private = BooleanField(default=True)
|
||||||
|
|
||||||
user = ForeignKey("users.User", related_name="files", on_delete=CASCADE)
|
|
||||||
folder = ForeignKey(
|
|
||||||
"files.Folder", related_name="files", blank=True, null=True, on_delete=CASCADE
|
|
||||||
)
|
|
||||||
|
|
||||||
preview = FileField(blank=True, upload_to="file/previews/")
|
preview = FileField(blank=True, upload_to="file/previews/")
|
||||||
file = FileField(blank=False, upload_to=user_unique_file_upload)
|
file_obj = FileField(blank=False, upload_to=user_unique_file_upload)
|
||||||
|
|
||||||
# meta
|
# meta
|
||||||
name = CharField(max_length=255, null=True, blank=True)
|
name = CharField(max_length=255, null=True, blank=True)
|
||||||
|
@ -39,6 +71,10 @@ class File(TimeStampedModel, ShortLink):
|
||||||
def file_name(self):
|
def file_name(self):
|
||||||
return self.file.path.split("/")[-1]
|
return self.file.path.split("/")[-1]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def file(self):
|
||||||
|
return self.file_obj
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def file_image_url(self):
|
def file_image_url(self):
|
||||||
if self.preview:
|
if self.preview:
|
||||||
|
@ -61,27 +97,24 @@ def get_absolute_url(self):
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"file: {self.name}"
|
return f"file: {self.name}"
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ["-modified"]
|
class Folder(BaseFileItem, ShortLink):
|
||||||
|
name = CharField(max_length=100)
|
||||||
|
slug = SlugField(max_length=20, blank=True)
|
||||||
|
private = BooleanField(default=True)
|
||||||
|
|
||||||
|
# meta
|
||||||
|
size = IntegerField(default=0)
|
||||||
|
amount = IntegerField(default=0)
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse("files:folder", kwargs={"slug": self.slug})
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"folder: {self.name}"
|
||||||
|
|
||||||
|
|
||||||
class FileInTrash(TimeStampedModel):
|
class FileInTrash(TimeStampedModel):
|
||||||
name = CharField(max_length=200, blank=True)
|
name = CharField(max_length=200, blank=True)
|
||||||
user = ForeignKey("users.User", related_name="trash_files", on_delete=CASCADE)
|
user = ForeignKey("users.User", related_name="trash_files", on_delete=CASCADE)
|
||||||
file = FileField(blank=False, upload_to=trash_file_upload)
|
file = FileField(blank=False, upload_to=trash_file_upload)
|
||||||
|
|
||||||
|
|
||||||
class Folder(TimeStampedModel, ShortLink):
|
|
||||||
name = CharField(max_length=100)
|
|
||||||
slug = SlugField(max_length=20, blank=True)
|
|
||||||
|
|
||||||
user = ForeignKey("users.User", related_name="files_folders", on_delete=CASCADE)
|
|
||||||
parent = ForeignKey(
|
|
||||||
"self", null=True, blank=True, related_name="children", on_delete=CASCADE
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
|
||||||
return reverse("files:folder", kwargs={"slug": self.slug})
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f"file: {self.name}"
|
|
||||||
|
|
|
@ -65,18 +65,18 @@ def view(file: File) -> (str, str):
|
||||||
|
|
||||||
|
|
||||||
def meta(file: File):
|
def meta(file: File):
|
||||||
descr = ""
|
description = ""
|
||||||
i = 0
|
i = 0
|
||||||
with file.file.open("r") as f:
|
with file.file.open("r") as f:
|
||||||
lines = f.readlines()
|
lines = f.readlines()
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if i == 0:
|
if i == 0:
|
||||||
descr += line + "\n"
|
description += line + "\n"
|
||||||
else:
|
else:
|
||||||
descr += line + " "
|
description += line + " "
|
||||||
i += 1
|
i += 1
|
||||||
if i > 20:
|
if i > 20:
|
||||||
descr += "..."
|
description += "..."
|
||||||
break
|
break
|
||||||
url = file.get_absolute_url()
|
url = file.get_absolute_url()
|
||||||
section = ""
|
section = ""
|
||||||
|
@ -88,7 +88,7 @@ def meta(file: File):
|
||||||
<meta property="og:title" content="{file.name}">
|
<meta property="og:title" content="{file.name}">
|
||||||
<meta property="og:url" content="{url}">
|
<meta property="og:url" content="{url}">
|
||||||
<meta property="og:image" content="">
|
<meta property="og:image" content="">
|
||||||
<meta property="og:description" content="{html.escape(descr)}">
|
<meta property="og:description" content="{html.escape(description)}">
|
||||||
<meta property="article:author" content="{file.user.username}">
|
<meta property="article:author" content="{file.user.username}">
|
||||||
<meta property="article:section" content="{section}">
|
<meta property="article:section" content="{section}">
|
||||||
<meta property="article:published_time" content="{file.created}">
|
<meta property="article:published_time" content="{file.created}">
|
||||||
|
|
|
@ -47,36 +47,3 @@ def view(file: File) -> (str, str):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return static, content
|
return static, content
|
||||||
|
|
||||||
|
|
||||||
def meta(file: File):
|
|
||||||
descr = ""
|
|
||||||
i = 0
|
|
||||||
with file.file.open("r") as f:
|
|
||||||
lines = f.readlines()
|
|
||||||
for line in lines:
|
|
||||||
if i == 0:
|
|
||||||
descr += line + "\n"
|
|
||||||
else:
|
|
||||||
descr += line + " "
|
|
||||||
i += 1
|
|
||||||
if i > 20:
|
|
||||||
descr += "..."
|
|
||||||
break
|
|
||||||
url = file.get_absolute_url()
|
|
||||||
section = ""
|
|
||||||
if file.file_type:
|
|
||||||
section = file.file_type.split("/")[0]
|
|
||||||
|
|
||||||
meat_f = f"""
|
|
||||||
<meta property="og:type" content="article">
|
|
||||||
<meta property="og:title" content="{file.name}">
|
|
||||||
<meta property="og:url" content="{url}">
|
|
||||||
<meta property="og:image" content="">
|
|
||||||
<meta property="og:description" content="{html.escape(descr)}">
|
|
||||||
<meta property="article:author" content="{file.user.username}">
|
|
||||||
<meta property="article:section" content="{section}">
|
|
||||||
<meta property="article:published_time" content="{file.created}">
|
|
||||||
<meta property="article:modified_time" content="{file.modified}">
|
|
||||||
"""
|
|
||||||
return meat_f
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from akarpov.files.views import (
|
from akarpov.files.views import (
|
||||||
ChunkedUploadDemo,
|
|
||||||
MyChunkedUploadCompleteView,
|
MyChunkedUploadCompleteView,
|
||||||
MyChunkedUploadView,
|
MyChunkedUploadView,
|
||||||
TopFolderView,
|
TopFolderView,
|
||||||
|
@ -14,12 +13,16 @@
|
||||||
app_name = "files"
|
app_name = "files"
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("", TopFolderView.as_view(), name="main"),
|
path("", TopFolderView.as_view(), name="main"),
|
||||||
path("upload", ChunkedUploadDemo.as_view(), name="chunked_upload"),
|
|
||||||
path(
|
path(
|
||||||
"api/chunked_upload_complete/",
|
"api/chunked_upload_complete/",
|
||||||
MyChunkedUploadCompleteView.as_view(),
|
MyChunkedUploadCompleteView.as_view(),
|
||||||
name="api_chunked_upload_complete",
|
name="api_chunked_upload_complete",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"api/chunked_upload_complete/<str:slug>",
|
||||||
|
MyChunkedUploadCompleteView.as_view(),
|
||||||
|
name="api_chunked_upload_complete_folder",
|
||||||
|
),
|
||||||
path(
|
path(
|
||||||
"api/chunked_upload/", MyChunkedUploadView.as_view(), name="api_chunked_upload"
|
"api/chunked_upload/", MyChunkedUploadView.as_view(), name="api_chunked_upload"
|
||||||
),
|
),
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils.timezone import now
|
||||||
from django.views.generic import DetailView, ListView, RedirectView, UpdateView
|
from django.views.generic import DetailView, ListView, RedirectView, UpdateView
|
||||||
from django.views.generic.base import TemplateView
|
from django.views.generic.base import TemplateView
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@
|
||||||
ChunkedUploadView,
|
ChunkedUploadView,
|
||||||
)
|
)
|
||||||
from akarpov.files.forms import FileForm
|
from akarpov.files.forms import FileForm
|
||||||
from akarpov.files.models import File, Folder
|
from akarpov.files.models import BaseFileItem, File, Folder
|
||||||
from akarpov.files.previews import extensions, meta, meta_extensions, previews
|
from akarpov.files.previews import extensions, meta, meta_extensions, previews
|
||||||
from akarpov.files.services.preview import get_base_meta
|
from akarpov.files.services.preview import get_base_meta
|
||||||
|
|
||||||
|
@ -26,17 +27,43 @@
|
||||||
class TopFolderView(LoginRequiredMixin, ListView):
|
class TopFolderView(LoginRequiredMixin, ListView):
|
||||||
template_name = "files/list.html"
|
template_name = "files/list.html"
|
||||||
paginate_by = 19
|
paginate_by = 19
|
||||||
model = File
|
model = BaseFileItem
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return File.objects.filter(user=self.request.user, folder__isnull=True)
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
contex = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
contex["folders"] = Folder.objects.filter(
|
context["folder_slug"] = None
|
||||||
user=self.request.user, parent__isnull=True
|
return context
|
||||||
)
|
|
||||||
return contex
|
def get_queryset(self):
|
||||||
|
return BaseFileItem.objects.filter(user=self.request.user, parent__isnull=True)
|
||||||
|
|
||||||
|
|
||||||
|
class FileFolderView(ListView):
|
||||||
|
template_name = "files/folder.html"
|
||||||
|
model = BaseFileItem
|
||||||
|
paginate_by = 39
|
||||||
|
slug_field = "slug"
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
self.object = None
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
folder = self.get_object()
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context["folder_slug"] = folder.slug
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_object(self, *args):
|
||||||
|
obj = get_object_or_404(Folder, slug=self.kwargs["slug"])
|
||||||
|
if self.object:
|
||||||
|
return self.object
|
||||||
|
self.object = obj
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
folder = self.get_object()
|
||||||
|
return BaseFileItem.objects.filter(parent=folder)
|
||||||
|
|
||||||
|
|
||||||
class FileUpdateView(LoginRequiredMixin, UpdateView):
|
class FileUpdateView(LoginRequiredMixin, UpdateView):
|
||||||
|
@ -131,12 +158,6 @@ def get_redirect_url(self, *args, **kwargs):
|
||||||
delete_file_view = DeleteFileView.as_view()
|
delete_file_view = DeleteFileView.as_view()
|
||||||
|
|
||||||
|
|
||||||
class FileFolderView(DetailView):
|
|
||||||
template_name = "files/folder.html"
|
|
||||||
model = Folder
|
|
||||||
slug_field = "slug"
|
|
||||||
|
|
||||||
|
|
||||||
folder_view = FileFolderView.as_view()
|
folder_view = FileFolderView.as_view()
|
||||||
|
|
||||||
|
|
||||||
|
@ -169,17 +190,42 @@ def check_permissions(self, request):
|
||||||
)
|
)
|
||||||
|
|
||||||
def on_completion(self, uploaded_file, request):
|
def on_completion(self, uploaded_file, request):
|
||||||
if uploaded_file.size <= request.user.left_file_upload:
|
folder = None
|
||||||
|
prepared = True
|
||||||
|
if "slug" in self.kwargs and self.kwargs["slug"]:
|
||||||
|
try:
|
||||||
|
folder = Folder.objects.get(slug=self.kwargs["slug"])
|
||||||
|
if folder.user != self.request.user:
|
||||||
|
self.message = {
|
||||||
|
"message": "You can't upload to this folder",
|
||||||
|
"status": False,
|
||||||
|
}
|
||||||
|
prepared = False
|
||||||
|
except Folder.DoesNotExist:
|
||||||
|
self.message = {
|
||||||
|
"message": "Folder doesn't exist",
|
||||||
|
"status": False,
|
||||||
|
}
|
||||||
|
prepared = False
|
||||||
|
if prepared and uploaded_file.size <= request.user.left_file_upload:
|
||||||
f = File.objects.create(
|
f = File.objects.create(
|
||||||
user=request.user, file=uploaded_file, name=uploaded_file.name
|
user=request.user,
|
||||||
|
file_obj=uploaded_file,
|
||||||
|
name=uploaded_file.name,
|
||||||
|
parent=folder,
|
||||||
)
|
)
|
||||||
|
if folder:
|
||||||
|
folder.modified = now()
|
||||||
|
folder.size += uploaded_file.size
|
||||||
|
folder.amount += 1
|
||||||
|
folder.save()
|
||||||
request.user.left_file_upload -= uploaded_file.size
|
request.user.left_file_upload -= uploaded_file.size
|
||||||
request.user.save()
|
request.user.save()
|
||||||
self.message = {
|
self.message = {
|
||||||
"message": f"File {f.file.name.split('/')[-1]} successfully uploaded",
|
"message": f"File {f.file.name.split('/')[-1]} successfully uploaded",
|
||||||
"status": True,
|
"status": True,
|
||||||
}
|
}
|
||||||
else:
|
elif prepared:
|
||||||
self.message = {
|
self.message = {
|
||||||
"message": "File is too large, please increase disk space",
|
"message": "File is too large, please increase disk space",
|
||||||
"status": False,
|
"status": False,
|
||||||
|
|
1
akarpov/templates/files/folder.html
Normal file
1
akarpov/templates/files/folder.html
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{% extends 'files/list.html' %}
|
|
@ -37,6 +37,7 @@
|
||||||
{{ folder.name }}
|
{{ folder.name }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
|
{% if request.user.is_authenticated %}
|
||||||
<div class="col-lg-2 col-xxl-2 col-md-4 col-sm-6 col-xs-12 mb-3 m-3 d-flex align-items-stretch card">
|
<div class="col-lg-2 col-xxl-2 col-md-4 col-sm-6 col-xs-12 mb-3 m-3 d-flex align-items-stretch card">
|
||||||
<div class="card-body d-flex flex-column justify-content-center align-items-center">
|
<div class="card-body d-flex flex-column justify-content-center align-items-center">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
@ -64,8 +65,10 @@
|
||||||
<div id="messages"></div>
|
<div id="messages"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% for file in file_list %}
|
{% endif %}
|
||||||
|
{% for file in basefileitem_list %}
|
||||||
<div class="col-lg-2 col-xxl-2 col-md-4 col-sm-6 col-xs-12 mb-3 m-3 d-flex align-items-stretch card">
|
<div class="col-lg-2 col-xxl-2 col-md-4 col-sm-6 col-xs-12 mb-3 m-3 d-flex align-items-stretch card">
|
||||||
|
{% if file.is_file %}
|
||||||
<div class="card-body d-flex flex-column">
|
<div class="card-body d-flex flex-column">
|
||||||
<h5 class="card-title">{{ file.name }}</h5>
|
<h5 class="card-title">{{ file.name }}</h5>
|
||||||
<p class="card-text mb-4"><small class="text-muted">{{ file.file_size | filesizeformat }}</small></p>
|
<p class="card-text mb-4"><small class="text-muted">{{ file.file_size | filesizeformat }}</small></p>
|
||||||
|
@ -76,6 +79,19 @@
|
||||||
<a href="{% url 'files:view' file.slug %}" class="stretched-link"></a>
|
<a href="{% url 'files:view' file.slug %}" class="stretched-link"></a>
|
||||||
<p class="card-text mb-4 mt-2 ms-3"><small class="text-muted">{{ file.modified | naturaltime }}</small></p>
|
<p class="card-text mb-4 mt-2 ms-3"><small class="text-muted">{{ file.modified | naturaltime }}</small></p>
|
||||||
</div>
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="card-body d-flex flex-column">
|
||||||
|
<h5 class="card-title">{{ file.name }}</h5>
|
||||||
|
<p class="card-text mb-4"><small class="text-muted">{{ file.size | filesizeformat }}, {{ file.amount }} {% if file.amount == 1 %} item {% else %} items {% endif %}</small></p>
|
||||||
|
<div class="align-self-stretch align-items-center justify-content-center d-flex flex-column fill-height controlsdiv">
|
||||||
|
<i class="bi bi-folder"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a href="{% url 'files:folder' file.slug %}" class="stretched-link"></a>
|
||||||
|
<p class="card-text mb-4 mt-2 ms-3"><small class="text-muted">{{ file.modified | naturaltime }}</small></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -207,7 +223,11 @@
|
||||||
sel.text(progress + "%");
|
sel.text(progress + "%");
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
|
{% if folder_slug %}
|
||||||
|
url: "{% url 'files:api_chunked_upload_complete_folder' slug=folder_slug %}",
|
||||||
|
{% else %}
|
||||||
url: "{% url 'files:api_chunked_upload_complete' %}",
|
url: "{% url 'files:api_chunked_upload_complete' %}",
|
||||||
|
{% endif %}
|
||||||
data: {
|
data: {
|
||||||
csrfmiddlewaretoken: csrf,
|
csrfmiddlewaretoken: csrf,
|
||||||
upload_id: data.result.upload_id,
|
upload_id: data.result.upload_id,
|
||||||
|
|
BIN
models.png
BIN
models.png
Binary file not shown.
Before Width: | Height: | Size: 2.6 MiB After Width: | Height: | Size: 2.4 MiB |
Loading…
Reference in New Issue
Block a user