سَعَد و حَمَد که در یک خوابگاه، هماتاقی هستند؛ از طبقهی همکف سوار آسانسور میشوند تا به طبقهای که اتاقشان در آن قرار دارد بروند. ولی هنگامی که سوار آسانسور میشوند؛ تصمیم به انجام بازی هیجانانگیزی میگیرند!
آسانسور خوابگاه آنها بدین صورت است که فقط دکمهی بالا و پایین دارد، دکمهی بالا، آسانسور را به یک طبقه بالاتر میبرد و دکمهی پایین، آسانسور را به یک طبقه پایینتر.
بازی به این صورت است که این دو نفر، ۴ بار فرصت دارند تا دکمهی پایین و بالای این آسانسور را فشار دهند. در نهایت، پس از اینکه ۴ بار دکمههای بالا و پایین آسانسور فشار داده شد؛ باید بفهمند که در کدام طبقه قرار دارند.
فرض میکنیم که طبقات منفی نیز داریم و آسانسور، حداکثر تا ۴ طبقه، زیر زمین نیز خواهد رفت.
حال تابع `calculate_floor` را بهگونهای تکمیل کنید که با گرفتن یک رشتهی ۴ حرفی که شامل `U` به معنای رفتن به طبقهی بالا و `D` به معنای رفتن به طبقهی پایین است، شمارهی طبقهای که در نهایت به آن میرویم را بازگرداند.
دقت کنید که در ابتدای حرکت، در طبقهی همکف (شماره ۰) قرار داریم.
``` python calculator.py
def calculate_floor(string):
pass
```
## نمونه ۱
``` python
>>> calculate_floor('UUDU')
2
```
<details class="orange">
<summary> **توضیحات نمونه** </summary>
ابتدا در طبقهی همکف قرار داریم. سپس با دیدن حرف `U` یک طبقه به بالا میرویم و در طبقهی ۱ قرار داریم. مجددا با دیدن حرف `U` یک طبقهی دیگر به بالا میرویم و در طبقهی ۲ قرار داریم. حال با دیدن `D` یک طبقه به پایین میرویم و در طبقهی ۱ قرار داریم. در نهایت با دیدن `U` یک طبقه به بالا میرویم و در نهایت در طبقهی ۲ هستیم. پس عدد ۲ را بازمیگردانیم.
</details>
## نمونه ۲
``` python
>>> calculate_floor('DDDD')
-4
```
<details class="orange">
<summary> **توضیحات نمونه** </summary>
ابتدا در طبقهی همکف قرار داریم. با هر بار مشاهدهی حرف `D`، یک طبقه به پایین میرویم. پس با ۴ بار دیدن حرف `D`، چهار بار به پایین میرویم و در نهایت در طبقهی ۴- قرار میگیریم. پس ۴- را بازمیگردانیم.
</details>
## نکات
+ میتوانید فایل اولیه این سوال را از [این لینک](/contest/assignments/51094/download_problem_initial_project/174126/) دریافت کنید.
+ شما باید تابع `calculate_floor` موجود در فایل `calculator.py` را تکمیل و سپس این فایل را ارسال کنید.
+ تابع شما نباید مقداری را چاپ کند، بلکه باید مقدار مورد نظر را بازگرداند.
+ تضمین میشود که رشتههای ورودی، همیشه یک رشتهی ۴ حرفی متشکل از حروف `U` و `D` میباشند.
تبریک! شما در ژورنالی که سلیب رئیس آن است، استخدام شدهاید. اما سلیب که بسیار سختگیر است، در همان ابتدای کار به شما یک وظیفه محول کرده است. شما باید برنامهای برای اعتبارسنجی اولیهٔ مقالاتی که نویسندگان به ژورنال برای چاپ ارسال کردهاند، بنویسید. فرمت این اعتبارسنجی به شرح زیر است:
## تابع `extract_paper`
### عملکرد تابع
در ورودی آدرس فایل مقاله و سایز فونت را می گیرد. باید بتواند با باز کردن و خواندن فایل مقاله، فیلدهای مختلف آن را استخراج کرده و یک دیکشنری از آن بسازد. فرمت مقالهها به شکل زیر است:
![توضیح تصویر](https://s4.uupload.ir/files/68er_i5al.png)
در نهایت این تابع باید یک دیکشنری با کلیدهای زیر برگرداند.
+ **عنوان `title`:** از نوع str است.
+ **چکیده `abstract`:** از نوع str است.
+ **کلمات کلیدی `keywords`:** از نوع list است.
+ **مقدمه `introduction`:** از نوع str است.
+ **بدنه `body`:** از نوع str است.
+ **نتیجهگیری `conclusion`:** از نوع str است.
+ **مراجع `references`:** از نوع list است.
+ **تعداد کلمات کل مقاله `words_count`:** از نوع int است.
+ **تعداد صفحات کل مقاله `pages_count`:** از نوع int است.
### اعتبارسنجیها
+ چکیده نباید بیش از ۱۵۰ کلمه باشد. درغیراینصورت یک Exception با پیام `The abstract section can't be more than 150 words` پرتاب میشود.
+ تعداد کلمات کلیدی نباید بیش از ۵ باشد. درغیراینصورتت یک Exception با پیام `You can't put more than 5 keywords` پرتاب میشود.
+ کلمات کلیدی باید بر اساس حروف الفبا مرتب شده باشند. درغیراینصورت یک Exception با پیام `Keywords are not sorted` پرتاب میشود.
+ طول کل مقاله نباید بیش از ۹ صفحه باشد. درغیراینصورت یک Exception با پیام `The whole paper can't be more than 9 pages` پرتاب میشود.
### نحوهٔ شمارش کلمات
جداکنندهٔ کلمات از یکدیگر، کاراکترهای «فاصله» و «خط جدید» هستند.
### نحوهٔ شمارش صفحات
محاسبهٔ تعداد صفحات از طریق تعداد کلمات و اندازهٔ فونت صورت میگیرد. هر ۵۱۲ کلمه با اندازهٔ فونت ۱۶، یک صفحه را تشکیل میدهند. اگر اندازهٔ فونت بزرگتر شود، یک صفحه شامل تعداد کلمات کمتری خواهد بود و اگر اندازهٔ فونت کوچکتر شود، یک صفحه شامل تعداد کلمات بیشتری میشود.
بهطور مثال فرض کنید یک مقاله ۵۱۲ کلمه باشد. اگر اندازهٔ فونت ۱۶ باشد، این مقاله یک صفحه است و اگر اندازهٔ فونت ۳۲ باشد، این مقاله ۲ صفحه خواهد بود زیرا هر صفحه شامل ۲۵۶ کلمه میشود.
## نکات
+ میتوانید فایل اولیهٔ این سؤال را از [این لینک](/contest/assignments/51094/download_problem_initial_project/174127/) دریافت کنید.
واحد جنایی کوئرا که فعالیت خودش را از سال ۱۳۹۹ آغاز کرده بود، فیلمی از کارآگاه فرهاد -یکی از اولین کارآگاههای کوئرا- دریافت کرده است. در این فیلم فرهاد توسط یک باند مافیایی محاصره شده است و از کوئرا درخواست کمک کرده است. فرهاد به سرنخهای مهمی از عملیاتهای این باند مافیایی دست پیدا کرده است و آنها را داخل یکی از سرورهای امن کوئرا و با چند پیچیدگی امنیتی آپلود کرده است. باند مافیایی که از این ماجرا بسیار عصبانی شده بود، فرهاد را به قتل رساند! حال واحد جنایی کوئرا به کارآگاه کیان و کارآگاه آدرینا ماموریت داده است تا دادههایی که فرهاد بر روی سرور قرار داده است را رمزگشایی کنند.
از آنجایی که فرهاد چندین لایه امنیتی را بر روی سرور تنظیم کرده است، آنها به کمک شما برای پیدا کردن سرنخها نیاز دارند.
## ساختار پروژه
کیان و آدرینا کلاسی به نام `Detective` را طراحی کردند که دارای توابع زیر هست:
<details class="green">
<summary>**تابع** `login`</summary>
این تابع با دریافت `username` و `password` و `URL` صفحه ورود، وظیفه احراز هویت کاربران را به عهده دارد. در صورتی که عملیات احراز هویت موفقیت آمیز باشد، یک فایل `JSON` به فرمت زیر برگردانده میشود:
```json
{
"token": <mark title="توکن احراز هویت کاربر" class="yellow"><Authorization Token></mark>,
"first_name": "Kian",
"last_name": "Majlessi",
"email": "contact@quera.org",
"upload_url": <mark title="URL صفحه آپلود سرنخها" class="yellow"><UPLOAD_URL></mark>
}
```
از آنجایی که `token` و `upload_url` محرمانه هستند؛ لازم هست که شما یک دیکشنری تنها با دو کلید `full_name` و `email` برگردانید.
+ `full_name` یک کاربر نام و نام خانوادگی او است که با یک اسپیس از هم جدا شدهاند.
و در صورتی که عملیات احراز هویت موفقیت آمیز نبود، باید یک `Exception` با پیغام زیر پرتاب کنید:
```
[<mark title="در اینجا کد وضعیتی که از سرور دریافت میکنید را بنویسید" class="red"><STATUS_CODE></mark>]: Unable to log in with provided credentials.
```
### نکات مهم
+ درخواستهای شما به صفحه ورود باید از طریق متد `POST` انجام شوند.
+ سرور فرهاد از **احراز هویت با توکن** استفاده میکند. به این صورت که هر کابر برای لاگین کردن پس از ارسال نام کاربری و رمز عبور خود و در صورت درست بودن اطلاعات، یک نشانهی منحصر به فرد _(Unique Token)_ را به عنوان پاسخ دریافت میکند. از این پس هر ریکوئستی که آن کاربر به ایپیآیهای آن سرور میزند، برای آن که لاگین بودن خود را ثابت کند، باید این نشانهی منحصر به فرد را برای سرور ارسال کند تا سرور بتواند هویت آن شخص را بر اساس این نشانه، تشخیص دهد و به او اجازههای دسترسی لازم را بدهد.
+ برای ارسال توکن به سرور باید مقدار زیر را در Header درخواستهای خود به سرور قرار دهید.
```
Authorization: Token <mark title="توکن دریافتی از سرور" class="red"><Token></mark>
```
+ برای امنیت بیشتر، پس از لاگین کاربر، یک کوکی مخفی در سیستم او ذخیره میشود. برای انجام درخواستهای بعدی لازم است که این کوکی را در سیستم خود در اختیار داشته باشید!
</details>
<details class="teal">
<summary>**تابع** `upload_clues`</summary>
سعید و مهدی که موازی با فرهاد در حال کار بر روی این پرونده بودند، مدارکی را جمعآوری و در پوشهای به نام `secrets` در کنار فایل کلاینت شما قرار دادند. شما باید تمامی این مدارک را پیدا کرده و از طریق متد `PUT` و فیلد `uploaded_files` داخل آدرسی که در مرحله قبل دریافت کردهاید در سرور آپلود کنید.
در نهایت، سرور یک فایل `JSON` که شامل کلیدهای `detail` و `download_url` هست را به شما برمیگرداند. از مقدار `download_url` برای قسمت بعدی سوال استفاده کنید و مقدار `detail` را برای ما برگردانید!
```python
put(url=upload_url, files=[('uploaded_files', open(file_address,"rb")),('uploaded_files', , open(file_address,"rb")), ......])
```
</details>
<details class="purple">
<summary>**تابع** `html_scraper`</summary>
تبریک! شما به اسناد فرهاد دسترسی پیدا کردید. اما عجله نکنید! این تازه اول راه است. فرهاد که هیچوقت نمیخواست باند مافیا به اسناد دست پیدا کند، آنها را در مکانهای مختلفی قرار داد و لینکهایش را در صفحه `HTML` ای مخفی کرد. شما در این تابع با استفاده از متد `GET` و آدرس صفحهای که در مرحله قبل دریافت کردهاید، میتوانید این صفحه `HTML` را دانلود کنید. حال، تمامی لینکهای آن و عنوانهایش را پیدا کنید و در دیکشنریای به تیم جنایی کوئرا برگردانید. کلید دیکشنری شما باید عنوان لینک و مقدار آن آدرس لینک باشد.
+ **توجه کنید** که تنها لینکهایی را باید داخل دیکشنری قرار دهید که دارای عنوان باشند.
</details>
<details class="grey">
<summary>محتویات فایل `solution.py`</summary>
```python solution.py
class Detective:
def login(self, username: str, password: str, login_url: str):
pass
#TODO: Complete login Function
def upload_clues(self):
pass
#TODO: Complete upload_clues Function
def html_scraper(self):
pass
#TODO: Complete html_scraper Function
```
همچنین شما میتوانید پروژه اولیه را از [این لینک](/contest/assignments/51094/download_problem_initial_project/174128/) دانلود کنید.
</details>
## پاسخ ارسالی
در پاسخ ارسالی خود میتوانید از هر کتابخانهای که لازم میدانید استفاده کنید. اما در فایل ارسالی خود، علاوه بر فایل `solution.py` که حاوی راهحل شما است، باید فایلی با نام `python_requirements.txt` نیز موجود باشد که در آن نام کتابخانههای مورد نیاز و شمارهٔ نسخهٔ آنها به فرمت زیر در آن موجود باشد:
```txt python_requirements.txt
firstlib==1.2.3
secondlib==4.5.6
...
```
## ساختار فایل ارسالی
ساختار فایل `.zip` ارسالی شما باید به صورت زیر باشد:
```
<your_zip_file_name.zip>
├── solution.py
└── python_requirements.txt
```
فرهاد که به تازگی کتابفروشی آنلاین خود را باز کرده، تصمیم گرفته قابلیت تخفیف را به آن اضافه کند. ولی برای این کار نیاز به کمک شما دارد تا پروژه را طبق توضیحات ادامه تکمیل کنید.
## پروژه اولیه
پروژه اولیه را از [این لینک](/contest/assignments/51094/download_problem_initial_project/174129/) دانلود کنید. ساختار فایلهای این پروژه به صورت زیر است:
```
Discount
├── accounts
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── __init__.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── authors
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── <mark class="yellow" title="اجازه ایجاد فایل جدیدی در این پوشه را دارید ولی به جز فایلهای مشخص شده اجازه تغییر سایر فایلها را ندارید">> books <</mark>
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── <mark class="blue" title="این فایل را تغییر دهید">> models.py <</mark>
│ ├── <mark class="blue" title="این فایل را تغییر دهید">> serializers.py <</mark>
│ ├── tests.py
│ ├── urls.py
│ └── <mark class="blue" title="این فایل را تغییر دهید">> views.py <</mark>
├── BookStore Quera.postman_collection.json
├── config
│ ├── asgi.py
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── discounts
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── permissions.py
│ ├── serializers.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── fixtures
│ └── postman_sample_fixture.json
├── manage.py
├── requirements.txt
└── tests
├── __init__.py
└── testsample.py
```
### اپلیکشن `discounts`
اپلیکیشن `discounts` شامل مدلهای مختلفی میشود که کتاب میتواند براساس آن شامل تخفیف شود. در ادامه شرایط اعمال آنها را برای کتابها مشخص شده است.
<details class="green">
<summary> **مدل `CountryDiscount`** </summary>
اگر کشور کاربر با کشور مشخص شده در این تخفیف یکسان بود، تمامی کتابهای موجود شامل درصد تخفیف مشخص شده میشوند.
</details>
<details class="green">
<summary> **مدل `AuthorDiscount`** </summary>
تمامی کتابهایی که یکی از نویسندگان آن، نویسنده مشخص شده بود، شامل درصد تخفیف مشخص شده میشوند
</details>
<details class="green">
<summary> **مدل `CategoryDiscount`** </summary>
تمامی کتابهایی که یکی از دستهبندیهای آن، دستهبندی مشخص شده بود، شامل درصد تخفیف مشخص شده میشوند.
</details>
<details class="green">
<summary> **مدل `BookDiscount`** </summary>
در این تخیفیف تنها کتاب مشخص شده، شامل درصد تخفیف مشخص شده میشود.
</details>
## پیادهسازی مورد انتظار
**اکیدا توصیه میشود** پیش از حل این بخش سایر قسمتهای پروژه را مطالعه کنید.
<details class="yellow">
<summary> **تابع `get_discount` در `books/models.py`** </summary>
این تابع باید بهترین تخفیفی که شامل کتاب مورد نظر (`self`) میشود. را انتخاب و قیمت بعد از اعمال شدن آن تخفیف را خروجی دهد.
<details class="purple">
<summary> **نکات** </summary>
\* ممکن است چندین تخفیف مختلف را برای کتاب بتوان اعمال کرد. ولی فقط باید بهترین تخفیف بر روی آن، اعمال شود و در خروجی قیمت پس از اعمال تخفیف برگردانده شود.
\* دقت کنید ممکن است ریکوئست دریافتی از طرف کاربری که احراز هویت نشده فرستاده شود.
</details>
</details>
<details class="yellow">
<summary> **ویو `BookViewSet` در `books/views.py`** </summary>
شما باید با نوشتن سریالایزر یا سریالایزرهایی در `books/serializers.py` برای مدل `Book` و تکمیل ویو `BookViewSet` ریکوئستهایی مشابه نمونههای آورده شده در فایل *BookStore Quera.postman_collection.json* (این فایل را با اپلیکیشن **postman** باز کنید.) مدیریت کنید و پاسخ مشابهی دریافت کنید.
<details class="purple">
<summary> **نکات** </summary>
\* از فیکسچر *postman_sample_fixture.josn* برای ایجاد مثالهای موجود در کالکشن پستمن استفاده شده، در صورتی که مایل باشید میتوانید این فیکسچر را **load** کرده و ریکوئستها را مجدد اجرا کنید.
</details>
</details>
## نکات
+ شما تنها مجوز ایجاد تغییرات در فایلهای `books/views.py`، `books/models.py` و `books/serializers.py` و ایجاد فایل جدیدی در `books/` را دارید و **تمامی تغییرات دیگر شما** در فایلهای پروژه **نادیده گرفته خواهند شد.**
+ فراموش نکنید که میتوانید با مطالعهی `testsample.py` با روش تست کردن مدلها، فرمها و ادمینها آشنا شوید.
## نحوه ارسال
یک فایل _ZIP_ حاوی همهی فایلهای پروژه، آپلود کنید. نام فایل _ZIP_ اهمیتی ندارد.
کوئرا قصد دارد تا آپلودسنتری برای کاربران سامانه *LMS* اش طراحی کند. بدین ترتیب کاربران میتوانند فایلهای آموزشی موردنیاز خود برای هر کلاس را داخل صفحه کلاس آپلود کنند و لینکش را با بقیه به اشتراک قرار دهند. از آنجایی که همه آپلودسنترها دارای محدودیتهایی برای آپلود فایل هستند و تیم فنی کوئرا وقتی برای پیادهسازی این سامانه ندارند، از شما میخواهیم تا *API* آپلودسنتر مدنظرشان را طراحی کنید.
## پروژه اولیه
پروژه اولیه را از [این لینک](/contest/assignments/51094/download_problem_initial_project/174130/) دانلود کنید. ساختار فایلهای این پروژه به صورت زیر است:
```
django_upload_center
├── account
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── config
│ ├── __init__.py
│ ├── asgi.py
│ ├── <mark title="این فایل را میتوانید تغییر دهید" class="teal">settings.py</mark>
│ ├── urls.py
│ └── wsgi.py
├── tests
│ └── testssample.py
├── upload_center
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── <mark title="این فایل را تغییر دهید" class="yellow">serializers.py</mark>
│ ├── tests.py
│ ├── urls.py
│ └── <mark title="این فایل را تغییر دهید" class="yellow">views.py</mark>
├── manage.py
└── requirements.txt
```
### اپلیکشن `account`
اپلیکیشن `account` شامل دو مدل میشود که محدودیتهای کاربران را مشخص میکنند. در ادامه فیلدهای هر یک توضیح داده شده است.
<details class="green">
<summary> **مدل `User`** </summary>
این مدل شامل فیلدهای زیر است:
+ فیلد `account` که مشخص کننده نوع حساب کاربری یک `User` است.
+ فیلد `used_storage` که مقدار فضای اشغال شده در سرور توسط `User` را بر حسب بایت نشان میدهد.
</details>
<details class="green">
<summary> **مدل `Account`** </summary>
این مدل شامل فیلدهای زیر است:
+ فیلد `title` که عنوان اکانت را مشخص میکند.
+ فیلد `storage` که حداکثر فضای مربوط به این نوع حساب کاربری را بر حسب بایت مشخص میکند.
+ فیلد `max_file_transfer` که حداکثر محدودیت حجمی فایلهای آپلود شده مربوط به این نوع حساب کاربری را بر حسب بایت مشخص میکند.
</details>
## پیادهسازی مورد انتظار
**اکیدا توصیه میشود** پیش از حل این بخش سایر قسمتهای پروژه را مطالعه کنید.
<details class="yellow">
<summary> **ویو `UploadFile`** </summary>
متد `PUT` در این ویو، وظیفه آپلود فایل کاربران را بر عهده دارد و در پاسخ یک دیکشنری به صورت فایل `JSON` مانند زیر برمیگرداند:
```json
{
"city-g948bcbda2_640.jpg": "/fm/download/kian/city-g948bcbda2_640.jpg",
"a-month-ga3e069e51_640.jpg": "/fm/download/kian/a-month-ga3e069e51_640.jpg",
"Kargah.rar": "You don't have enough space to upload this file!",
"Tedx_Intro.pdf": "You can't upload files more than 1.000 Megabytes!"
}
```
در این دیکشنری، کلیدها نام فایل ذخیره شده در سرور و مقدار آنها آدرس دانلود فایل مربوطه میباشد.
در صورتی که حجم فایل ارسالی از محدودیت مشخص شده (`max_file_transfer`) بیشتر باشد، کلید دیکشنری اسم فایل ارسالی و مقدار آن باید عبارت زیر باشد:
```
You can't upload files more than <mark class="red" title="محدودیت حجمی کاربر با ۳ رقم اعشار"><user_max_file_transfer></mark> Megabytes!
```
و در صورتی که کاربر فضایی برای آپلود فایل جدید نداشت، کلید دیکشنری اسم فایل ارسالی و مقدار آن باید عبارت زیر باشد:
```
You don't have enough space to upload this file!
```
### نکات مهم
+ فایلهای کاربران باید در `root` پروژه و در دایرکتوری زیر ذخیره شوند.
```
.uploaded_files/<mark class="red" title="یوزرنیم کاربر آپلودکننده"><username></mark>
```
+ کاربران باید امکان آپلود چندین فایل را به صورت همزمان داشته باشند.
+ در صورتی که یک فایل خالی آپلود شود، استاتوس کد ۴۰۰ را برگردانید.
+ آپلودسنتر **حداکثر** تعداد فایلی که از کاربر دریافت میکند را باید با توجه به محدودیتهای اکانت کاربر آپلود کند.
+ کاربران باید بتوانند فایلهایی تکراری یا با نام یکسان آپلود کنند.
+ برای مدیریت آپلود فایلهایی با نام مشابه، فقط به انتهای نام فایل میتوانید یک شناسه (_suffix_) اضافه کنید و نام فایل نباید تغییری کند.
+ برای تبدیل کیلوبایت به مگابایت تنها کافیست که عدد موردنظر را بر عدد ۱۰۲۴ تقسیم کنید.
</details>
<details class="yellow">
<summary> **ویو `FileManager`** </summary>
<details class="orange">
<summary> متد `GET` </summary>
در این متد، اطلاعات کاربر به صورت یک فایل `JSON` مانند زیر برمیگردد:
```json
{
<mark title="نوع اکانت کاربر" class="red">"Account"</mark>: "Pro",
<mark title="میزان فضای ذخیرهسازی کاربر برحسب مگابایت (با ۳ رقم اعشار)" class="red">"Storage"</mark>: 5.000,
<mark title="میزان فضای مصرف شده توسط کاربر برحسب مگابایت (با ۳ رقم اعشار)" class="red">"Used"</mark>: 0.916,
<mark title="نام فایلهای ذخیره شده در سرور توسط کاربر" class="red">"Files"</mark>: [
"a-month-ga3e069e51_640.jpg",
"city-g948bcbda2_640.jpg"
]
}
```
+ در صورتی که کاربر فایلی در سرور نداشت، متن زیر را به عنوان مقدار کلید `Files` قرار دهید:
```
<mark class="red" title="یوزرنیم کاربر"><username></mark> doesn't have any files!
```
</details>
<details class="orange">
<summary> متد `DELETE` </summary>
در این متد، نام فایلی که قرار است حذف شود در پارامتر `file_name` از طریق دیکشنری `POST` شئ ریکوئست در دسترس است. در صورتی که فایل موردنظر در سرور وجود داشت، فایل را از سرور حذف کنید، اطلاعات کاربر را بهروز کنید و پاسخ زیر را در قالب `JSON` به کاربر نشان دهید:
```json
{
"detail": "<mark class="red" title="نام فایل"><FILE_NAME></mark> Deleted Successfully."
}
```
و در صورتی که فایل در سرور موجود نبود، پاسخ زیر را در قالب `JSON` و با استاتوس کد ۴۰۴ به کاربر ارائه دهید:
```json
{
"detail": "<mark class="red" title="نام فایل"><FILE_NAME></mark> hasn't existed!"
}
```
</details>
</details>
<details class="yellow">
<summary> **ویو `DownloadFile`** </summary>
در متد `GET` این ویو، فایل خواسته شده را به صورت یک `FileResponse` برگردانید.
+ پارامتر `user` نام کاربری کاربر آپلودکننده فایل است و پارامتر `filename` نام فایل را مشخص میکند.
+ در صورتی که فایل درخواست شده موجود نباشد، یک دیکشنری به فرمت زیر و با کد وضعیت ۴۰۴ برگردانید:
```python
{"detail": f"{filename} hasn't existed!"}
```
</details>
## نکات
+ شما تنها مجوز ایجاد تغییرات در فایلهای `upload_center/views.py`، `config/settings.py` و `upload_center/serializers.py` را دارید و **تمامی تغییرات دیگر شما** در فایلهای پروژه **نادیده گرفته خواهند شد.**
+ فراموش نکنید که میتوانید با مطالعهی `testssample.py` با روش تست کردن مدلها، فرمها و ویوها آشنا شوید.
## نحوه ارسال
یک فایل _ZIP_ حاوی همهی فایلهای پروژه، آپلود کنید. نام فایل _ZIP_ اهمیتی ندارد.