بعد از تقویمهای جلالی، میلادی و کلندرهای مجازی که گوگل و سایر شرکتها ارائه میدهند؛ ما در کوئرا به فکر طراحی تقویم خودمان افتادهایم. و وظیفهی آن به *اون یکی همکارمون* در شرکت محول شده.
از شما میخواهیم این پروژه را طبق معمول کوئرا برای *اون یکی همکارمون* پیادهسازی کنید.
# جزئیات پروژه
پروژهی اولیه را از [این لینک](/contest/assignments/54145/download_problem_initial_project/183358/) دانلود کنید. در این پروژه شما باید قسمتهای مشخصشده با `// TODO` را پیادهسازی کنید.
## جداول
ساختار `struct`هایی که جداول شما رو میسازند باید به شکل زیر باشد:
1- `User`
| نام ستون | نوع | ملاحظات |
|:------------------:|:------------------:|:-----------:|
| `gorm.Model` | `struct` |`PRIMARY KEY AUTO_INCREMENT`|
| `Username` |`string` | نام کاربری |
| `FirstName` | `string` | نام |
| `LastName` | `string` | نام خانوادگی |
2- `Calendar`
| نام ستون | نوع | ملاحظات |
|:------------------:|:------------------:|:-----------:|
| `gorm.Model` | `struct` |`PRIMARY KEY AUTO_INCREMENT`|
| `Name` |`string` | نام تقویم |
| `UserID` | `uint` | کلید خارجی به جدول `users` و ستون `id` |
3- `Appointment`
| نام ستون | نوع | ملاحظات |
|:------------------:|:------------------:|:-----------:|
| `gorm.Model` | `struct` |`PRIMARY KEY AUTO_INCREMENT`|
| `Subject` |`string` | موضوع ملاقات |
| `Description` | `string` | توضیحات ملاقات |
| `StartTime` | `time.Time` | زمان شروع ملاقات |
| `Length` | `uint` | مدت زمان ملاقات |
| `OwnerID` | `uint` | آیدی دارنده ملاقات |
| `OwnerType` | `string` | تایپ کلاس دارنده ملاقات |
4- `TaskList`
| نام ستون | نوع | ملاحظات |
|:------------------:|:------------------:|:-----------:|
| `gorm.Model` | `struct` |`PRIMARY KEY AUTO_INCREMENT`|
جهت اطلاعات بیشتر در مورد `gorm.Model` میتوانید به [این لینک](https://gorm.io/docs/models.html#gorm-Model) مراجعه نمایید.
## روابط
در ادامه شما باید به پیادهسازی روابط بین مدلها بپردازید که ارتباطات بین مدلها باید بهصورت زیر باشد:
+ هر کاربر یک تقویم دارد و هر تقویم متعلق به یک کاربر است.
+ هر کاربر میتواند چند وقتملاقات داشته باشد و هر وقتملاقات هم میتواند چند کاربر داشته باشد.(از طریق جدول `appointment_user`)
+ هر تقویم میتواند چند وقتملاقات داشته باشد.
+ هر فهرستوظیفه میتواند چند وقتملاقات داشته باشد.
+ هر وقتملاقات متعلق به یک تقویم یا فهرستوظیفه است.
## توابع
شما باید بدنه توابع زیر را به شکلی مطلوب تکمیل نمایید.
### تابع `RefreshDatabase`
این تابع با دریافت آبجکتی از نوع `*gorm.DB` و لیستی از جداول، ابتدا باید آنها را حذف کند و سپس آنها را طبق آخرین تغییرات بر اساس استراکتهای مربوطه بسازد. در صورت موفقیتآمیز بودن عملیات باید `Refresh database successfully done` به عنوان رشته برگردانده شود به همره `nil` و اگر خطایی در طی فرآیند رخ داد باید رشته خالی به همراه ارور مربوطه برگردانده شود.
امضای تابع به شکل زیر است:
```go
func RefreshDatabase(db *gorm.DB, tables []interface{}) (string, error){
// TODO: Implement
}
```
### تابع `SeedUser`
این تابع باید به صورت *Seeder* عمل کند و با دریافت پارامترهای لازم یک کاربر با تقویم و لیست ملاقاتهای مربوطه بسازد و در جدول ذخیره کند و در صورت موفقیتآمیز بودن عملیات پیام `Seeding database successfully done` را چاپ کند و در غیر این صورت ارور را به همراه یک رشته خالی برگرداند.
امضای تابع به شکل زیر است:
```go
func SeedUser(db *gorm.DB, username, firstName, lastName, calendarName, appointmentSubject string, startDate time.Time) (string, error) {
// TODO: Implement
}
```
### تابع `updateAppointment`
این تابع باید به تمام وقتملاقاتهایی که اسم تقویم آنها برابر با `calendarName`، زمان شروع آنها بین `startTime` و `endTime` و موضوع رویداد، شامل `keyword` باشد یک ساعت به زمان شروع ملاقاتها اضافه کند و به انتهای توضیحات آنها هم ` event` (یک فاصله و بعد *event*) را اضافه کند و در جدول ذخیره نماید در غیر این صورت ارور مربوطه را برگرداند.
امضای تابع به شکل زیر است:
```go
func updateAppointment(db *gorm.DB, calendarName string, startTime time.Time, endTime time.Time, keyword string) error {
// TODO: Implement
}
```
### اسکوپ `UserWithRangeAppointment`
این اسکوپ باید تمام کاربرانی که زمان شروع ملاقات آنها بین `startDate` و `endDate` است، موضوع ملاقات آنها برابر `subject` است و اسم تقویم آنها برابر `calendarTableName` را برگرداند.
امضای اسکوپ به شکل زیر است:
```go
func UserWithRangeAppointment(startDate, endDate time.Time, subject string, calendarTableName string) func(db *gorm.DB) *gorm.DB {
// TODO: Implement
}
```
# نکات
+ دقت کنید که قسمتهای مختلف سوال با هم مرتبط هستند و در صورت **صحیح نبودن جداول و روابط بین آنها** ممکن است **تستهای بعدی هم پاس نشوند**!
+ شما در این سوال باید از [GORM](https://gorm.io/) و امکانات آن استفاده کنید.
+ فایل `db.go` جهت اتصال *GORM* با دیتابیس است که در آن از دیزانپترن *singleton* استفاده شده و شما نیازی به تغییر آن ندارید و صرفا ثابتهای آن را جهت اجرا در محیط لوکال خود میتوانید تغییر دهید. فرض کنید سمت سرور نیز این فایل به درستی و مطابق دیتابیس سرور وجود دارد.
# آنچه باید آپلود کنید
پس از پیادهسازی موارد خواسته شده، فایل `main.go` را که شامل تمام موارد گفته شده در بالا است آپلود کنید.