mirror of
https://github.com/wgh136/nysoure.git
synced 2025-09-27 12:17:24 +00:00
Initial commit
This commit is contained in:
79
server/model/error.go
Normal file
79
server/model/error.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type RequestError struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (e *RequestError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func NewRequestError(message string) *RequestError {
|
||||
return &RequestError{
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
func IsRequestError(err error) bool {
|
||||
var requestError *RequestError
|
||||
ok := errors.As(err, &requestError)
|
||||
return ok
|
||||
}
|
||||
|
||||
type UnAuthorizedError struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (e *UnAuthorizedError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func NewUnAuthorizedError(message string) *UnAuthorizedError {
|
||||
return &UnAuthorizedError{
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
func IsUnAuthorizedError(err error) bool {
|
||||
var unAuthorizedError *UnAuthorizedError
|
||||
ok := errors.As(err, &unAuthorizedError)
|
||||
return ok
|
||||
}
|
||||
|
||||
type NotFoundError struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (e *NotFoundError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func NewNotFoundError(message string) *NotFoundError {
|
||||
return &NotFoundError{
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
func IsNotFoundError(err error) bool {
|
||||
var notFoundError *NotFoundError
|
||||
ok := errors.As(err, ¬FoundError)
|
||||
return ok
|
||||
}
|
||||
|
||||
type InternalServerError struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (e *InternalServerError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func NewInternalServerError(message string) *InternalServerError {
|
||||
return &InternalServerError{
|
||||
Message: message,
|
||||
}
|
||||
}
|
33
server/model/file.go
Normal file
33
server/model/file.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type File struct {
|
||||
gorm.Model
|
||||
Filename string
|
||||
Description string
|
||||
StorageKey string
|
||||
StorageID *uint `gorm:"default:null"`
|
||||
Storage Storage
|
||||
ResourceID uint
|
||||
RedirectUrl string
|
||||
Resource Resource `gorm:"foreignKey:ResourceID"`
|
||||
UserID uint
|
||||
User User `gorm:"foreignKey:UserID"`
|
||||
}
|
||||
|
||||
type FileView struct {
|
||||
ID uint `json:"id"`
|
||||
Filename string `json:"filename"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
func (f *File) ToView() *FileView {
|
||||
return &FileView{
|
||||
ID: f.ID,
|
||||
Filename: f.Filename,
|
||||
Description: f.Description,
|
||||
}
|
||||
}
|
26
server/model/image.go
Normal file
26
server/model/image.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package model
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type Image struct {
|
||||
gorm.Model
|
||||
FileName string
|
||||
Width int
|
||||
Height int
|
||||
// An image can only belong to one resource, or it doesn't belong to any resource and is waiting for usage.
|
||||
Resource []Resource `gorm:"many2many:resource_images;"`
|
||||
}
|
||||
|
||||
type ImageView struct {
|
||||
ID uint `json:"id"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
}
|
||||
|
||||
func (i *Image) ToView() ImageView {
|
||||
return ImageView{
|
||||
ID: i.ID,
|
||||
Width: i.Width,
|
||||
Height: i.Height,
|
||||
}
|
||||
}
|
89
server/model/resource.go
Normal file
89
server/model/resource.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Resource struct {
|
||||
gorm.Model
|
||||
Title string
|
||||
AlternativeTitles []string `gorm:"serializer:json"`
|
||||
Article string
|
||||
Images []Image `gorm:"many2many:resource_images;"`
|
||||
Tags []Tag `gorm:"many2many:resource_tags;"`
|
||||
Files []File `gorm:"foreignKey:ResourceID"`
|
||||
UserID uint
|
||||
User User
|
||||
}
|
||||
|
||||
type ResourceView struct {
|
||||
ID uint `json:"id"`
|
||||
Title string `json:"title"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Tags []TagView `json:"tags"`
|
||||
Image *ImageView `json:"image"`
|
||||
Author UserView `json:"author"`
|
||||
}
|
||||
|
||||
type ResourceDetailView struct {
|
||||
ID uint `json:"id"`
|
||||
Title string `json:"title"`
|
||||
AlternativeTitles []string `json:"alternativeTitles"`
|
||||
Article string `json:"article"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Tags []TagView `json:"tags"`
|
||||
Images []ImageView `json:"images"`
|
||||
Files []FileView `json:"files"`
|
||||
Author UserView `json:"author"`
|
||||
}
|
||||
|
||||
func (r *Resource) ToView() ResourceView {
|
||||
tags := make([]TagView, len(r.Tags))
|
||||
for i, tag := range r.Tags {
|
||||
tags[i] = *tag.ToView()
|
||||
}
|
||||
|
||||
var image *ImageView
|
||||
if len(r.Images) > 0 {
|
||||
v := r.Images[0].ToView()
|
||||
image = &v
|
||||
}
|
||||
|
||||
return ResourceView{
|
||||
ID: r.ID,
|
||||
Title: r.Title,
|
||||
CreatedAt: r.CreatedAt,
|
||||
Tags: tags,
|
||||
Image: image,
|
||||
Author: r.User.ToView(),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Resource) ToDetailView() ResourceDetailView {
|
||||
images := make([]ImageView, len(r.Images))
|
||||
for i, image := range r.Images {
|
||||
images[i] = image.ToView()
|
||||
}
|
||||
tags := make([]TagView, len(r.Tags))
|
||||
for i, tag := range r.Tags {
|
||||
tags[i] = *tag.ToView()
|
||||
}
|
||||
|
||||
files := make([]FileView, len(r.Files))
|
||||
for i, file := range r.Files {
|
||||
files[i] = *file.ToView()
|
||||
}
|
||||
return ResourceDetailView{
|
||||
ID: r.ID,
|
||||
Title: r.Title,
|
||||
AlternativeTitles: r.AlternativeTitles,
|
||||
Article: r.Article,
|
||||
CreatedAt: r.CreatedAt,
|
||||
Tags: tags,
|
||||
Images: images,
|
||||
Files: files,
|
||||
Author: r.User.ToView(),
|
||||
}
|
||||
}
|
14
server/model/response.go
Normal file
14
server/model/response.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package model
|
||||
|
||||
type Response[T any] struct {
|
||||
Success bool `json:"success"`
|
||||
Data T `json:"data,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
type PageResponse[T any] struct {
|
||||
Success bool `json:"success"`
|
||||
TotalPages int `json:"totalPages"`
|
||||
Data []T `json:"data"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
6
server/model/statistic.go
Normal file
6
server/model/statistic.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package model
|
||||
|
||||
type Statistic struct {
|
||||
Key string `gorm:"primaryKey"`
|
||||
Value int64
|
||||
}
|
35
server/model/storage.go
Normal file
35
server/model/storage.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Storage struct {
|
||||
gorm.Model
|
||||
Name string
|
||||
Type string
|
||||
Config string
|
||||
MaxSize int64
|
||||
CurrentSize int64
|
||||
}
|
||||
|
||||
type StorageView struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
MaxSize int64 `json:"maxSize"`
|
||||
CurrentSize int64 `json:"currentSize"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
func (s *Storage) ToView() StorageView {
|
||||
return StorageView{
|
||||
ID: s.ID,
|
||||
Name: s.Name,
|
||||
Type: s.Type,
|
||||
MaxSize: s.MaxSize,
|
||||
CurrentSize: s.CurrentSize,
|
||||
CreatedAt: s.CreatedAt,
|
||||
}
|
||||
}
|
21
server/model/tag.go
Normal file
21
server/model/tag.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package model
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
type Tag struct {
|
||||
gorm.Model
|
||||
Name string `gorm:"unique"`
|
||||
Resources []Resource `gorm:"many2many:resource_tags;"`
|
||||
}
|
||||
|
||||
type TagView struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func (t *Tag) ToView() *TagView {
|
||||
return &TagView{
|
||||
ID: t.ID,
|
||||
Name: t.Name,
|
||||
}
|
||||
}
|
77
server/model/uploading_file.go
Normal file
77
server/model/uploading_file.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"context"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/schema"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type UploadingFile struct {
|
||||
gorm.Model
|
||||
Filename string
|
||||
Description string
|
||||
TargetResourceID uint
|
||||
TargetStorageID uint
|
||||
UserID uint
|
||||
BlockSize int64
|
||||
TotalSize int64
|
||||
Blocks UploadingFileBlocks `gorm:"type:blob"`
|
||||
TempPath string
|
||||
Resource Resource `gorm:"foreignKey:TargetResourceID"`
|
||||
Storage Storage `gorm:"foreignKey:TargetStorageID"`
|
||||
}
|
||||
|
||||
func (uf *UploadingFile) BlocksCount() int {
|
||||
return int((uf.TotalSize + uf.BlockSize - 1) / uf.BlockSize)
|
||||
}
|
||||
|
||||
type UploadingFileBlocks []bool
|
||||
|
||||
func (ufb *UploadingFileBlocks) Scan(ctx context.Context, field *schema.Field, dst reflect.Value, dbValue interface{}) (err error) {
|
||||
data, ok := dbValue.([]byte)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
*ufb = make([]bool, len(data)*8)
|
||||
for i, b := range data {
|
||||
for j := 0; j < 8; j++ {
|
||||
(*ufb)[i*8+j] = (b>>j)&1 == 1
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ufb UploadingFileBlocks) Value(ctx context.Context, field *schema.Field, dbValue reflect.Value) (value interface{}, err error) {
|
||||
data := make([]byte, (len(ufb)+7)/8)
|
||||
for i, b := range ufb {
|
||||
if b {
|
||||
data[i/8] |= 1 << (i % 8)
|
||||
}
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
type UploadingFileView struct {
|
||||
ID uint `json:"id"`
|
||||
Filename string `json:"filename"`
|
||||
Description string `json:"description"`
|
||||
TotalSize int64 `json:"totalSize"`
|
||||
BlockSize int64 `json:"blockSize"`
|
||||
BlocksCount int `json:"blocksCount"`
|
||||
StorageID uint `json:"storageId"`
|
||||
ResourceID uint `json:"resourceId"`
|
||||
}
|
||||
|
||||
func (uf *UploadingFile) ToView() *UploadingFileView {
|
||||
return &UploadingFileView{
|
||||
ID: uf.ID,
|
||||
Filename: uf.Filename,
|
||||
Description: uf.Description,
|
||||
TotalSize: uf.TotalSize,
|
||||
BlockSize: uf.BlockSize,
|
||||
BlocksCount: uf.BlocksCount(),
|
||||
StorageID: uf.TargetStorageID,
|
||||
ResourceID: uf.TargetResourceID,
|
||||
}
|
||||
}
|
49
server/model/user.go
Normal file
49
server/model/user.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gorm.io/gorm"
|
||||
"time"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
gorm.Model
|
||||
Username string
|
||||
PasswordHash []byte
|
||||
IsAdmin bool
|
||||
CanUpload bool
|
||||
AvatarVersion int
|
||||
Resources []Resource `gorm:"foreignKey:UserID"`
|
||||
}
|
||||
|
||||
type UserView struct {
|
||||
ID uint `json:"id"`
|
||||
Username string `json:"username"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
AvatarPath string `json:"avatar_path"`
|
||||
IsAdmin bool `json:"is_admin"`
|
||||
CanUpload bool `json:"can_upload"`
|
||||
}
|
||||
|
||||
type UserViewWithToken struct {
|
||||
UserView
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func (u User) ToView() UserView {
|
||||
return UserView{
|
||||
ID: u.ID,
|
||||
Username: u.Username,
|
||||
CreatedAt: u.CreatedAt,
|
||||
AvatarPath: fmt.Sprintf("/api/user/avatar/%d?v=%d", u.ID, u.AvatarVersion),
|
||||
IsAdmin: u.IsAdmin,
|
||||
CanUpload: u.CanUpload || u.IsAdmin,
|
||||
}
|
||||
}
|
||||
|
||||
func (u UserView) WithToken(token string) UserViewWithToken {
|
||||
return UserViewWithToken{
|
||||
UserView: u,
|
||||
Token: token,
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user