model

package
v0.0.0-...-bef4ad1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 28, 2022 License: MIT Imports: 6 Imported by: 0

README

设计手册

directory

// file: directory.go
// DirectoryInfo 目录信息
type DirectoryInfo struct {
	Description string `json:"description,omitempty" example:"course materials" bson:"description,omitempty"`
	Cover       string `json:"cover,omitempty" example:"https://www.motwo.cn/cover" bson:"cover,omitempty"`
}

// Directory 目录
type Directory struct {
	ID       primitive.ObjectID   `json:"id,omitempty" example:"xxxxxxxxxxxxxx==" bson:"_id,omitempty"`
	ParentID primitive.ObjectID   `json:"parent_id,omitempty" example:"xxxxxxxxxxxxxx==" bson:"parent_id,omitempty"`
	Name     string               `json:"name,omitempty" example:"records" bson:"name,omitempty"`
	Info     DirectoryInfo        `json:"info,omitempty" bson:"info,omitempty"`
	OwnerIDs []primitive.ObjectID `json:"owner_ids,omitempty"  bson:"owner_ids,omitempty"`
}
字段含义
  • ParentID:父目录的id
  • Name:名称
  • OwnerIDs:归属者的id列表,用于访问控制
设计思路

需要层级目录的对象都可以复用,比如收藏夹,群组共享等
将应用于不同对象的数据存放在不同的表中,下面均以第一个实现的category为例:

  1. 首先,用户初始化category功能,生成一个category的对象(定义名称为root
    • parent_id为创建用户id
    • 此时的ownerIDs也添加用户id
  2. 若为category新增子category,对子归档(subCategory)进行修改:
    • parent_id为父category的id
    • 此时的ownerIDs也添加用户id

这种设计的优势有:

  • 易得某目录c的子目录s(c.ID==s.ParentID)
  • 易得子目录s的父目录p(p.ID==s.ParentID)
  • 易得某用户u的根目录r(u.ID==r.ParentID)
  • 易得某用户u的所有目录cs(u.ID in cs.OwnerIDs)
api设计

由于新增了归档这一实体,其内部之间的关系、归档与博客之间的关系、归档与用户之间的关系都需要设定与查询。 与此相类,之后复用目录结构的实体也将面对这一需求,因此,设计泛化通用的api势在必行
遵循REST API的设计理念,将api的路径对应相应资源,方法代表操作,于是引入以下实体:

dto/directory.go
// file: dto/directory.go

// RelateEntity2Entity 将单实体关联到单实体dto
type RelateEntity2Entity struct {
	RelatedID  primitive.ObjectID `json:"related_id,omitempty"`
	RelateToID primitive.ObjectID `json:"relateTo_id,omitempty"`
}

// RelateEntitySet2EntitySet 关联两个实体集dto
type RelateEntitySet2EntitySet struct {
	RelatedIDs  []primitive.ObjectID `json:"related_ids,omitempty"`
	RelateToIDs []primitive.ObjectID `json:"relateTo_ids,omitempty"`
}

// RelateEntity2EntitySet 关联单实体到多实体集dto
type RelateEntity2EntitySet struct {
	RelatedID   primitive.ObjectID   `json:"related_id,omitempty"`
	RelateToIDs []primitive.ObjectID `json:"relateTo_ids,omitempty"`
}

// RelateEntitySet2Entity 关联实体集到单实体dto
type RelateEntitySet2Entity struct {
	RelatedIDs []primitive.ObjectID `json:"related_ids,omitempty"`
	RelateToID primitive.ObjectID   `json:"relateTo_id,omitempty"`
}

分别对应实现:

  • 将单实体关联到单实体
  • 关联两个实体集
  • 关联单实体到多实体集
  • 关联实体集到单实体
api使用

controller.go

    api := middleware.H.Group("/api")
    {
    	//...
        relation := api.Group("relation", model.OrdinaryUser)
        {
            relation.Post("categories/:type", c.RelateCategories2Entity)
            relation.Post("category/:type", c.RelateCategory2Entity)
            relation.Get("category/:type/:ID", c.FindCategoriesByType)
        }
        //...
    }
       
  • 未实现前加(x)
  • 基础

    • 访问控制未完善
    • api/blog/category [post]
      • upsert增改category信息
    • api/blog/category [get]
      • 查询category信息
    • api/directories/category [delete] (important)
      • 删除category信息
      • 解除与该category相关的所有联系:blog字段寻找相关字段并删去
  • relation部分

    • categories
      • 多对一

        • api/relation/categories/:type [post]
          • 建立categories与type之间的联系,目前可选:
          • category:将多实体集categories的父categoryid均设为单实体的id
          • blog:将多实体集categories的ids添加到blog的categories列表中去
      • (x)多对多

    • category
      • 一对一
        • api/relation/category/:type [post]
          • 建立category与type之间的联系,目前可选:
          • user:将user的id添加到category的ownerIDs列表中
          • userMain:将user的id设定为category的parent_id
          • category:将related id的parent_id设定为relateTo的category的id
          • blog:将category的id添加到blog的categories列表中去
      • 一对一/多
        • api/relation/category/:type/:id [get]
          • 获取categories与type之间的联系,目前可选:
          • user:将多实体集categories的父categoryid均设为单实体的id
          • sub:将多实体集categories添加到blog的categories列表中去
新增部分
  • 若upsert中的id为零值,初始化id
  • 若parentID为零值,寻找此次请求用户的根目录rootid,亦即ownerIDs的最末一位
    • root不存在,则为该用户新建root,并返回新建root的id
    • root存在,则返回已有root的id
    • 返回id作为本次新增directory的parentID
删除部分

因为删除某directory涉及到冗余关联数据的删除,因此需要:

  • 对blog端:删除所有blog中categories列表里的相关id即可
  • 对category端:所有删除category(dCat)的子category加入到其上一级(id=dCat.parent_id)中
  • 增加鉴权,只有操作用户id in owner_ids匹配成功的可以进行删除操作
    • 新思路,增加过滤器,在请求的id列表中过滤出可以进行操作的id列表

BLOG

API
删除部分
  • UPDATE: 3.15
    添加回收站规则 需要新增/修改api 新增表示删除(回收recycle)时间
  • api/blog [delete]

  • 彻底删除文章

  • api/blog/{operation}/{id} [put]
    *[operation]:

    • recycle:加入回收站
      • 新增关于本blog/draft的recycleBin信息
      • 且isDeleted字段置为true状态
    • restore:从回收站还原
      • 将recycleBin中关于本blog/draft的信息进行删除
      • 且isDeleted字段恢复为false状态

    *[id]:被操作对象的id

recycleItem

为定时清空回收站,新建一个表,用来记录所有需要延时删除的对象,分别记录:

  • 删除对象ID
  • 加入删除列表时间
  • 预计删除时间
  • 删除方法
    这样删除工作可统一通过遍历此表进行
// RecycleItem 回收站中的对象信息,记录加入回收站时间和预计被删除时间,以及处理函数
type RecycleItem struct {
	ID         primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
	ItemID     primitive.ObjectID `json:"item_id,omitempty" bson:"item_id,omitempty"`
	CreateTime time.Time          `json:"create_time,omitempty" example:"2020-10-1" bson:"create_time,omitempty"`
	DeleteTime time.Time          `json:"delete_time,omitempty" example:"2020-10-1" bson:"delete_time,omitempty"`
	Handler    string             `json:"handler,omitempty" example:"blog" bson:"handler,omitempty"`
}

group

群组功能允许:

  • 创建群组
  • 邀请成员
  • 管理成员权限
  • 创建群组共享文章

想法是这样的,把群组视为一个权限过滤器。那么文章的authorId设置为群组的id,也就是权限过滤器的id

(突然感觉这个想法不错,可以抽象出一个权限过滤器的类,这样需要有处理权限功能的事务都可复用)
但这个权限管理器与设计的abac的关系是怎么样的呢?是否能够完全交给abac实现?

aha,accessFilter 可以实现RuleType的接口

type RuleType interface {
	JudgeRule() (bool, error)
	ProcessContext(ctx ContextType)
}

那么判断一个用户有权访问某项资源为:

  • 判断用户的id是否是authorID
  • 判断用户是否通过资源的权限过滤器

权限管理器可以注册不同用户的在该资源中的身份:admin/read/write

群组中文章

需要将群组的id加入到blog的ownerID中

是否有必要把一个群组的分离?不若直接把filter作为群组的部分,减少查询次数

Documentation

Index

Constants

View Source
const (
	Token    = "token"
	Avatar   = "avatar"
	IsActive = "isActive"
	True     = "true"
	False    = "false"
)

User info consts

View Source
const (
	HandlerDraft = "draft"
	HandlerBlog  = "blog"
)

最好与collection名称保持一致!

Variables

View Source
var (
	ErrNameInvalid     = errors.New("name is empty")
	ErrEmailInvalid    = errors.New("email is empty")
	ErrPasswordInvalid = errors.New("password is invalid")
)

example

View Source
var IndexModels = []mongo.IndexModel{
	{Keys: bson.M{"entity_info.create_time": -1}},
	{Keys: bson.M{"entity_info.update_time": -1}},
	{Keys: bson.M{"entity_info.isdeleted": 1}},
}

IndexModels Index Models to index entity

Functions

func AddRoles

func AddRoles(a *Account, roles ...Erole)

AddRoles add roles to an account, should never add dup role

func IsTimeValid

func IsTimeValid(time2 time.Time) (valid bool)

Judge whether time exists

Types

type AccessManager

type AccessManager struct {
	EntityInfo Entity                          `json:"entityInfo,omitempty" bson:"entity_info,omitempty"`
	RoleMap    map[string][]primitive.ObjectID `json:"role_map,omitempty" example:"'admin':xxxxx 'write':xxxxx" bson:"role_map,omitempty"`
}

type Account

type Account struct {
	ID         primitive.ObjectID `json:"id,omitempty" example:"xxxxxxxxxxxxx==" bson:"_id,omitempty"`
	UserName   string             `json:"userName" example:"account name" bson:"username,omitempty"`
	Email      string             `json:"email" example:"email@qq.com" bson:"email,omitempty"`
	HashedPwd  string             `json:"hashedPassword" example:"$2a$10$rXMPcOyfgdU6y5n3pkYQAukc3avJE9CLsx1v0Kn99GKV1NpREvN2i" bson:"hashedpwd,omitempty"`
	EntityInfo Entity             `json:"entityInfo,omitempty" bson:"entity_info,omitempty"`
	Roles      []Erole            `json:"roles" bson:"roles"`
	Infos      map[string]string  `json:"infos" example:"'token': 'xxxxxxxx'(private data)" bson:"infos,omitempty"`
	Settings   map[string]string  `` /* 127-byte string literal not displayed */
}

Account example

func (Account) IsValid

func (a Account) IsValid() (valid bool)

IsValid check if user is valid (by id)

type AddAccount

type AddAccount struct {
	UserName string `json:"userName" example:"account name"`
	Email    string `json:"email" example:"email@mo2.com"`
	Password string `json:"password" example:"p@ssword"`
}

AddAccount example

func (AddAccount) Validation

func (a AddAccount) Validation() error

Validation example

type AddAccountRole

type AddAccountRole struct {
	ID       primitive.ObjectID `json:"id" example:"xxxxxxxxxxxxx==" `
	Roles    []Erole            `json:"roles"`
	SuperKey string             `json:"super_key" example:"special"`
}

AddAccountRole example

func (AddAccountRole) Validation

func (a AddAccountRole) Validation() error

Validation example

type Blog

type Blog struct {
	ID          primitive.ObjectID   `json:"id,omitempty" example:"xxxxxxxxxxxxx==" bson:"_id,omitempty"`
	AuthorID    primitive.ObjectID   `json:"authorId,omitempty" example:"xxxxxxxxxxxxx==" bson:"author_id"`
	Title       string               `json:"title,omitempty" example:"mouse ❤ monkey" bson:"title,omitempty"`
	Description string               `json:"description,omitempty" example:"mouse ❤ monkey" bson:"description,omitempty"`
	Content     string               `json:"content,omitempty" example:"xxxx\nxxxx" bson:"content,omitempty"`
	EntityInfo  Entity               `json:"entityInfo,omitempty" bson:"entity_info,omitempty"`
	Cover       string               `json:"cover,omitempty" example:"https://xxx/xxx" bson:"cover,omitempty"`
	KeyWords    []string             `json:"keyWords,omitempty" example:"xxx,xxx" bson:"key_words,omitempty"`
	CategoryIDs []primitive.ObjectID `json:"categories,omitempty" bson:"categories,omitempty"`
	YDoc        string               `json:"y_doc,omitempty" bson:"y_doc,omitempty"`       // 用于collaboration
	IsYDoc      bool                 `json:"is_y_doc,omitempty" bson:"is_y_doc,omitempty"` // 用于collaboration
	YToken      primitive.ObjectID   `json:"y_token,omitempty" bson:"y_token,omitempty"`   //用于collaboration
	ScoreSum    float64              `json:"score_sum" bson:"score_sum,omitempty"`
	ScoreNum    int                  `json:"score_num" bson:"score_num,omitempty"`
	ProjectID   primitive.ObjectID   `json:"project_id" bson:"project_id"`
	CoAuthorIDs []primitive.ObjectID `json:"coauthors,omitempty" bson:"coauthors"`
}

Blog example 若修改字段,需注意依赖此model的使用地方 important: dto.QueryBlog UpsertBlog()

func (*Blog) Add2Categories

func (b *Blog) Add2Categories(categoryIDs []primitive.ObjectID)

func (*Blog) Add2Category

func (b *Blog) Add2Category(categoryID primitive.ObjectID)

func (*Blog) Init

func (b *Blog) Init()

func (*Blog) IsValid

func (b *Blog) IsValid() (valid bool)

type Comment

type Comment struct {
	ID         primitive.ObjectID `json:"id,omitempty" example:"xxxxxxxxxxxxxx==" bson:"_id,omitempty"`
	Content    string             `json:"content,omitempty" example:"a comment" bson:"content,omitempty"`
	EntityInfo Entity             `json:"entity_info,omitempty" bson:"entity_info,omitempty"`
	Praise     Praiseable         `json:"praise,omitempty" bson:"praise,omitempty"`
	Author     primitive.ObjectID `json:"aurhor,omitempty" bson:"aurhor,omitempty"`
	Article    primitive.ObjectID `json:"article,omitempty" bson:"article,omitempty"`
	Subs       []Subcomment       `json:"subs" bson:"subs"`
}

Comment a comment

type DeleteAccount

type DeleteAccount struct {
	Email    string `json:"email" example:"email@mo2.com"`
	Password string `json:"password" example:"p@ssword"`
}

DeleteAccount example

type Directory

type Directory struct {
	ID       primitive.ObjectID   `json:"id,omitempty" example:"xxxxxxxxxxxxxx==" bson:"_id,omitempty"`
	ParentID primitive.ObjectID   `json:"parent_id,omitempty" example:"xxxxxxxxxxxxxx==" bson:"parent_id,omitempty"`
	Name     string               `json:"name,omitempty" example:"records" bson:"name,omitempty"`
	Info     DirectoryInfo        `json:"info,omitempty" bson:"info,omitempty"`
	OwnerIDs []primitive.ObjectID `json:"owner_ids"  bson:"owner_ids,omitempty"`
}

Directory 归档

func (*Directory) Init

func (c *Directory) Init()

func (*Directory) InitWithName

func (c *Directory) InitWithName(name string)

func (*Directory) InitWithNameAndParent

func (c *Directory) InitWithNameAndParent(name string, parentId primitive.ObjectID)

func (*Directory) IsValid

func (c *Directory) IsValid() (valid bool)

func (*Directory) UpdateName

func (c *Directory) UpdateName(name string)

func (*Directory) UpdateParent

func (c *Directory) UpdateParent(parent Directory)

UpdateParent 以父目录更新当前目录

func (*Directory) UpdateParentId

func (c *Directory) UpdateParentId(id primitive.ObjectID)

type DirectoryInfo

type DirectoryInfo struct {
	Description string `json:"description,omitempty" example:"course materials" bson:"description,omitempty"`
	Cover       string `json:"cover,omitempty" example:"https://www.motwo.cn/cover" bson:"cover,omitempty"`
}

DirectoryInfo 归档信息

type Entity

type Entity struct {
	CreateTime time.Time `json:"createTime" example:"2020-10-1" bson:"create_time,omitempty"`
	UpdateTime time.Time `json:"updateTime" example:"2020-10-1" bson:"update_time,omitempty"`
	IsDeleted  bool      `json:"is_deleted,omitempty" example:"true" bson:"isdeleted"`
}

Entity example

func InitEntity

func InitEntity() Entity

InitEntity init new entity

func (*Entity) Create

func (e *Entity) Create()

Create create entity

func (*Entity) Set

func (e *Entity) Set(createTime time.Time)

Set set entity with exist create time

func (*Entity) Update

func (e *Entity) Update()

Update update entity

type Erole

type Erole = string

Erole is mo2 role type

const (
	GeneralAdmin Erole = "GeneralAdmin"
	OrdinaryUser Erole = "OrdinaryUser"
	Anonymous    Erole = "Anonymous"
)

Roles

type Filter

type Filter struct {
	IsDraft   bool `json:"is_draft" example:"false"`
	IsDeleted bool `json:"is_deleted" example:"false"`
	Page      int  `json:"page"`
	PageSize  int  `json:"page_size"`
	Ids       []primitive.ObjectID
}

type Group

type Group struct {
	ID            primitive.ObjectID `json:"id" bson:"id"`
	OwnerID       primitive.ObjectID `json:"owner_id" bson:"owner_id"`
	AccessManager AccessManager      `json:"access_manager,omitempty" bson:"access_manager,omitempty"`
}

type LoginAccount

type LoginAccount struct {
	UserNameOrEmail string `json:"userNameOrEmail" example:"account name/email@mo2.com"`
	Password        string `json:"password" example:"p@ssword"`
}

LoginAccount example

func (LoginAccount) Validation

func (a LoginAccount) Validation() error

Validation is for LoginAccount Validation

type Praiseable

type Praiseable struct {
	Up       uint64 `json:"up" bson:"up"`
	Down     uint64 `json:"down" bson:"down"`
	Weighted uint64 `json:"weighted" bson:"weighted"`
}

Praiseable 可被点赞的

type Project

type Project struct {
	ID          primitive.ObjectID   `bson:"_id,omitempty"`
	Name        string               `bson:"name"`
	Tags        []string             `bson:"tags"`
	OwnerID     primitive.ObjectID   `bson:"owner_id"`
	ManagerIDs  []primitive.ObjectID `bson:"manager_i_ds"`
	MemberIDs   []primitive.ObjectID `bson:"member_i_ds"`
	BlogIDs     []primitive.ObjectID `bson:"blog_i_ds"`
	Description string               `bson:"description"`
	Avatar      string               `bson:"avatar"`
	EntityInfo  Entity               `bson:"entity_info"`
}

type RecycleItem

type RecycleItem struct {
	ID         primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
	ItemID     primitive.ObjectID `json:"item_id,omitempty" bson:"item_id,omitempty"`
	CreateTime time.Time          `json:"create_time,omitempty" example:"2020-10-1" bson:"create_time,omitempty"`
	DeleteTime time.Time          `json:"delete_time,omitempty" example:"2020-10-1" bson:"delete_time,omitempty"`
	Handler    string             `json:"handler,omitempty" example:"blog" bson:"handler,omitempty"`
}

RecycleItem 回收站中的对象信息,记录加入回收站时间和预计被删除时间,以及处理函数

type Subcomment

type Subcomment struct {
	ID         primitive.ObjectID `json:"id,omitempty" example:"xxxxxxxxxxxxxx==" bson:"_id,omitempty"`
	Content    string             `json:"content,omitempty" example:"a comment" bson:"content,omitempty"`
	Aurhor     primitive.ObjectID `json:"aurhor,omitempty" bson:"aurhor,omitempty"`
	EntityInfo Entity             `json:"entity_info,omitempty" bson:"entity_info,omitempty"`
	Praise     Praiseable         `json:"praise,omitempty" bson:"praise,omitempty"`
}

Subcomment level 2 comment

type VerifyEmail

type VerifyEmail struct {
	Email string `json:"Email" example:"email@mo2.com"`
	Token string `json:"token" example:"p@ssword"`
}

VerifyEmail struct for email verify

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL