سلیب که تمام بازیها را با باخت پشت سر گذاشته بود، بیخیال بازی کردن شد. او از خانه بیرون رفت تا به دنبال سرگرمی جدیدی باشد که ناگاه ردپای سجاد را بر روی زمین دید. او به دنبال آن ردپا رفت و در نهایت توانست یک شرکت جدید تاسیس کند.
شرکت سلیب از همان ابتدا برای خود هدفی پیدا کرد. این شرکت میخواهد برای خود سایتی راهاندازی کند تا بتواند مشتریهای بیشتری را جذب کند. به همین دلیل از علی و کیانوش در این راستا تقاضای کمک کرده است.
آنها هم چون در برنامهنویسی تازهکارند از شما درخواست کردهاند که این پروژه را برایشان پیادهسازی کنید.
برای این پروژه ما نیاز به پیادهسازی کلاسهای Account و Site داریم.
کلاس Account
Accountهر شی این کلاس دارای پنج ویژگی ($Attribute$) است که در تابع ــinitــ مقداردهی میشود و به ازای هر شیء مقدار آن فرق دارد:
۱. یوزرنیم username
usernameیوزرنیم کاربر باید به فرمت (نام + آندر لاین + نام خانوادگی) ذخیره شود. توجه کنید که نام و نام خانوادگی فقط باید از حروف انگلیسی باشند.
در صورتی که یوزرنیم دریافتی مانند فرمت بالا نبود باید یک $Exception$ با متن اررور invalid username raise کنید.
مثال:
- اگر یوزرنیم برابر با  
ali_babaeiبود مشکلی ندارد. - اما اگر یوزرنیم برابر با  
kianoush_nasr_azadaniبود باید $Exception$ خواسته شده را raise کنید. 
۲. پسورد password
passwordپسورد کاربر باید دارای نکات زیر باشد:
- طول آن حداقل ۸ کاراکتر باشد.
 - حتما شامل یک حرف بزرگ، یک حرف کوچک، یک عدد باشد.
 - باید حتما به صورت هش(
hash) با فرمتsha256وencodeutf-8ذخیره شود. در صورتی که پسورد دریافتی مانند فرمت بالا نبود باید یک $Exception$ با متن اررورinvalid passwordraise کنید. 
مثال:
- اگر پسورد برابر با  
Aa123123بود مشکلی ندارد و صحیح است. - ولیکن اگر پسورد برابر با 
Aa12312AA123123aa123123valid نیست. 
۳. کد ملّی user_id
user_idکدملّی کاربر باید اعتبار سنجی شود
الگوریتم اعتبارسنجی کد ملی:
کد ملی شمارهای است ۱۰ رقمی که از سمت چپ سه رقم کد شهرستان محل صدور شناسنامه، شش رقم بعدی کد منحصربهفرد برای فرد دارندهی شناسنامه در شهرستان محل صدور و رقم آخر آن هم یک رقم کنترل است که از روی ۹ رقم سمت چپ بهدست میآید. برای بررسی کنترل کد کافیست مجدد از روی ۹ رقم سمت چپ رقم کنترل را محاسبه کنیم

۱- برای محاسبهی رقم کنترل از روی سایر ارقام، هر رقم را در موقعیت آن ضرب کرده و حاصل را با هم جمع میکنیم.
۲- مجموع بهدست آمده از مرحله یک را بر ۱۱ تقسیم میکنیم.
۳- اگر باقیمانده کمتر از ۲ باشد، رقم کنترل باید برابر باقیمانده باشد در غیر اینصورت رقم کنترل باید برابر یازده منهای باقیمانده باشد.
مثال : آیا کد ۷۷۳۱۶۸۹۹۵۱ یک کد ملی معتبر است؟

حاصل جمع ضرب ارقام ۲ الی ۱۰ را در موقعیت آنها محاسبه میکنیم:
۱۰+۲۷+۳۶+۴۰+۳۶+۷+۲۴+۶۳+۷۰ = ۳۱۳
باقیمانده تقسیم ۳۱۳ بر ۱۱ = ۵
چون باقیمانده برابر با ۵ و بزرگتر یا مساوی ۲ است پس باید رقم کنترل این کد برابر ۶(یازده منهای پنج برابر است با شش)باشد.
در صورتی که کدملّی دریافتی مانند فرمت بالا نبود باید یک $Exception$ با متن اررور invalid code melli raise کنید.
مثال:
- اگر کدملّی برابر با  
0024848484بود مشکلی نداشته و valid است. - ولیکن اگر کد ملی برابر با 
0024848483valid نیست. 
۴. شماره موبایل phone
phoneشماره تلفن کاربر ممکن است به دو فرمت به شما داده شود:
۱- +989xxxxxxxxx
۲- 09xxxxxxxxx
اگر شماره صحیح بود در هر حالتی شما باید آن را به صورت 09xxxxxxxxx ذخیره کنید،
و در صورتی که شماره موبایل دریافتی مانند فرمت بالا نبود باید یک $Exception$ با متن اررور invalid phone number raise کنید.
مثال:
- اگر شمارهی موبایل برابر با 
09121212121باشد مشکلی ندارد. - ولیکن اگر شمارهی موبایل برابر با 
08121212121,0912121212,+988121212121,+98912121212باشد valid نیست. 
۵. ایمیل email
emailتضمین میشود ایمیل ورودی به فرمت First_Part@Second_Part.Third_Part به شما داده میشود.
ایمیل کاربر باید صحیح باشد، ایمیلی را صحیح مینامیم اگر و فقط اگر:
First_PartوSecond_Partتنها شامل حروف بزرگ و کوچک، اعداد،_،-،.باشد و تضمین میشود نیازی به چک کردن محدودیت طولی بخش اول و دوم ندارید.Third_Partباید تنها شامل حروف بزرگ و کوچک باشد و طولی میان ۲ تا ۵ کاراکتر داشته باشد.
در صورتی که ایمیل دریافتی مانند فرمت بالا نبود باید یک $Exception$ با متن اررور invalid email raise کنید.
دکوراتورها
تابع show_welcome
show_welcomeاین تابع بر اساس آنچه به عنوان کد اولیه پیادهسازی شده است شما باید آن را به نحوی پیادهسازی کنید که در ابتدا نام کاربری شخص (username) را که شامل آندرلاین است را برداشته و به جای آن space قرار داده و حروف اول آن را به صورت capital (بزرگ) بنویسد.؛
اگر طول این کلمه بیشتر از ۱۵ کاراکتر باشد (به همراه کاراکتر فاصله) هم ادامه آن را حذف کرده و به آخر آن ... قرار دهد و در آخر تابع welcome فراخوانی کند.
مثال:
>> print(user.username)
> kianoush_nasr
>> print(user2.username)
> salib_alibabaeei
>> welcome(user)
> welcome to our site Kianoush Nasr
>> welcome(user2)
> welcome to our site Salib Alibabaee...
تابع verify_change_password
verify_change_passwordاین تابع به عنوان کد اولیه پیادهسازی شده است و شما تنها نیاز است که اگر پسورد قبلی شما با old_password یکسان بود پسورد جدید را برای user قرار دهد و در آخر تابع change_password را فراخوانی کند.
توجه
- پسورد در هنگام تغییر یا در حالت set کردن باید به صورت هش شده ذخیره گردد.
 - کلاس یوزر باید دارای تابعی به نام 
set_new_passwordباشد که پسورد یوزر را عوض میکند(در این مرحله نیز باید چک کنید پسورد جدید دارای نکات گفته شده باشد و اگر بود باید آن را به صورت هش ذخیره کنید) 
کلاس Site
Siteهر شی این کلاس دارای سه ویژگی ($Attribute$) است که در تابع ــinitــ مقداردهی میشود و به ازای هر شیء مقدار آن فرق دارد:
۱. آدرس سایت url
تضمین میشود آدرس سایت صحیحی به شما داده میشود و نیازی به چک کردن آن ندارید.
۲. افراد ثبت نام شده register_users
در هنگام ساخت شیء این مقدار را برابر با یک لیست خالی قرار دهید.
۳. افراد فعال در سایت active_users
در هنگام ساخت شیء این مقدار را برابر با یک لیست خالی قرار دهید.
جزئیات
تابع register
registerکلاس سایت باید دارای تابعی به نام register باشد. این تابع یک شیء از کلاس یوزر ورودی میگیرد و اگر آن یوزر در register_users خود سایت بود یک $Exception$ با متن ارور user already registered raise کنید وگرنه آن را به لیست register_users خود سایت بیفزایید و عبارت register successful را برگردانید.
توجه کنید که لیست register_users باید به ترتیب ثبتنام کاربران، آنها را در خود ذخیره کند.
تابع login
loginکلاس سایت باید دارای تابعی به نام login باشد. این تابع ورودیهای متفاوتی میگیرد:
۱- ممکن است email و username و password به آن داده شود. در این حالت شما باید چک کنید یوزری در register_users سایت وجود دارد که هم یوزرنیم و هم ایمیلی برابر با ورودی داشته باشد و پسوردش برابر با هش شدهی پسورد ورودی باشد یا خیر.
۲- ممکن است username و password به آن داده شود. در این حالت شما باید چک کنید یوزری در register_users سایت وجود دارد که یوزرنیمی برابر با ورودی داشته باشد و پسوردش برابر با هش شدهی پسورد ورودی باشد یا خیر.
۳- ممکن است email و password به آن داده شود. در این حالت شما باید چک کنید یوزری در register_users سایت وجود دارد که ایمیلی برابر با ورودی داشته باشد و پسوردش برابر با هش شدهی پسورد ورودی باشد یا خیر.
- باید با توجه به اینکه ورودی تابع از کدام نوع است لاگین(login) را با اطلاعات ورودی تطبیق دهید.
 - اگر کاربری در هرکدام از حالات بالا یافت شد باید آن شیء یوزر را به لیست 
active_usersاضافه کنید و عبارتlogin successfulرا برگردانید. - اگر در هر کدام از حالات قبل از تطبیق اطلاعات یوزر در لیست 
active_usersموجود بود باید عبارتuser already logged inرا برگردانید. - اگر اطلاعات ورودی برای هیچکدام از کاربرهای 
register_usersنبودند باید عبارتinvalid loginرا برگردانید. 
توجه کنید که لیست active_users باید به ترتیب ورود کاربران، آنها را در خود ذخیره کند.
تابع logout
logoutکلاس سایت باید دارای تابعی به نام logout باشد. این تابع یک شیء از کلاس یوزر ورودی میگیرد و اگر آن یوزر در active_users خود سایت بود آن را از لیست حذف کرده و عبارت logout successful را برگردانید و در صورت عدم وجود آن یوزر در active_users سایت عبارت user is not logged in را برگردانید.
نکات
- میتوانید فایل اولیه این سوال را از این لینک دریافت کنید.
 - شما میتوانید با پیادهسازی این سوال به صورت بخشبخش نمره بگیرید.
 - برای ارسال باید یک فایل پایتون ارسال کنید که در آن تابع 
AccountوSiteو دکوراتورها به شکل گفته شده وجود داشته باشد. 
نحوه ارسال
شما باید کلاسهای Account و Site موجود در فایل source.py را تکمیل و سپس این فایل را ارسال کنید.
ارسال پاسخ برای این سؤال