سجاد یک لیست $n$ تایی از اعداد دارد و در گروههای مختلف آن را تقسیمبندی میکند؛ به این صورت که $m$ عضو اول را در یگ گروه قرار میدهد، $m$ عضو بعدی را در یک گروه و به همین ترتیب اعضا را گروه بندی میکند (دقت کنید که گروه آخر ممکن است کمتر از $m$ عضو داشته باشد).
سجاد از روی این اعداد، یک لیست جدید میسازد که عضو $i$ام آن، جمع اعضای گروه $i$ام باشد.
او که به شطرنج علاقه خاصی دارد به صورت شطرنجی اعضای لیست جدید را از هم کم و زیاد میکند؛ به این معنا که از عضو اول لیست جدید، عضو دوم را کم میکند و سپس عضو سوم را اضافه میکند و از این مقدار عضو چهارم را کم میکند و این روند را ادامه میدهد تا به آخر لیست جدید برسد و سپس مقدار نهایی را به عنوان ارزش لیست در نظر میگیرد.
<details class="green">
<summary>
مثال محاسبه ارزش لیست
</summary>
به طور مثال اگر سجاد لیست زیر را داشته باشد و مقدار $m$ برابر با ۳ باشد:
$$[1, 2, 3, 4, 5, 6, 7, 8]$$
آنگاه لیست جدید به صورت زیر میشود:
$$[6, 15, 15]$$
بعد از آن سجاد اعداد لیست را به صورت شطرنجی جمع میکند و ارزش لیست برابر با عبارت زیر میشود:
$$6 - 15 + 15 = 6$$
بنابراین عدد نهایی سجاد برابر با ۶ میشود. همچنین اگر مقدار $m$ در این سوال برابر با یک بود ارزش نهایی برابر با عبارت زیر میشود:
$$1 - 2 + 3 - 4 + 5 - 6 + 7 - 8 = -4$$
</details>
در این سوال شما باید تابع `calculator(n, m, li)` را پیادهسازی کنید که به ترتیب $n$ (تعداد اعضای لیست)، و $m$ (تعداد اعضای هر گروه) و خود لیست را ورودی بگیرد و ارزش نهایی لیست را برگرداند.
# پروژه اولیه
پروژه اولیه را از [این لینک](/contest/assignments/21629/download_problem_initial_project/76084/) دانلود کنید. شما باید تابع `calculator` را در این فایل کامل کنید.
# مثال
```python
>>> calculator(8, 3, [1, 2, 3, 4, 5, 6, 7, 8])
6
>>> calculator(8, 1, [1, 2, 3, 4, 5, 6, 7, 8])
-4
```
# آنچه باید آپلود کنید
یک فایل پایتون که تابع `calculator` در آن پیادهسازی شده است را آپلود کنید.
پایتون - امتاییها
در این سوال شما باید یک کلاس مدیریت فاکتورهای فروش برای شرکت سجادینه طراحی کنید. در شرکت سجادینه افراد زیادی میتوانند فاکتورهای مالی را ثبت کنند و هر کدام از این افراد تاریخ فاکتور را به یکی از ۶ فرمتی که در جدول پایین آمده ثبت میکنند.
برای مثال یک فاکتور که روز دوم ماه ششم سال ۲۰۲۰ ثبت شود، میتواند طبق یکی از فرمتهای زیر ثبت شود:
| زمانی که در سیستم ثبت میشود | فرمت زمان |
|:------------------:|:------------------:|
| `02/06/2020` | `dd/mm/yyyy` |
| `02/2020/06` | `dd/yyyy/mm` |
| `2020/06/02` | `yyyy/mm/dd` |
| `2020/02/06` | `yyyy/dd/mm` |
| `06/2020/02` | `mm/yyyy/dd` |
| `06/02/2020` | `mm/dd/yyyy` |
# پروژه اولیه
پروژه اولیه را از [این لینک](/contest/assignments/21629/download_problem_initial_project/76083/) دانلود کنید. شما باید کلاس `FactorHandler` را در این فایل کامل کنید به طوری که سه تابع زیر عملکردهای خواسته شده را داشته باشند.
<details class="green">
<summary>
تابع `add_factor`
</summary>
این تابع به ترتیب سه ورودی `time_format` و `time` و `value` را ورودی میگیرد. مقدار `time_format` یکی از ۶ رشته جدول بالا است و `time` تاریخ ثبت فاکتور بر حسب فرمت داده شده است. مقدار `value` هم، هزینه فروش فاکتور داده شده برای آن تاریخ را مشخص میکند.
</details>
<details class="green">
<summary>
تابع `remove_all_factors`
</summary>
این تابع به ترتیب سه ورودی `time_format` و `time` را ورودی میگیرد که هر دویشان مانند تابع `add_factor` هستند؛ این تابع تمام فاکتورهایی که در تاریخ داده شده ثبت شدهاند را از لیست فاکتورها حذف میکند.
</details>
<details class="green">
<summary>
تابع `get_sum`
</summary>
این تابع به ترتیب سه ورودی `time_format` و `start_time` و `finish_time` را ورودی میگیرد و جمع هزینه فاکتورهایی که از تاریخ `start_time` تا `finish_time` ثبتشدهاند (شامل خود این دو تاریخ) را برمیگرداند.
</details>
در همه توابع تضمین میشود که `time` حتما بر حسب فرمت `time_format` است. توجه کنید که هیچ یک از توابع بالا را نباید استاتیک تعریف کنید.
# مثال
```python
>>> fh = FactorHandler()
>>> fh.add_factor("dd/mm/yyyy", "02/10/2019", 10)
>>> fh.add_factor("dd/mm/yyyy", "03/10/2019", 20)
>>> fh.add_factor("dd/mm/yyyy", "03/10/2019", 30)
>>> fh.add_factor("dd/mm/yyyy", "05/10/2019", 5)
>>> fh.get_sum("yyyy/dd/mm", "2019/02/10", "2019/03/10")
60
>>> fh.remove_all_factors("mm/dd/yyyy", "10/03/2019")
>>> fh.get_sum("yyyy/dd/mm", "2019/02/10", "2019/05/10")
15
```
# آنچه باید آپلود کنید
یک فایل پایتون که کلاس `FactorHandler` در آن پیادهسازی شده است را آپلود کنید.
پایتون - فاکتوریسم
در شهر انگوتستان دادهها تنها به وسیلهی [*JSON*](https://en.wikipedia.org/wiki/JSON) منتقل میشود. برای نمایش دادهی یک جدول در این شهر، به ازای هر سطر، یک فایل *JSON* ذخیره میشود؛ در فایل *JSON* مربوط به هر سطر، به ازای هر ستون، شماره ستون به عنوان `key` و مقدار موجود در آن سطر و ستون، به عنوان `value` ذخیره میشود.
<details class="green">
<summary>
مثال ذخیره جدول به صورت *JSON*
</summary>
برای مثال جدول زیر را در نظر بگیرید:
| ستون اول | ستون دوم | ستون سوم |
| :-----------: | :-----------: | :-----------: |
| ۳ | ۱ | ۴ |
| ۱ | ۳ | ۱۳ |
| ۱ | ۲ | ۳ |
این جدول در شهر انگوتستان به شکل سه فایل *JSON* ذخیره میشود، فایل مربوط به هر سطر، به ترتیب به شکل زیر میشود:
```json
{"1": "3", "2": "1", "3": "4"}
```
```json
{"1": "1", "2": "3", "3": "13"}
```
```json
{"1": "1", "2": "2", "3": "3"}
```
</details>
سجاد که از اهالی قانونشکن شهر انگوتستان میباشد میخواهد برعکس کارهای بالا را انجام دهد و با گرفتن تمامی فایلهای *JSON* مربوط به یک جدول، آن را به صورت یک فایل [*CSV*](https://en.wikipedia.org/wiki/Comma-separated_values) نمایش دهد. او برای این کار، دقیقا برعکس کارهای بالا را انجام میدهد؛ البته چون فقط میخواهد جدول را ذخیره کند از `index` و `header` در *CSV* استفاده نمیکند.
اما او هر جدولی را دوست ندارد و برای این که جدول بهتر شود؛ ابتدا مقادیر مربوط به هر سطر را از کوچک به بزرگ مرتب میکند؛ سپس سطر $i$ام را $i - 1$ بار شیفت دوری میدهد (یعنی سطر اول هیچ تغییری نمیکند)؛ در واقع خانه موجود در سطر $i$ام و ستون $j$ ام مقدار خانه سطر $i$ و ستون
$(i+j - 1) \mod n$
را به خود میگیرد (اگر مقدار عبارت گفته شده برابر با صفر بود، $n$ در نظر گرفته میشود).
<details class="green">
<summary>
مثال عملیات روی جدول
</summary>
برای مثال جدول زیر را در نظر بگیرید:
| ستون اول | ستون دوم | ستون سوم
| :-----------: | :-----------: | :-----------: |
| ۳ | ۱ | ۴ |
| ۱ | ۳ | ۱۳ |
| ۱ | ۲ | ۳ |
اگر سطرهای این جدول را مرتب کنیم به صورت زیر درمیآید:
| ستون اول | ستون دوم | ستون سوم |
| :-----------: | :-----------: | :-----------: |
| ۱ | ۳ | ۴ |
| ۱ | ۳ | ۱۳ |
| ۱ | ۲ | ۳ |
حال اگر هر سطر را با توجه به روش داده شده تغییر دهیم سطر اول تغییری نمیکند؛ ولی سطر دوم، یک شیفت به سمت راست میخود و سطر سوم دو شیفت به سمت راست میخورد و جدول نهایی به شکل زیر درمیآید:
| ستون اول | ستون دوم | ستون سوم |
| :-----------: | :-----------: |:-----------: |
| ۱ | ۳ | ۴ |
| ۳ | ۱۳ | ۱ |
| ۳ | ۱ | ۲ |
بررسی دقیقتر:
```
inputs:
3 1 4
1 3 13
1 2 3
-----------------
sort:
1 3 4
1 3 13
1 2 3
---------------
rotate:
1 3 4 (no rotation)
3 13 1 (one left rotation)
3 1 2 (two left rotation)
```
</details>
حال سجاد از شما میخواهد برایش یک تابع به نام `process` بنویسید که به عنوان ورودی یک لیست از نام فایلهای *JSON* بگیرد (دقت کنید که فایلهای *JSON* در این لیست به ترتیب هستند؛ یعنی فایل مربوط به سطر $i$ در جایگاه $i-1$ در لیست وجود دارد)، و جدول نهایی را در فایلی به نام `ans.csv` ذخیره کند.
تضمین میشود که جدول ورودی داده شده مربعی است و در آن اعداد صحیح قرار دارد.
# پروژه اولیه
پروژه اولیه را از [این لینک](/contest/assignments/21629/download_problem_initial_project/76086/) دانلود کنید. شما باید تابع `process` در فایل `solution.py` را کامل کنید.
# مثال
اگر در کنار فایل `solution.py` فایلهای *JSON* پروژه اولیه وجود داشته باشد، باید خروجی زیر از تابع گرفته شود:
```python
>>> from solution import process
>>> process(['sample1.json', 'sample2.json'])
>>> with open('ans.csv', 'r') as f:
... print(f.readlines())
...
['1,3\n', '3,1\n']
```
# نکات
+ دقت کنید که در جداول مثال، ستون اول، به علت فارسی بودن، سمت راست جدول است و اگر *CSV* را به طور عادی باز کنید باید ترتیب ستونهای جدول برعکس شود و ستون اون در سمت چپ قرار گیرد.
+ توجه کنید که مقادیر را باید به صورت عددی مرتب کنید؛ یعنی عدد ۲ از عدد ۱۷ کوچکتر است (یعنی باید اعداد را هنگام خواندن از فایل به `int` تبدیل کنید).
# آنچه باید آپلود کنید
فایل کامل شده `solution.py` را ارسال کنید؛ همچنین برای استفاده از کتابخانههای مختلف میتوانید همراه فایل ارسالی، فایلی به نام `python_requirements.txt` در *ZIP* خود بگذارید که در آن نام کتابخانههای مورد نیاز و شماره نسخهی آنها به فرمت زیر در آن موجود باشد: (اگر شماره نسخه را ننویسید آخرین نسخهی آن کتابخانه نصب میشود)
```
firstlib==1.2.3
secondlib==4.5.6
...
```
در نهایت یک فایل *ZIP* حاوی دو فایل خواسته شده را آپلود کنید.
پایتون - قانونشکن
به علت شیوع کرونا شرکت *سجادینه* جلسات خود را به صورت مجازی و در وبسایت [جیتسی](https://meet.jit.si) برگزار میکند.
شرکت *سجادینه* شامل تیمهای مختلفیست و هر عضو این شرکت دقیقا در یک تیم عضو میباشد. برای مدیریت بهتر جلسات این شرکت میخواهیم وبسایتی طراحی کنیم تا هر عضو بتواند وارد تیم خود بشود و هر تیم یک لینک مخصوص در [جیتسی](https://meet.jit.si) داشته باشد.
از شما میخواهیم ویوهای این وبسایت را با توجه به ساختار پروژه برای ما طراحی کنید.
# پروژه اولیه
پروژه اولیه را از [این لینک](/contest/assignments/21629/download_problem_initial_project/76087/) دانلود کنید.
ساختار فایلهای این پروژه به صورت زیر است.
<details class="green">
<summary>
مدلها - پیادهسازی شده است
</summary>
### مدل `Team`
این مدل نشاندهندهی تیمها میباشد.
هر تیم شامل دو فیلد زیر میباشد:
+ فیلد `name`: که از نوع *CharField* میباشد و نشاندهندهی نام تیم است.
+ فیلد `jitsi_url_path`: که از نوع *CharField* میباشد و نشاندهنده لینک اختصاصی جیتسی برای آن تیم میباشد.
### مدل `Account`
این مدل از مدل `User` ارثبری میکند و دارای یک فیلد اضافه بر `User` میباشد:
+ فیلد `team`: که از نوع *foreignkey* میباشد و نشاندهندهی شیء تیم مربوط به این فرد میباشد.
</details>
<details class="green">
<summary>
فرمها - پیادهسازی شده است
</summary>
### فرم `SignUpForm`
از این فرم باید در قسمت ثبتنام افراد در سایت استفاده شود.
### فرم `TeamForm`
از این فرم باید برای اضافه کردن یک تیم و یا اضافه شدن به یک تیم استفاده شود.
### فرم `LoginForm`
از این فرم باید برای وارد شدن کاربر به سایت استفاده شود.
</details>
<details class="yellow">
<summary>
ویوها - توسط شما پیادهسازی شود
</summary>
## ویو `home`
به این ویو فقط میتوان ریکوئست `Get` زد و این ویو برای این نوع ریکوئست باید نام تیم کاربر را نشان دهد.
اگر کاربری که به این ویو ریکوئست میزند دارای تیم بود، صفحهی `home.html` را طوری نمایش دهید که در این صفحه، نام تیم این کاربر به نمایش دربیاید.
اگر کاربری که به این ویو ریکوئست میزند تیمی نداشت، صفحهی `home.html` را طوری نمایش دهید که در این صفحه، کلمهی `None` به نمایش دربیاید.
## ویو `signup`
به این ویو میتوان دو نوع ریکوئست `Get` و `Post` زد و کار این ویو ثبتنام کردن کاربر در سایت میباشد.
اگر نوع ریکوئست کاربر `Get` باشد؛ صفحهی `signup.html` را طوری به کاربر نمایش دهید که در این صفحه فرم `SignUpForm` برای کاربر به نمایش دربیاید.
اگر نوع ریکوئست کاربر `Post` باشد؛ بعد از انجام اعتبارسنجی دادههای وارد شده در فرم، اگر فرم به درستی پر شده بود کاربر را در دیتابیس ذخیره کرده و در سایت `login` کنید و کاربر را به آدرس `team` بفرستید؛ اگر هم فرم اشتباه پر شده بود کاربر را دوباره به صفحه `signup` بازگردانید.
## ویو `login_account`
به این ویو میتوان دو نوع ریکوئست `Get` و `Post` زد و کار این ویو وارد کردن کاربر به سایت میباشد.
اگر نوع ریکوئست کاربر `Get` باشد؛ صفحهی `login.html` را طوری به او نمایش دهید که فرم `LoginForm` به نمایش دربیاید.
اگر نوع ریکوئست کاربر `Post` باشد؛ بعد از اعتبارسنجی فرم، اگر کاربر فرم را درست پر کرده بود، بررسی کنید که کاربری با اطلاعات پر شده وجود داشته باشد و اگر وجود داشت کاربر را `login` کنید و او را به صفحهی `home` بفرستید؛ در غیر این صورت او را دوباره به صفحهی `login` بازگردانید.
## ویو `logout_account`
به این ویو فقط میتوان ریکوئست `Get` زد و کار این ویو خارج کردن کاربر از حساب کاربری خود میباشد.
اگر کاربر به این ویو ریکوئست `Get` زد او را از حساب کاربری خود بیرون کنید و به صفحهی `login` منتقل کنید.
## ویو `joinoradd_team`
به این ویو میتوان دو نوع ریکوئست `Get` و `Post` زد.
اگر نوع ریکوئست کاربر `Get` باشد؛ بررسی کنید کاربر در حال حاضر دارای تیم میباشد یا خیر.
اگر کاربر تیمی داشت او را به صفحهی `home` منتقل کنید وگرنه او را طوری به صفحهی `team.html` منتقل کنید که فرم `TeamForm` به او نمایش داده شود.
اگر نوع ریکوئست کاربر `Post` باشد؛ بعد از اعتبارسنجی فرم اگر کاربر فرم را درست پر کرده بود بررسی کنید اگر تیمی با این نام وجود داشت فیلد `team` کاربر را برابر با این تیم قرار دهید؛ و اگر وجود نداشت یک تیم با این نام بسازید. فیلد `jitsi_url_path` این تیم به صورت `http://meet.jit.si/team_name` قرار گیرد که جای `team_name` نام تیم قرار میگیرد. بعد از ساخت تیم فیلد `team` کاربر را برابر با این تیم قرار دهید و کاربر را به صفحهی `home` انتقال دهید.
اگر هم فرم درست پر نشده بود کاربر را به صفحه `home` انتقال دهید.
## ویو `exit_team`
به این ویو فقط میتوان ریکوئست `Get` زد و کار این ویو خارج کردن کاربر از تیم حال حاضر آن میباشد.
اگر کاربر به این ویو ریکوئست `Get` زد فیلد `team` کاربر را برابر با `None` قرار دهید و او را به صفحهی `home` منتقل کنید. اگر هم کاربر از قبل تیمی نداشت صرفا او را به صفحهی `home` منتقل کنید.
</details>
# نکات
+ دقت کنید که تمامی ریدایرکتها را با استفاده از تابع `redirect` انجام دهید.
# آنچه باید آپلود کنید
یک فایل *ZIP* شامل پروژه جنگو خود آپلود کنید؛ توجه کنید که فقط میتوانید فایل `account/views.py` را تغییر دهید.
جنگو - جیتسی
شرکت بورس ع.ش که بعد از کرونا مشتریهای زیادی پیدا کرده، با مشکلات جدیدی روبهرو شده!
زیاد شدن تعداد مشتریهای این شرکت بورس، باعث جلب توجه تعدادی از خرابکاران اینترنتی شده. این خرابکارها تصمیم گرفتند تا با حملههای **DDoS** به سایت این شرکت، آن را از دسترس خارج کنند و تنها به ازای گرفتن پولی هنگفت! از رئیس شرکت، دست از حمله بر میدارند.
شما باید به مدیر شرکت ع.ش کمک کنید تا با کمترین هزینه و با کمک دانش ملی و بومی! جلوی حملات این خرابکاران را بگیرد.
# پروژه اولیه
پروژه اولیه را از [این لینک](/contest/assignments/21629/download_problem_initial_project/76085/) دانلود کنید. ساختار فایلهای این پروژه به صورت زیر است:
<details class="brown">
<summary>
ساختار فایلها
</summary>
```
boors-va-corona
├── apps
│ ├── guard
│ │ ├── admin.py
│ │ ├── apps.py
│ │ ├── __init__.py
│ │ ├── management
│ │ │ ├── commands
│ │ │ │ ├── init_guard.py
│ │ │ │ └── __init__.py
│ │ │ └── __init__.py
│ │ ├── middlewares.py
│ │ ├── migrations
│ │ ├── models.py
│ │ ├── urls.py
│ │ ├── utils.py
│ │ └── views.py
│ ├── __init__.py
│ └── market
│ ├── admin.py
│ ├── apps.py
│ ├── __init__.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── codecup
│ ├── asgi.py
│ ├── __init__.py
│ ├── settings
│ │ ├── base.py
│ │ ├── development.py
│ │ ├── __init__.py
│ │ └── production.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── codecupdb.sqlite3
├── deploy
│ └── nginx
│ └── default.conf
├── docker-compose.yml
├── Dockerfile
├── manage.py
├── README.md
└── requirements.txt
```
</details>
<details class="brown">
<summary>راهاندازی پروژه</summary>
برای اجرای پروژه ابتدا باید تمام کتابخانههای مورد نیاز را با استفاده از دستور زیر اجرا کنید:
```
> pip install -r requirements.txt
```
برای اجرای خود پروژه هم میتوانید از دستور زیر استفاده کنید:
```
> python manage.py runserver
```
</details>
فایلهایی که شما باید در این پروژه تکمیل کنید همگی در اپ `guard` قرار دارند. نام این فایلها به صورت زیر است:
`middlewares.py`
`admin.py`
`models.py`
`init_guard.py`
<details class="green">
<summary>
فایل `models.py`
</summary>
در این فایل تمام مدلهای مورد نیاز برای پروژه از قبل تعریف شدهاند. در زیر به توضیح هر کدام از این مدلها میپردازیم:
### مدل `BlockedIp`
این مدل برای ذخیره کد آیپیها مسدود شده می باشد. این مدل یک فیلد `ban_time` دارد که اگر از زمان ساخت یک نمونه از این مدل، به مقدار `ban_time` بگذرد، آیپی موردنظر از حالت مسدود خارج میشود. توجه کنید که واحد `ban_time` به ثانیه است.
شما تنها کافیست دو متد `is_blocked` و `is_ip_blocked` را کامل کنید. متد `is_blocked` یک مقدار بولین برمیگرداند که آیا هنوز یک شئ `BlockedIp` معتبر هست یا نه. اگر معتبر بود مقدار `True` و اگر زمان `ban_time` به طور کامل گذشته باشد مقدار `False` برمیگرداند. متد `is_ip_blocked` نیز یک آیپی به عنوان ورودی گرفته و یک مقدار بولین برمیگرداند که نشان میدهد آیپی داده شده مسدود شده است یا نه.
همچنین دو مدل دیگر در این فایل قرار دارد که نباید در آنها تغییری ایجاد کنید.
### مدل `ViewDetail`
این مدل برای ذخیره کردن تمام ویوهای موجود در پروژه استفاده میشود. یعنی تمام ویوها به همراه *URL* شان را در ابتدای اجرا کردن پروژه، تعریف میکنیم و به دیتابیس اضافه میکنیم. با این کار به راحتی میتوانیم بفهمیم که هر آیپی با ریکوئست زدن به کدام ویو و *URL* مسدود شده است.
### مدل `SecurityConfig`
از این مدل نیز تنها یک نمونه ساخته میشود که در ابتدای اجرا کردن پروژه باید تعریف شود و دیگر تغییری نکند.
در این مدل میتوان لیست ویوهایی که میخواهیم از حمله مهاجامان در امان بماند را مشخص کرد.
</details>
<details class="green">
<summary>
فایل `init_guard.py`
</summary>
در این فایل باید یک دستور برای جنگو بنویسید که بتواند مقادیر اولیهی موردنیاز برای مدلهای `ViewDetail` و `SecurityConfig` را در صورتی که از قبل ساخته نشده باشند را بسازد و در دیتابیس قرار دهد.
</details>
<details class="green">
<summary>
فایل `admin.py`
</summary>
در این فایل نیز باید تنظیمات ادمین مربوط به مدلهای گفته شده در بالا را انجام دهید. نیازمندیهای ما به شکل زیر است:
+ لیست اشیاء `BlockedIp` را بتوان بر حسب فیلد `view` فیلتر کرد.
+ در لیست اشیاء `BlockedIp`، بتوان بر حسب آیپی، نام ویو و *URL* ویو جست و جو کرد.
+ برای قسمت ادمین `SecurityConfig`، اجازه ساختن و حذف کردن شئ جدید را به ادمینهای سایت ندهیم.
+ برای قسمت ادمین `ViewDetail`، اجازه ساختن، حذف کردن و تغییر دادن شئ را به ادمینهای سایت ندهیم.
</details>
<details class="green">
<summary>
فایل `middlewares.py`
</summary>
در این قسمت باید مهمترین عنصر این ماژول امنیتی جدید را پیاده کنید. یک *middleware* که مقدار ریکوئست بر ثانیه را برای هر ریکوئست محاسبه میکند و اگر این مقدار از حداکثر مقدار ممکن، یعنی ۴ ریکوئست بر ثانیه، بیشتر باشد، آیپی کاربر را مسدود میکند. در این میدلور باید بررسی شود که اگر آیپی کسی که ریکوئست زده است، قبلا مسدود شده بود (`banned_before`)، یک ریسپانس با کد ۴۰۳ برگرداند؛ همچنین در این میدلور برای ذخیره کردن ریکوئستهای هر کاربر، از کش جنگو با زمان ماندگاری (*timeout*) ۶۰ثانیه استفاده میشود نه دیتابیس، تا سرعت پاسخگویی به ریکوئستها خیلی تحت تاثیر قرار نگیرد.
هم چنین در متد `validate_request_per_second` باید دادههای مربوط به آیپی ریکوئست زننده که در کش ذخیره شده، بررسی و تعداد ریکوئستها بر ثانیهی آن محاسبه شود. اگر این مقدار بیشتر از ۴ ریکوئست بر ثانیه بود، آن وقت آیپی موردنظر را در لیست سیاه قرار داده و ریسپانسی با کد ۴۲۹ برگردانده شود.
</details>
حالا با اطلاعاتی که آقای رئیس به شما داده، کمکهایتان را برای ما آپلود کنید!
# آنچه باید آپلود کنید
یک فایل *ZIP* شامل پروژه جنگو خود آپلود کنید؛ توجه کنید که فقط میتوانید ۴ فایل گفته شده در بالا را تغییر دهید.
جنگو - بورس و کرونا
ساکنان کشور دوبستان علاقهای به رعایت پروتکلهای بهداشتی از خود نشان نمیدهند، برای همین مسئولین این کشور تصمیم به اجرای یک سامانه گرفتهاند. هدف اصلی این سامانه پیدا کردن افرادیست که بدیهیترین پروتکل بهداشتی را رعایت نمیکنند و هدف بعدی آن اطلاعرسانی اخبار از طریق پیامک است.
در این کشور عجیب فقط بیمارستانها و شرکتها وجود دارند. ساکنانش هم مثل کشورشان عجیباند؛ با اینکه پروتکلها را رعایت نمیکنند ولی از مریضی به شدت میترسند، برای همین برای هر مسئلهای به بیمارستان مراجعه میکنند.
برای اجرای این سامانه مدیران بیمارستانها و شرکتها همکاری خود را اعلام کردهاند. این سامانه چند کار را انجام میدهد:
1. با گرفتن اسم بیمارستان، افرادی را که در این بیمارستان بستری هستند، کرونا دارند و در شرکتی کار میکنند را برمیگرداند.
2. با گرفتن اسم شرکت، کارمندانی که بهخاطر کرونا به بیمارستان مراجعه کرده بودهاندرا بر میگرداند.
3. این سامانه برای اطلاعرسانی از سرویس `sms` استفاده میکند. لیستی از کد ملی اشخاص دریافت میکند و با استفاده از کد ملی شماره تلفنشان را پیدا کرده و برای آنها`sms` میفرستد. (در این شهر هر کد ملی به یک شماره تلفن اختصاص و هر شماره تلفن به یک کد ملی اختصاص داده شده است.)
# پروژه اولیه
پروژه اولیه را از [این لینک](/contest/assignments/21629/download_problem_initial_project/76088/) دانلود کنید.
ساختار فایلهای این پروژه به صورت زیر است.
<details class="green">
<summary>
دیتابیسها - پیادهسازی شده است
</summary>
## دیتابیسها
### دیتابیس `default`
در این دیتابیس قرار است گزارشهای مربوط به `sms`های داده شده ذخیره شود.
### دیتابیس `hospitals`
در این دیتابیس اطلاعات راجعبه بیمارستانها و مریضهای مربوط به هر بیمارستان را داریم.
### دیتابیس `companies`
در این دیتابیس اطلاعات راجع به شرکتها و کارمندهای مربوط به هر شرکت را داریم.
</details>
<details class="green">
<summary>
مدلها - پیادهسازی شده است
</summary>
## مدلها
### مدل `DeliveryReport`
این مدل فقط شامل یک فیلد میباشد:
فیلد `phone_number` : شمارهی شهروندی که به او از طریق این سرویس `sms` داده شده در آن ذخیره میشود. این فیلد از نوع `CharField` میباشد.
این مدل مربوط به دیتابیس `default` میباشد.
### مدل `Hospital`
این مدل شامل سه فیلد میباشد:
فیلد `name`: نشاندهندهی نام بیمارستان میباشد و `unique` است. این فیلد از نوع `CharField` میباشد.
فیلد `manager_name`: نشاندهندهی نام مدیر بیمارستان است. این فیلد از نوع `CharField` میباشد.
فیلد `manager_id`: نشاندهندهی کد ملی مدیر بیمارستان است. این فیلد از نوع `CharField` میباشد.
این مدل مربوط به دیتابیس `hospitals` میباشد.
### مدل `Company`
این مدل شامل سه فیلد میباشد:
فیلد `name`: نشاندهندهی نام شرکت میباشد و `unique` است. این فیلد از نوع `CharField` میباشد.
فیلد `manager_name`: نشاندهندهی نام مدیر شرکت است. این فیلد از نوع `CharField` میباشد.
فیلد `manager_id`: نشاندهندهی کد ملی مدیر شرکت است. این فیلد از نوع `CharField` میباشد.
این مدل مربوط به دیتابیس `companies` میباشد.
### مدل `Sick`
این مدل شامل چهار فیلد میباشد:
فیلد `name`: نشاندهندهی نام بیمار است. این فیلد از نوع `CharField` میباشد.
فیلد `nationalID`: نشاندهندهی کدملی بیمار است. این فیلد از نوع `CharField` میباشد
فیلد `illName`: نشاندهندهی نام بیماری بیمار مورد نظر است. این فیلد از نوع `CharField` میباشد.
فیلد `hospital`: نشاندهندهی بیمارستانیست که این بیمار در آن بستری شده است. این فیلد از نوع `ForeignKey` به مدل `hospital` میباشد.
این مدل مربوط به دیتابیس `hospital` میباشد.
### مدل `employee`
این مدل شامل سه فیلد میباشد:
فیلد `name`: نشاندهندهی نام کارمند است. این فیلد از نوع `CharField` میباشد.
فیلد `nationalID`: نشاندهندهی کد ملی کارمند است. این فیلد از نوع `CharField` میباشد.
فیلد `company`: نشاندهندهی شرکتیست که این کارمند در آن کار میکند. این فیلد از نوع `ForeignKey` به مدل `company` میباشد.
این مدل مربوط به دیتابیس `companies` میباشد.
</details>
<details class="yellow">
<summary>
ویوها - توسط شما پیادهسازی میشود
</summary>
## ویوها
### ویو `get_sick_employee_by_hospital`
این ویو یک `request` میپذیرد که از نوع `POST` میباشد.
در `request` اسم بیمارستان به صورت `json` داده میشود. (`NameSerializer` سریالایزر مربوط به این ریکوئست میباشد.) به عنوان `response` یک دیکشنری داده میشود؛ به این صورت که در قسمت `key` اعداد ۱ تا n قرار دارند و در قسمت `value` یک رشته به صورت زیر ذخیره میشود:
"(name, nationalID)"
در واقع نام و کد ملی شخصیست که به آن بیمارستان برای کرونا مراجعه کرده و کارمند است.
دقت کنید که اهمیتی ندارد کدام `value` به کدام `key` نسبت داده شده است.
کسانی که کرونا دارند فیلد `illName` آنها به صورت `Covid19` ذخیره شده است.
### ویو `get_sick_employee_by_company`
این ویو یک `request` میپذیرد که از نوع `POST` میباشد.
در `request` اسم شرکت به صورت `json` داده میشود. (`NameSerializer` سریالایزر مربوط به این ریکوئست میباشد.) به عنوان `response` یک دیکشنری داده میشود؛ به این صورت که در قسمت `key` اعداد ۱ تا n قرار دارد و در قسمت `value` یک **رشته** به این صورت ذخیره میشود:
`(name, nationalID)`(دقت کنید که این **رشته** است و نه تاپل.)
در واقع نام و کدملی شخصیست که در آن شرکت کار میکند و برای کرونا به بیمارستان مراجعه کرده است.
دقت کنید که اهمیتی ندارد کدام `value` به کدام `key` نسبت داده شده است.
کسانی که کرونا دارند فیلد `illName` آنها به صورت `Covid19` ذخیره شده است.
### ویو `sms_link`
این ویو یک `request` میپذیرد که از نوع `POST` میباشد.
در `request` کد ملی کسانی که قرار است برای آنها *sms* فرستاده شود به صورت `json` داده میشود.(`NationalIDSerializer` سریالایزر مربوط به این ریکوئست میباشد.)
در فایل `SMS.py` دو تابع داریم:
تابع `sms`: به عنوان ورودی یک شماره تلفن میگیرد(*phone_number*) و برای آن `sms` میفرستد.
تابع `get_phone_number`: به عنوان ورودی کد ملی میگیرد(*number*) و به عنوان خروجی شماره تلفن اختصاص داده شده به آن را میدهد.
ویو `sms_link` با استفاده از توابع فایل `SMS.py` برای شمارههای اختصاص داده شده به کدهای ملی دریافتی *sms* میفرستد و در دیتابیس به ازای هر *sms* فرستاده شده، یک شیء`DeliveryReport` با شمارهی شخص را ذخیره میکند.
دقت کنید که تابع `sms` از نوع `async` میباشد.
در نهایت به عنوان `response` کد استاتوس ۲۰۰ برگردانده میشود..
</details>
<details class="yellow">
<summary>
فایل روتر - توسط شما پیاده میشود
</summary>
### فایل `db_Router.py`
در این فایل دو کلاس مربوط به لیست `DATABASE_ROUTERS` (تعریف شده در `settings.py`) باید توسط شما پیادهسازی شود.
</details>
# نکات
+ توجه کنید که اگر هر `request` مشکلی داشته باشد، ویوی مربوط به آن باید کداستاتوس ۴۰۰ را برگرداند.
+ هر کد ملی برای یک نفر است.
+ شما فقط مجاز به تغییر دادن فایلهای `views.py` و `db_Router.py` هستید. باقی تغییرات در سیستم داوری نادیده گرفته میشود.
# آنچه باید آپلود کنید
یک فایل *ZIP* شامل پروژه جنگو خود آپلود کنید.