✨ Realm list
This commit is contained in:
		| @@ -1,5 +1,13 @@ | |||||||
| package models | package models | ||||||
|  |  | ||||||
|  | type RealmType = int | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	RealmTypePublic = RealmType(iota) | ||||||
|  | 	RealmTypeRestricted | ||||||
|  | 	RealmTypePrivate | ||||||
|  | ) | ||||||
|  |  | ||||||
| type Realm struct { | type Realm struct { | ||||||
| 	BaseModel | 	BaseModel | ||||||
|  |  | ||||||
| @@ -8,7 +16,7 @@ type Realm struct { | |||||||
| 	Articles    []Article     `json:"article"` | 	Articles    []Article     `json:"article"` | ||||||
| 	Moments     []Moment      `json:"moments"` | 	Moments     []Moment      `json:"moments"` | ||||||
| 	Members     []RealmMember `json:"members"` | 	Members     []RealmMember `json:"members"` | ||||||
| 	IsPublic    bool          `json:"is_public"` | 	RealmType   RealmType     `json:"realm_type"` | ||||||
| 	AccountID   uint          `json:"account_id"` | 	AccountID   uint          `json:"account_id"` | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -60,14 +60,14 @@ func createRealm(c *fiber.Ctx) error { | |||||||
| 	var data struct { | 	var data struct { | ||||||
| 		Name        string `json:"name" validate:"required"` | 		Name        string `json:"name" validate:"required"` | ||||||
| 		Description string `json:"description"` | 		Description string `json:"description"` | ||||||
| 		IsPublic    bool   `json:"is_public"` | 		RealmType   int    `json:"realm_type"` | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err := BindAndValidate(c, &data); err != nil { | 	if err := BindAndValidate(c, &data); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	realm, err := services.NewRealm(user, data.Name, data.Description, data.IsPublic) | 	realm, err := services.NewRealm(user, data.Name, data.Description, data.RealmType) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fiber.NewError(fiber.StatusBadRequest, err.Error()) | 		return fiber.NewError(fiber.StatusBadRequest, err.Error()) | ||||||
| 	} | 	} | ||||||
| @@ -150,7 +150,7 @@ func editRealm(c *fiber.Ctx) error { | |||||||
| 	var data struct { | 	var data struct { | ||||||
| 		Name        string `json:"name" validate:"required"` | 		Name        string `json:"name" validate:"required"` | ||||||
| 		Description string `json:"description"` | 		Description string `json:"description"` | ||||||
| 		IsPublic    bool   `json:"is_public"` | 		RealmType   int    `json:"realm_type"` | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err := BindAndValidate(c, &data); err != nil { | 	if err := BindAndValidate(c, &data); err != nil { | ||||||
| @@ -165,7 +165,7 @@ func editRealm(c *fiber.Ctx) error { | |||||||
| 		return fiber.NewError(fiber.StatusNotFound, err.Error()) | 		return fiber.NewError(fiber.StatusNotFound, err.Error()) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	realm, err := services.EditRealm(realm, data.Name, data.Description, data.IsPublic) | 	realm, err := services.EditRealm(realm, data.Name, data.Description, data.RealmType) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return fiber.NewError(fiber.StatusBadRequest, err.Error()) | 		return fiber.NewError(fiber.StatusBadRequest, err.Error()) | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -274,7 +274,7 @@ func NewPost[T models.PostInterface](item T) (T, error) { | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if item.GetRealm() != nil { | 	if item.GetRealm() != nil { | ||||||
| 		if !item.GetRealm().IsPublic { | 		if item.GetRealm().RealmType != models.RealmTypePublic { | ||||||
| 			var member models.RealmMember | 			var member models.RealmMember | ||||||
| 			if err := database.C.Where(&models.RealmMember{ | 			if err := database.C.Where(&models.RealmMember{ | ||||||
| 				RealmID:   item.GetRealm().ID, | 				RealmID:   item.GetRealm().ID, | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ func ListRealmIsAvailable(user models.Account) ([]models.Realm, error) { | |||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	if err := database.C.Where(&models.Realm{ | 	if err := database.C.Where(&models.Realm{ | ||||||
| 		IsPublic: true, | 		RealmType: models.RealmTypePublic, | ||||||
| 	}).Or("id IN ?", idx).Find(&realms).Error; err != nil { | 	}).Or("id IN ?", idx).Find(&realms).Error; err != nil { | ||||||
| 		return realms, err | 		return realms, err | ||||||
| 	} | 	} | ||||||
| @@ -46,12 +46,12 @@ func ListRealmIsAvailable(user models.Account) ([]models.Realm, error) { | |||||||
| 	return realms, nil | 	return realms, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func NewRealm(user models.Account, name, description string, isPublic bool) (models.Realm, error) { | func NewRealm(user models.Account, name, description string, realmType int) (models.Realm, error) { | ||||||
| 	realm := models.Realm{ | 	realm := models.Realm{ | ||||||
| 		Name:        name, | 		Name:        name, | ||||||
| 		Description: description, | 		Description: description, | ||||||
| 		AccountID:   user.ID, | 		AccountID:   user.ID, | ||||||
| 		IsPublic:    isPublic, | 		RealmType:   realmType, | ||||||
| 		Members: []models.RealmMember{ | 		Members: []models.RealmMember{ | ||||||
| 			{AccountID: user.ID}, | 			{AccountID: user.ID}, | ||||||
| 		}, | 		}, | ||||||
| @@ -86,10 +86,10 @@ func KickRealmMember(user models.Account, target models.Realm) error { | |||||||
| 	return database.C.Delete(&member).Error | 	return database.C.Delete(&member).Error | ||||||
| } | } | ||||||
|  |  | ||||||
| func EditRealm(realm models.Realm, name, description string, isPublic bool) (models.Realm, error) { | func EditRealm(realm models.Realm, name, description string, realmType int) (models.Realm, error) { | ||||||
| 	realm.Name = name | 	realm.Name = name | ||||||
| 	realm.Description = description | 	realm.Description = description | ||||||
| 	realm.IsPublic = isPublic | 	realm.RealmType = realmType | ||||||
|  |  | ||||||
| 	err := database.C.Save(&realm).Error | 	err := database.C.Save(&realm).Error | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| <html lang="en"> | <html lang="en"> | ||||||
|   <head> |   <head> | ||||||
|     <meta charset="UTF-8"> |     <meta charset="UTF-8"> | ||||||
|     <link rel="icon" type="image/xml+svg" href="/favicon.svg"> |     <link rel="icon" type="image/xml+svg" href="/favicon.png"> | ||||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> |     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||||
|     <title>Solarplaza</title> |     <title>Solarplaza</title> | ||||||
|   </head> |   </head> | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								pkg/views/public/favicon.png
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								pkg/views/public/favicon.png
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 68 KiB | 
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| Before Width: | Height: | Size: 51 KiB | 
							
								
								
									
										116
									
								
								pkg/views/src/components/realms/RealmList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								pkg/views/src/components/realms/RealmList.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | |||||||
|  | <template> | ||||||
|  |   <v-list density="comfortable"> | ||||||
|  |     <v-list-subheader>Realms</v-list-subheader> | ||||||
|  |     <v-list-item v-for="item in realms" prepend-icon="mdi-account-multiple" :title="item.name" /> | ||||||
|  |  | ||||||
|  |     <v-divider v-if="realms.length > 0" class="border-opacity-75 my-2" /> | ||||||
|  |  | ||||||
|  |     <v-list-item | ||||||
|  |       prepend-icon="mdi-plus" | ||||||
|  |       title="Create a realm" | ||||||
|  |       :disabled="!id.userinfo.isLoggedIn" | ||||||
|  |       @click="creating = true" | ||||||
|  |     /> | ||||||
|  |   </v-list> | ||||||
|  |  | ||||||
|  |   <v-dialog v-model="creating" class="max-w-[540px]"> | ||||||
|  |     <v-card title="Create a realm" prepend-icon="mdi-account-multiple-plus" :loading="loading"> | ||||||
|  |       <v-form @submit.prevent="submit"> | ||||||
|  |         <v-card-text> | ||||||
|  |           <v-text-field | ||||||
|  |             label="Name" | ||||||
|  |             variant="outlined" | ||||||
|  |             density="comfortable" | ||||||
|  |             v-model="requestData.name" | ||||||
|  |           /> | ||||||
|  |           <v-textarea | ||||||
|  |             label="Description" | ||||||
|  |             variant="outlined" | ||||||
|  |             density="comfortable" | ||||||
|  |             v-model="requestData.description" | ||||||
|  |           /> | ||||||
|  |           <v-select | ||||||
|  |             label="Realm type" | ||||||
|  |             item-title="label" | ||||||
|  |             item-value="value" | ||||||
|  |             variant="outlined" | ||||||
|  |             density="comfortable" | ||||||
|  |             :items="realmTypeOptions" | ||||||
|  |             v-model="requestData.realm_type" | ||||||
|  |           /> | ||||||
|  |         </v-card-text> | ||||||
|  |         <v-card-actions> | ||||||
|  |           <v-spacer></v-spacer> | ||||||
|  |  | ||||||
|  |           <v-btn type="reset" color="grey-darken-3" @click="creating = false">Cancel</v-btn> | ||||||
|  |           <v-btn type="submit" :disabled="loading">Save</v-btn> | ||||||
|  |         </v-card-actions> | ||||||
|  |       </v-form> | ||||||
|  |     </v-card> | ||||||
|  |   </v-dialog> | ||||||
|  |  | ||||||
|  |   <!-- @vue-ignore --> | ||||||
|  |   <v-snackbar v-model="error" :timeout="5000">Something went wrong... {{ error }}</v-snackbar> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import { ref } from "vue"; | ||||||
|  | import { getAtk, useUserinfo } from "@/stores/userinfo"; | ||||||
|  |  | ||||||
|  | const id = useUserinfo(); | ||||||
|  |  | ||||||
|  | const realms = ref<any[]>([]); | ||||||
|  | const requestData = ref({ | ||||||
|  |   name: "", | ||||||
|  |   description: "", | ||||||
|  |   realm_type: 0 | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const realmTypeOptions = [ | ||||||
|  |   { label: "Public Realm", value: 0 }, | ||||||
|  |   { label: "Restricted Realm", value: 1 }, | ||||||
|  |   { label: "Private Realm", value: 2 } | ||||||
|  | ]; | ||||||
|  |  | ||||||
|  | const creating = ref(false); | ||||||
|  |  | ||||||
|  | const error = ref<string | null>(null); | ||||||
|  | const reverting = ref(false); | ||||||
|  | const loading = ref(false); | ||||||
|  |  | ||||||
|  | async function list() { | ||||||
|  |   reverting.value = true; | ||||||
|  |   const res = await fetch("/api/realms/me/available", { | ||||||
|  |     headers: { Authorization: `Bearer ${getAtk()}` } | ||||||
|  |   }); | ||||||
|  |   if (res.status !== 200) { | ||||||
|  |     error.value = await res.text(); | ||||||
|  |   } else { | ||||||
|  |     realms.value = await res.json(); | ||||||
|  |   } | ||||||
|  |   reverting.value = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | async function submit(evt: SubmitEvent) { | ||||||
|  |   const form = evt.target as HTMLFormElement; | ||||||
|  |   const payload = requestData.value; | ||||||
|  |   if (!payload.name) return; | ||||||
|  |  | ||||||
|  |   loading.value = true; | ||||||
|  |   const res = await fetch("/api/realms", { | ||||||
|  |     method: "POST", | ||||||
|  |     headers: { "Content-Type": "application/json", Authorization: `Bearer ${getAtk()}` }, | ||||||
|  |     body: JSON.stringify(payload) | ||||||
|  |   }); | ||||||
|  |   if (res.status !== 200) { | ||||||
|  |     error.value = await res.text(); | ||||||
|  |   } else { | ||||||
|  |     await list(); | ||||||
|  |     form.reset(); | ||||||
|  |     creating.value = false; | ||||||
|  |   } | ||||||
|  |   loading.value = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | list(); | ||||||
|  | </script> | ||||||
| @@ -1,7 +1,7 @@ | |||||||
| <template> | <template> | ||||||
|   <v-navigation-drawer v-model="drawerOpen" color="grey-lighten-5" floating> |   <v-navigation-drawer v-model="drawerOpen" color="grey-lighten-5" floating> | ||||||
|     <div class="flex flex-col h-full"> |     <div class="flex flex-col h-full"> | ||||||
|       <v-list> |       <v-list class="border-b border-opacity-15 h-[64px]" style="border-bottom-width: thin"> | ||||||
|         <v-list-item :subtitle="username" :title="nickname"> |         <v-list-item :subtitle="username" :title="nickname"> | ||||||
|           <template #prepend> |           <template #prepend> | ||||||
|             <v-avatar icon="mdi-account-circle" :image="id.userinfo.data?.avatar" /> |             <v-avatar icon="mdi-account-circle" :image="id.userinfo.data?.avatar" /> | ||||||
| @@ -27,7 +27,9 @@ | |||||||
|         </v-list-item> |         </v-list-item> | ||||||
|       </v-list> |       </v-list> | ||||||
|  |  | ||||||
|       <v-list density="compact" class="flex-grow-1" nav> </v-list> |       <div class="flex-grow-1"> | ||||||
|  |         <realm-list /> | ||||||
|  |       </div> | ||||||
|  |  | ||||||
|       <div> |       <div> | ||||||
|         <v-alert type="info" variant="tonal" class="text-sm"> |         <v-alert type="info" variant="tonal" class="text-sm"> | ||||||
| @@ -95,6 +97,7 @@ import { useEditor } from "@/stores/editor" | |||||||
| import { useUserinfo } from "@/stores/userinfo" | import { useUserinfo } from "@/stores/userinfo" | ||||||
| import { useWellKnown } from "@/stores/wellKnown" | import { useWellKnown } from "@/stores/wellKnown" | ||||||
| import PostAction from "@/components/publish/PostAction.vue" | import PostAction from "@/components/publish/PostAction.vue" | ||||||
|  | import RealmList from "@/components/realms/RealmList.vue"; | ||||||
|  |  | ||||||
| const id = useUserinfo() | const id = useUserinfo() | ||||||
| const editor = useEditor() | const editor = useEditor() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user