Browse Source

go api 完成

visuddhinanda 4 năm trước cách đây
mục cha
commit
78647e4caa

+ 318 - 74
api/main.go

@@ -1,11 +1,12 @@
 package main
 
 import (
+	"fmt"
+
 	"github.com/gin-gonic/gin"
 	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
 	"github.com/iapt-platform/mint"
-	"fmt"
-    "github.com/go-redis/redis/v8"
 )
 
 func main() {
@@ -18,84 +19,327 @@ func main() {
 	db := pg.Connect(opt)
 	defer db.Close()
 
+	rdb := redis.NewClient(&redis.Options{
+		Addr:     "localhost:6379",
+		Password: "", // no password set
+		DB:       0,  // use default DB
+	})
+
 	rt := gin.Default()
 
-	rdb := redis.NewClient(&redis.Options{
-        Addr:     "localhost:6379",
-        Password: "", // no password set
-        DB:       0,  // use default DB
-    })
-
-
-	// TODO 在这里进行http mount
-
-	rt.GET("/demo/user/:id", mint.GetDemo(db))
-	//rt.POST("/demo/sign-in", mint.LoginDemo(db))
-	rt.POST("/demo/user",mint.PostDemo(db))
-	rt.PUT("/demo/user",mint.PutDemo(db))
-	rt.PATCH("/demo/user/:id",mint.PatchDemo(db))
-	rt.DELETE("/demo/user/:id",mint.DeleteDemo(db))
-
-	//课程
-	//根据id查询课程 
-	rt.GET("/api/course/:cid",mint.GetCourse(db))
-	//输入标题查询符合条件的课程 title% 
-	rt.GET("/api/course/title/:ctitle",mint.GetCourseByTitle(db))
-	//新建课程
-	rt.PUT("/api/course",mint.PutCourse(db)) 
-	//修改
-	rt.POST("/api/course",mint.PostCourse(db))//改
-	//删除
-	rt.DELETE("/api/course/:cid",mint.DeleteCourse(db)) 
-	//修改课程表里的课的数量
-	rt.PATCH("/api/course/lessonnum",mint.PatchLessonNumInCousrse(db))
-
-	//课
-	//根据id查询课程
-	rt.GET("/api/lesson/:lid",mint.GetLesson(db))
-	//输入标题查询符合条件的课程 title% 
-	rt.GET("/api/lesson/title/:ltitle",mint.GetLessonByTitle(db))
-	//新建课
-	rt.PUT("/api/lesson",mint.PutLesson(db)) 
-	//修改
-	rt.POST("/api/lesson",mint.PostLesson(db))//改
-	//删除
-	rt.DELETE("/api/lesson/:lid",mint.DeleteLesson(db)) 
-
-	//文章
-	//根据id查询
-	rt.GET("/api/article/:aid",mint.GetArticle(db,rdb))
-	//输入标题查询符合条件的 title% 
-	rt.GET("/api/article/title/:title",mint.GetArticleByTitle(db))
-	//新建课
-	rt.PUT("/api/article",mint.PutArticle(db))
-	//修改
-	rt.POST("/api/article",mint.PostAritcle(db,rdb))//改
-	//删除
-	rt.DELETE("/api/article/:aid",mint.DeleteArticle(db,rdb))
-
-	//文集
-	//根据id查询
-	rt.GET("/api/collection/:cid",mint.GetCollection(db))
-	//输入标题查询符合条件的 title% 
-	rt.GET("/api/collection/title/:title",mint.GetCollectionByTitle(db))
-	//新建课
-	rt.PUT("/api/collection",mint.PutCollection(db))
-	//修改
-	rt.POST("/api/collection",mint.PostCollection(db))//改
-	//删除
-	rt.DELETE("/api/collection/:cid",mint.DeleteCollection(db))
+	rt.LoadHTMLGlob("templates/**/*")
 
-	//文章列表
-	rt.GET("/api/article_list/collection/:cid",mint.GetCollectionArticleList(db))//改
+	//课程 Courses
+	//display a list of all Courses
+	rt.GET("/api/courses", mint.CoursesIndex(db))
+	//return an HTML form for creating a new Courses
+	rt.GET("/courses/new", mint.CoursesNew(db))
+	//create a new Courses
+	rt.POST("/api/courses", mint.CoursesCreate(db))
+	//display a specific Courses
+	rt.GET("/api/courses/:id", mint.CoursesShow(db, rdb))
+	//return an HTML form for edit a Courses
+	rt.GET("/courses/:id/edit", mint.CoursesEdit(db))
+	//update a specific Courses
+	rt.PUT("/api/courses/:id", mint.CoursesUpdate(db, rdb))
+	//delete a specific Courses
+	rt.DELETE("/api/courses/:id", mint.CoursesDestroy(db, rdb))
+
+	// Articles
+	//display a list of all articles
+	rt.GET("/api/articles", mint.ArticlesIndex(db))
+	//return an HTML form for creating a new articles
+	rt.GET("/api/articles/new", mint.ArticlesNew(db))
+	//create a new articles
+	rt.POST("/api/articles", mint.ArticlesCreate(db))
+	//display a specific articles
+	rt.GET("/api/articles/:id", mint.ArticlesShow(db, rdb))
+	//return an HTML form for edit a articles
+	rt.GET("/api/articles/:id/edit", mint.ArticlesEdit(db))
+	//update a specific articles
+	rt.PUT("/api/articles/:id", mint.ArticlesUpdate(db, rdb))
+	//delete a specific articles
+	rt.DELETE("/api/articles/:id", mint.ArticlesDestroy(db, rdb))
+
+	//Collections
+	//display a list of all collections
+	rt.GET("/api/collections", mint.CollectionsIndex(db))
+	//return an HTML form for creating a new collections
+	rt.GET("/api/collections/new", mint.CollectionsNew(db))
+	//create a new collections
+	rt.POST("/api/collections", mint.CollectionsCreate(db))
+	//display a specific collections
+	rt.GET("/api/collections/:id", mint.CollectionsShow(db))
+	//return an HTML form for edit a collections
+	rt.GET("/api/collections/:id/edit", mint.CollectionsEdit(db))
+	//update a specific collections
+	rt.PUT("/api/collections/:id", mint.CollectionsUpdate(db))
+	//delete a specific collections
+	rt.DELETE("/api/collections/:id", mint.CollectionsDestroy(db))
+
+	//文章列表article_lists
+
+	//rt.GET("/api/article_list/collection/:cid",mint.GetCollectionArticleList(db))//改
 	//修改
-	rt.POST("/api/article_list/article/:aid",mint.PostArticleListByArticle(db))//改
+	//rt.POST("/api/article_list/article/:aid",mint.PostArticleListByArticle(db))//改
+	//rt.DELETE("/api/article_list",mint.DeleteArticleInList(db,rdb))
+	//rt.DELETE("/api/article_list/article/:aid",mint.DeleteArticleInList(db,rdb))
+	//rt.DELETE("/api/article_list/collection/:cid",mint.DeleteCollectionInList(db,rdb))
+	//Collections
+	//display a list of all collections
+	rt.GET("/api/article_list", mint.ArticleListIndex(db))
+	//update a specific collections
+	rt.PUT("/api/article_list/:id", mint.ArticleListUpdate(db))
+
+	//group
+	//display a list of all groups
+	rt.GET("/api/groups", mint.GroupsIndex(db))
+	//return an HTML form for creating a new group
+	rt.GET("/api/groups/new", mint.GroupsNew(db))
+	//create a new group
+	rt.POST("/api/groups", mint.GroupsCreate(db))
+	//display a specific Group
+	rt.GET("/api/groups/:id", mint.GroupsShow(db, rdb))
+	//return an HTML form for edit a group
+	rt.GET("/api/groups/:id/edit", mint.GroupsEdit(db))
+	//update a specific group
+	rt.PUT("/api/groups/:id", mint.GroupsUpdate(db, rdb))
+	//delete a specific group
+	rt.DELETE("/api/groups/:id", mint.GroupsDestroy(db, rdb))
+
+	//groups_users
+	//display a list of all user in group
+	rt.GET("/api/groups_users", mint.GroupsUsersIndex(db))
+	//create a new user in group
+	rt.POST("/api/groups_users", mint.GroupsUsersCreate(db))
+	//delete a specific user in group
+	rt.DELETE("/api/groups_users", mint.GroupsUsersDestroy(db, rdb))
+
+	//channels
+	//display a list of all channel
+	rt.GET("/api/channels", mint.ChannelsIndex(db))
+	//return an HTML form for creating a new group
+	rt.GET("/api/channels/new", mint.ChannelsNew(db))
+	//create a new channels
+	rt.POST("/api/channels", mint.ChannelsCreate(db))
+	//display a specific channels
+	rt.GET("/api/channels/:id", mint.ChannelsShow(db, rdb))
+	//return an HTML form for edit a channels
+	rt.GET("/api/channels/:id/edit", mint.ChannelsEdit(db))
+	//update a specific channels
+	rt.PUT("/api/channels/:id", mint.ChannelsUpdate(db, rdb))
+	//delete a specific channels
+	rt.DELETE("/api/channels/:id", mint.ChannelsDestroy(db, rdb))
+
+	//dictionaries
+	//display a list of all channel
+	rt.GET("/api/dictionaries", mint.DictionariesIndex(db))
+	//return an HTML form for creating a new group
+	rt.GET("/api/dictionaries/new", mint.DictionariesNew(db))
+	//create a new channels
+	rt.POST("/api/dictionaries", mint.DictionariesCreate(db))
+	//display a specific channels
+	rt.GET("/api/dictionaries/:id", mint.DictionariesShow(db, rdb))
+	//return an HTML form for edit a channels
+	rt.GET("/api/dictionaries/:id/edit", mint.DictionariesEdit(db))
+	//update a specific channels
+	rt.PUT("/api/dictionaries/:id", mint.DictionariesUpdate(db, rdb))
+	//delete a specific channels
+	rt.DELETE("/api/dictionaries/:id", mint.DictionariesDestroy(db, rdb))
+
+	//ref_dicts
+	//display a list of all ref_dicts
+	rt.GET("/api/refdicts", mint.RefDictsIndex(db))
+	//display a specific ref_dicts
+	rt.GET("/api/refdicts/:id", mint.RefDictsShow(db, rdb))
+
+	//terms
+	//display a list of all terms
+	rt.GET("/api/terms", mint.TermsIndex(db))
+	//return an HTML form for creating a new terms
+	rt.GET("/api/terms/new", mint.TermsNew(db))
+	//create a new terms
+	rt.POST("/api/terms", mint.TermsCreate(db))
+	//display a specific terms
+	rt.GET("/api/terms/:id", mint.TermsShow(db, rdb))
+	//return an HTML form for edit a terms
+	rt.GET("/api/terms/:id/edit", mint.TermsEdit(db))
+	//update a specific terms
+	rt.PUT("/api/terms/:id", mint.TermsUpdate(db, rdb))
+	//delete a specific terms
+	rt.DELETE("/api/terms/:id", mint.TermsDestroy(db, rdb))
 
+	//active_logs
+	//display a list of all terms
+	rt.GET("/api/active", mint.ActiveIndex(db))
+	//create a new active
+	rt.POST("/api/active", mint.ActiveCreate(db))
 
-	rt.DELETE("/api/article_list",mint.DeleteArticleInList(db,rdb))
-	rt.DELETE("/api/article_list/article/:aid",mint.DeleteArticleInList(db,rdb))
-	rt.DELETE("/api/article_list/collection/:cid",mint.DeleteCollectionInList(db,rdb))
+	//sentences
+	//display a list of all sentences
+	rt.GET("/api/sentences", mint.SentencesIndex(db))
+	//return an HTML form for creating a new sentences
+	rt.GET("/api/sentences/new", mint.SentencesNew(db))
+	//create a new sentences
+	rt.POST("/api/sentences", mint.SentencesCreate(db))
+	//display a specific sentences
+	rt.GET("/api/sentences/:id", mint.SentencesShow(db, rdb))
+	//return an HTML form for edit a sentences
+	rt.GET("/api/sentences/:id/edit", mint.SentencesEdit(db))
+	//update a specific sentences
+	rt.PUT("/api/sentences/:id", mint.SentencesUpdate(db, rdb))
+	//delete a specific sentences
+	rt.DELETE("/api/sentences/:id", mint.SentencesDestroy(db, rdb))
+
+	//sentences_historay
+	//display a list of all sentences
+	rt.GET("/api/senthis", mint.SentencesHistoraiesIndex(db))
+	//create a new group
+	rt.POST("/api/senthis", mint.SentencesHistoraiesCreate(db))
+	//display a specific Group
+	rt.GET("/api/senthis/:id", mint.SentencesHistoraiesShow(db, rdb))
+
+	//authorizations
+	//display a list of all authorizations
+	rt.GET("/api/authorizations", mint.SentencesIndex(db))
+	//return an HTML form for creating a new authorizations
+	rt.GET("/api/authorizations/new", mint.SentencesNew(db))
+	//create a new authorizations
+	rt.POST("/api/authorizations", mint.SentencesCreate(db))
+	//display a specific authorizations
+	rt.GET("/api/authorizations/:id", mint.SentencesShow(db, rdb))
+	//return an HTML form for edit a authorizations
+	rt.GET("/api/authorizations/:id/edit", mint.SentencesEdit(db))
+	//update a specific authorizations
+	rt.PUT("/api/authorizations/:id", mint.SentencesUpdate(db, rdb))
+	//delete a specific authorizations
+	rt.DELETE("/api/authorizations/:id", mint.SentencesDestroy(db, rdb))
+
+	//likes
+	//display a list of all likes
+	rt.GET("/api/likes", mint.LikesIndex(db))
+	//create a new likes
+	rt.POST("/api/likes", mint.LikesCreate(db))
+	//delete a specific likes
+	rt.DELETE("/api/likes/:id", mint.LikesDestroy(db))
+
+	//books
+	//display a list of all books
+	rt.GET("/api/books", mint.BooksIndex(db))
+	//return an HTML form for creating a new group
+	rt.GET("/api/books/new", mint.BooksNew(db))
+	//create a new books
+	rt.POST("/api/books", mint.BooksCreate(db))
+	//display a specific books
+	rt.GET("/api/books/:id", mint.BooksShow(db, rdb))
+	//return an HTML form for edit a books
+	rt.GET("/api/books/:id/edit", mint.BooksEdit(db))
+	//update a specific books
+	rt.PUT("/api/books/:id", mint.BooksUpdate(db, rdb))
+	//delete a specific books
+	rt.DELETE("/api/books/:id", mint.BooksDestroy(db, rdb))
+
+	//pali_text
+	//display a list of all books
+	rt.GET("/api/palitexts", mint.PaliTextsIndex(db))
+
+	//wbw_templates 逐词解析模板
+	//display a list of wbw_templates
+	rt.GET("/api/wbwtemplates", mint.WbwTemplatesIndex(db))
+
+	//wbw_templates
+	//display a list of nissaya_book_maps
+	rt.GET("/api/nissayabookmaps", mint.NissayaBookMapsIndex(db))
+
+	//nissaya_page_maps
+	//display a list of nissaya_page_maps
+	rt.GET("/api/nissayapagemaps", mint.NissayaPageMapsIndex(db))
+
+	//nissaya_page_maps
+	//display a list of multi_edition_page_numbers
+	rt.GET("/api/multi_edition_page_numbers", mint.MultiEditionPageNumbersIndex(db))
+
+	//cs_para_numbers
+	//display a list of cs_para_numbers
+	rt.GET("/api/cs_para_numbers", mint.CsParaNumbersIndex(db))
+
+	//pali_word_indexs
+	//display a list of pali_word_indexs
+	rt.GET("/api/pali_word_indexs", mint.PaliWordIndexsIndex(db))
+
+	//pali_word_indexs
+	//display a list of pali_word_indexs
+	rt.GET("/api/pali_words", mint.PaliWordsIndex(db))
+
+	//pali_word_indexs
+	//display a list of pali_word_indexs
+	rt.GET("/api/word_in_book_indexs", mint.WordInBookIndexsIndex(db))
+
+	//bold
+	//display a list of pali_word_indexs
+	rt.GET("/api/bolds", mint.BoldsIndex(db))
+
+	//sub book
+	//display a list of subbooks
+	rt.GET("/api/subbooks", mint.SubBooksIndex(db))
+
+	//wbws
+	//display a list of all wbws
+	rt.GET("/api/wbws", mint.WbwsIndex(db))
+	//return an HTML form for creating a new wbws
+	rt.GET("/api/wbws/new", mint.WbwsNew(db))
+	//create a new wbws
+	rt.POST("/api/wbws", mint.WbwsCreate(db))
+	//display a specific wbws
+	rt.GET("/api/wbws/:id", mint.WbwsShow(db, rdb))
+	//return an HTML form for edit a wbws
+	rt.GET("/api/wbws/:id/edit", mint.WbwsEdit(db))
+	//update a specific wbws
+	rt.PUT("/api/wbws/:id", mint.WbwsUpdate(db, rdb))
+	//delete a specific wbws
+	rt.DELETE("/api/wbws/:id", mint.WbwsDestroy(db, rdb))
+
+	//wbw_index
+	//display a list of all wbwindexs
+	rt.GET("/api/wbwindexs", mint.WbwIndexsIndex(db))
+	//create a new wbwindexs
+	rt.POST("/api/wbwindexs", mint.WbwIndexsCreate(db))
+	//display a specific wbwindexs
+	rt.GET("/api/wbwindexs/:id", mint.WbwIndexsShow(db, rdb))
+	//delete a specific wbwindexs
+	rt.DELETE("/api/wbwindexs/:id", mint.WbwIndexsDestroy(db, rdb))
+
+	//wbws_lists
+	//display a list of all wbws
+	rt.GET("/api/wbws_lists", mint.WbwsListsIndex(db))
+	//return an HTML form for creating a new wbws
+	rt.GET("/api/wbws_lists/new", mint.WbwsListsNew(db))
+	//create a new wbws
+	rt.POST("/api/wbws_lists", mint.WbwsListsCreate(db))
+	//display a specific wbws
+	rt.GET("/api/wbws_lists/:id", mint.WbwsListsShow(db, rdb))
+	//return an HTML form for edit a wbws
+	rt.GET("/api/wbws_lists/:id/edit", mint.WbwsListsEdit(db))
+	//update a specific wbws
+	rt.PUT("/api/wbws_lists/:id", mint.WbwsListsUpdate(db, rdb))
+	//delete a specific wbws
+	rt.DELETE("/api/wbws_lists/:id", mint.WbwsListsDestroy(db, rdb))
+
+	//comments
+	//display a list of all comments
+	rt.GET("/api/comments", mint.CommentsIndex(db))
+	//return an HTML form for creating a new comments
+	rt.GET("/api/comments/new", mint.CommentsNew(db))
+	//create a new comments
+	rt.POST("/api/comments", mint.CommentsCreate(db))
+	//display a specific comments
+	rt.GET("/api/comments/:id", mint.CommentsShow(db, rdb))
+	//return an HTML form for edit a comments
+	rt.GET("/api/comments/:id/edit", mint.CommentsEdit(db))
+	//update a specific comments
+	rt.PUT("/api/comments/:id", mint.CommentsUpdate(db, rdb))
+	//delete a specific comments
+	rt.DELETE("/api/comments/:id", mint.CommentsDestroy(db, rdb))
 
 	rt.Run()
 }
-

+ 109 - 0
api/mint/active.go

@@ -0,0 +1,109 @@
+package mint
+
+import (
+	"net/http"
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	//"github.com/go-redis/redis/v8"
+	"time"
+)
+
+type ActiveLogs struct {
+	Id     int `form:"id" json:"id" `
+	UserId int `form:"user_id" json:"user_id" `
+	ActiveType string `form:"active_type" json:"active_type"`
+	Content string `form:"content" json:"content"`
+	Timezone string `form:"timezone" json:"timezone"`
+
+    CreatedAt time.Time
+    UpdatedAt time.Time
+}
+
+type ActiveTimeFrames struct {
+	Id     int `form:"id" json:"id" `
+	UserId int `form:"user_id" json:"user_id" `
+	Hit int `form:"hit" json:"hit"`
+	Timezone string `form:"timezone" json:"timezone"`
+
+    CreatedAt time.Time
+    UpdatedAt time.Time
+}
+type ActiveDayFrames struct {
+	Id        int `form:"id" json:"id" `
+	UserId    int `form:"user_id" json:"user_id" `
+    Date      time.Time
+
+	Duration  int `form:"duration" json:"duration"`
+	hit       int `form:"hit" json:"hit"`
+
+    CreatedAt time.Time
+    UpdatedAt time.Time
+}
+
+//display a list of all groups
+func ActiveIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		timerange := c.Query("range")
+		userid := c.Query("userid")
+
+		switch timerange {
+		case "day":
+			var dayFrames []ActiveDayFrames
+			err := db.Model(&dayFrames).Column("id","date","Duration","hit").Where("user_id = ?",userid).Select()
+			if err != nil {
+				panic(err)
+			}
+			c.JSON(http.StatusOK, gin.H{
+				"data": dayFrames,
+			})			
+		case "frame":
+			var timeFrames []ActiveTimeFrames
+			err := db.Model(&timeFrames).Column("id","hit","timezone","created_at","updated_at").Where("user_id = ?",userid).Select()
+			if err != nil {
+				panic(err)
+			}
+			c.JSON(http.StatusOK, gin.H{
+				"data": timeFrames,
+			})
+		case "event":
+			start := c.Query("start")
+			end := c.Query("end")
+
+			var activeLogs []ActiveLogs
+			err := db.Model(&activeLogs).Column("active_type","content","timezone","created_at").Where("user_id = ?",userid).Where("created_at > ?",start).Where("created_at < ?",end).Select()
+			if err != nil {
+				panic(err)
+			}
+			c.JSON(http.StatusOK, gin.H{
+				"data": activeLogs,
+			})
+		}		
+
+	}
+}
+
+
+//create a new group
+func ActiveCreate(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+	
+		active_type := c.Query("active_type")
+		content := c.Query("content")
+
+		activeLogs := &ActiveLogs{
+			ActiveType:   active_type,
+			Content: content,
+			UserId:1,//TODO user_id
+		}
+		_, err := db.Model(activeLogs).Insert()
+		if err != nil {
+			panic(err)
+		}
+		//TODO 补充业务逻辑
+		//建立成功
+		c.JSON(http.StatusOK,gin.H{
+			"message":"ok",
+		})
+	}
+}
+

+ 224 - 121
api/mint/article.go

@@ -1,194 +1,297 @@
 package mint
 
 import (
+	"context"
+	"encoding/json"
+	"fmt"
 	"net/http"
 	"strconv"
-	"fmt"
+	"time"
+
 	"github.com/gin-gonic/gin"
 	"github.com/go-pg/pg/v10"
 	"github.com/go-redis/redis/v8"
-	"context"
-	"time"
 )
-var ctx = context.Background()
-
 
-/*
-    id SERIAL PRIMARY KEY,
-    uuid         VARCHAR (36) ,
-    title        VARCHAR (32) NOT NULL,
-    subtitle     VARCHAR (32),
-    summary      VARCHAR (255),
-    content      TEXT,
-    owner_id     INTEGER  NOT NULL,
-    owner        VARCHAR (36),
-    setting      JSON,
-    status       INTEGER   NOT NULL DEFAULT (10),
-	version     INTEGER NOT NULL DEFAULT (1),
-    deleted_at  TIMESTAMP,
-    created_at  TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    updated_at  TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
+var ctx = context.Background()
 
-*/
 type Article struct {
-	Id     int `form:"id" json:"id" binding:"required"`
-	Title string `form:"title" json:"title" binding:"required"`
-	Subtitle string `form:"subtitle" json:"subtitle"`
-	Summary string `form:"summary" json:"summary"`
-	Content string `form:"content" json:"content"`
-	OwnerId int
-	Setting string `form:"setting" json:"setting"`
-	Status int `form:"status" json:"status"`
-	Version int
-    DeletedAt time.Time
-    CreatedAt time.Time
-    UpdatedAt time.Time
+	Id          int    `json:"id" `
+	Uid         string `json:"uid" `
+	ParentId    int    `json:"parent_id"`
+	PrParentId  int    `json:"pr_parent_id" `
+	Title       string `json:"title"`
+	Subtitle    string `json:"subtitle"`
+	Summary     string `json:"summary"`
+	Content     string `json:"content"`
+	ContentType string `json:"content_type"`
+	Lang        string `json:"lang"`
+	Setting     string `json:"setting"`
+	Status      string `json:"status"`
+	EditorId    int    `json:"editor_id"`
+	StudioId    int    `json:"studio_id"`
+	CreatorId   int    `json:"creator_id"`
+	Version     int
+	DeletedAt   time.Time
+	CreatedAt   time.Time
+	UpdatedAt   time.Time
 }
+
 //查询
-func GetArticle(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+/*
+parent_id=0 的文章为文章模板
+parent_id>0 的文章为文章实例,是模板+channel(多个)
+*/
+//查询 列表
+func ArticlesIndex(db *pg.DB) gin.HandlerFunc {
 	return func(c *gin.Context) {
-		lid,err := strconv.ParseInt(c.Param("aid"),10,64)
+		view := c.Query("view")
+		studio := c.DefaultQuery("studio", "")
+		status := c.DefaultQuery("status", "public")
+
+		columns := "id,title,subtitle,owner_id"
+		var articles []Article
+		var err error
+		if studio == "" {
+			switch view {
+			case "title":
+				err = db.Model(&articles).ColumnExpr(columns).Where("title like ?", c.Query("view")+"%").Select()
+			case "tempalet":
+				//列出文章模板
+				err = db.Model(&articles).ColumnExpr(columns).Where("parent_id = 0").Select()
+			case "instance":
+				//文章实例
+				err = db.Model(&articles).ColumnExpr(columns).Where("parent_id = ?", c.Query("id")).Select()
+			case "pr":
+				//修改建议
+				err = db.Model(&articles).ColumnExpr(columns).Where("pr_parent_id = ?", c.Query("id")).Select()
+			default:
+				panic("error view")
+			}
+
+		} else {
+			if status == "all" {
+				//TODO studio 鉴权
+				switch view {
+				case "title":
+					err = db.Model(&articles).ColumnExpr(columns).Where("title like ?", c.Query("view")+"%").Select()
+				case "tempalet":
+					//列出文章模板
+					err = db.Model(&articles).ColumnExpr(columns).Where("parent_id = 0").Select()
+				case "instance":
+					//文章实例
+					err = db.Model(&articles).ColumnExpr(columns).Where("parent_id = ?", c.Query("id")).Select()
+				case "pr":
+					//修改建议
+					err = db.Model(&articles).ColumnExpr(columns).Where("pr_parent_id = ?", c.Query("id")).Select()
+				default:
+					panic("error view")
+				}
+			} else {
+				//TODO studio 鉴权
+				switch view {
+				case "title":
+					err = db.Model(&articles).ColumnExpr(columns).Where("title like ?", c.Query("view")+"%").Where("status = ?", "public").Select()
+				case "tempalet":
+					//列出文章模板
+					err = db.Model(&articles).ColumnExpr(columns).Where("parent_id = 0").Where("status = ?", "public").Select()
+				case "instance":
+					//文章实例
+					err = db.Model(&articles).ColumnExpr(columns).Where("parent_id = ?", c.Query("id")).Where("status = ?", "public").Select()
+				case "pr":
+					//修改建议
+					err = db.Model(&articles).ColumnExpr(columns).Where("pr_parent_id = ?", c.Query("id")).Where("status = ?", "public").Select()
+				default:
+					panic("error view")
+				}
+			}
+		}
 		if err != nil {
 			panic(err)
 		}
-		fmt.Println("get article")
-		rkey := "article://"+c.Param("aid")
-		n, err := rdb.Exists(ctx,rkey).Result()
-		if err != nil  {
-			fmt.Println(err)
-		}else if n == 0 {
-			fmt.Println("redis key not exist")
-		}else{
-			fmt.Println("redis key exist")
-			val, err := rdb.HGetAll(ctx, rkey).Result()
-			if err != nil || val == nil {
-				//有错误或者没查到
-				fmt.Println("redis error")
-					
-			}else{
-				fmt.Println("redis no error")
-				c.JSON(http.StatusOK, gin.H{
-					"data": val,
-				})
-				return
-			}	
-		}
 
-		article := &Article{Id: int(lid)}
-		err = db.Model(article).Column("id","title","subtitle","content","owner_id","setting","status","version","updated_at").WherePK().Select()
-		if err != nil {
-			panic(err)
-		}			
 		c.JSON(http.StatusOK, gin.H{
-			"data": article,
+			"status": "success",
+			"data":   articles,
 		})
-		//写入redis
-		rdb.HSet(ctx,rkey,"id",article.Id)
-		rdb.HSet(ctx,rkey,"title",article.Title)
-		rdb.HSet(ctx,rkey,"subtitle",article.Subtitle)
-		rdb.HSet(ctx,rkey,"content",article.Content)
-		rdb.HSet(ctx,rkey,"owner_id",article.OwnerId)
-		rdb.HSet(ctx,rkey,"setting",article.Setting)
-		rdb.HSet(ctx,rkey,"status",article.Status)
-		rdb.HSet(ctx,rkey,"version",article.Version)
-		rdb.HSet(ctx,rkey,"updated_at",article.UpdatedAt)
-			
 	}
 }
 
-//查询
-func GetArticleByTitle(db *pg.DB) gin.HandlerFunc {
+//return an HTML form for creating a new Courses
+func ArticlesNew(db *pg.DB) gin.HandlerFunc {
 	return func(c *gin.Context) {
-		title:= c.Param("ltitle")
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "articles_new.html", gin.H{
+			"message": "ok",
+		})
+	}
+}
 
-		// TODO 在这里进行db操作
-		// Select user by primary key.
-		var articles []Article
-		err := db.Model(&articles).Column("id","title","subtitle").Where("title like ?",title+"%").Select()
+//新建-
+//create a new articles
+func ArticlesCreate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		var form Course
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{
+				"ok":    false,
+				"error": err.Error(),
+			})
+			return
+		}
+
+		if form.Title == "" {
+			c.JSON(http.StatusBadRequest, gin.H{
+				"ok":    false,
+				"error": ":no-title",
+			})
+			return
+		}
+
+		//TODO 获取 userid
+		form.EditorId = 1
+		form.CreatorId = 1
+
+		//TODO studio 鉴权
+
+		_, err := db.Model(&form).Column("title", "status", "editor_id", "creator_id", "studio_id").Insert()
 		if err != nil {
 			panic(err)
 		}
-		
+
+		//建立成功
 		c.JSON(http.StatusOK, gin.H{
-			"message": articles,
+			"ok":   true,
+			"data": form,
 		})
 	}
 }
 
-//新建-
-//PUT http://127.0.0.1:8080/api/lesson?title=lesson-one&status=10
-func PutArticle(db *pg.DB) gin.HandlerFunc{
-	return func(c *gin.Context){
-	
-		title := c.Query("title")
-		status1,err := strconv.ParseInt(c.Query("status"),10,64)
+//display a specific articles
+func ArticlesShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
 		if err != nil {
 			panic(err)
 		}
 
-		newArticle := &Article{
-			Title:   title,
-			Status: int(status1),
-			OwnerId:1,
+		rkey := "article/:id"
+		n, err := rdb.HExists(ctx, rkey, c.Param("id")).Result()
+		if err == nil && n {
+			val, err := rdb.HGet(ctx, rkey, c.Param("id")).Result()
+			if err == nil {
+				var redisData Article
+				json.Unmarshal([]byte(val), &redisData)
+				c.JSON(http.StatusOK, gin.H{
+					"ok":   true,
+					"data": redisData,
+				})
+				return
+			} else {
+				fmt.Println(err)
+			}
+		} else {
+			fmt.Println(err)
 		}
-		_, err = db.Model(newArticle).Insert()
+
+		article := &Article{Id: id}
+		err = db.Model(article).Column("id", "uid", "parent_id", "title", "subtitle", "content", "content_type", "lang", "owner_id", "setting", "status", "version", "updated_at").WherePK().First()
 		if err != nil {
-			panic(err)
+			if err.Error() == pg.ErrNoRows.Error() {
+				c.JSON(http.StatusOK, gin.H{
+					"ok":      true,
+					"message": "no-rows",
+				})
+			} else {
+				panic(err)
+			}
+		} else {
+			c.JSON(http.StatusOK, gin.H{
+				"ok":   true,
+				"data": article,
+			})
+			//写入redis
+			jsonData, err := json.Marshal(article)
+			if err == nil {
+				rdb.HSet(ctx, rkey, c.Param("id"), string(jsonData))
+			}
 		}
 
-		//修改完毕
-		c.JSON(http.StatusOK,gin.H{
-			"message":"",
-		})
 	}
 }
 
+//return an HTML form for edit a Courses
+func ArticlesEdit(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "articles/edit.html", gin.H{
+			"message": "ok",
+		})
+	}
+}
 
 //修改
-func PostAritcle(db *pg.DB,rdb *redis.Client) gin.HandlerFunc{
-	return func(c *gin.Context){
+//update a specific articles
+func ArticlesUpdate(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
 		var form Article
 
 		if err := c.ShouldBindJSON(&form); err != nil {
-			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			c.JSON(http.StatusBadRequest, gin.H{
+				"ok":      true,
+				"message": err.Error(),
+			})
+			return
+		}
+		if form.Title == "" {
+			c.JSON(http.StatusBadRequest, gin.H{
+				"ok":    false,
+				"error": ":no-title",
+			})
 			return
 		}
 
-		_,err := db.Model(&form).Column("title","subtitle","summary","status","content").WherePK().Update()
+		//TODO 鉴权
+		_, err := db.Model(&form).Column("title", "subtitle", "summary", "status", "content").WherePK().Update()
 		if err != nil {
 			panic(err)
 		}
-		c.JSON(http.StatusOK,gin.H{
-			"message":"update ok",
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   form,
 		})
-		rkey := "article://"+strconv.Itoa(form.Id)
-		rdb.Del(ctx,rkey)
+		rkey := "article/:id"
+		rdb.Del(ctx, rkey, c.Param("id"))
 	}
 }
 
-
 //删
-func DeleteArticle(db *pg.DB ,rdb *redis.Client) gin.HandlerFunc{
-	return func(c *gin.Context){
-		id,err := strconv.Atoi(c.Param("aid"))
+//delete a specific articles
+func ArticlesDestroy(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
 		if err != nil {
 			panic(err)
 		}
 		article := &Article{
-			Id:int(id),
+			Id: int(id),
 		}
-		//删之前获取 course_id
-		_, err = db.Model(article).WherePK().Delete()
+		//TODO 鉴权
+		_, err = db.Model(article).WherePK().Where("parent_id = ?", id).Where("pr_parent_id = ?", id).Delete()
 		if err != nil {
 			panic(err)
 		}
+
+		rkey := "article://id"
+		rdb.Del(ctx, rkey, c.Param("id"))
+
 		//TODO 删除article_list表相关项目
-		c.JSON(http.StatusOK,gin.H{
-			"message":"delete "+c.Param("lid"),
+		c.JSON(http.StatusOK, gin.H{
+			"ok":   true,
+			"data": c.Param("id"),
 		})
 
-		rkey := "article://"+c.Param("aid")
-		rdb.Del(ctx,rkey)
-
 	}
-}
+}

+ 21 - 13
api/mint/article_list.go

@@ -24,17 +24,20 @@ func (i *ArticleListHolder) UnmarshalJSON(b []byte) error{
 	return json.Unmarshal(b, &i.Items)
 }
 //查询
-func GetCollectionArticleList(db *pg.DB) gin.HandlerFunc {
+func ArticleListIndex(db *pg.DB) gin.HandlerFunc {
 	return func(c *gin.Context) {
-		cid,err:= strconv.Atoi(c.Param("cid"))
-		if err != nil {
-			panic(err)
-		}
+		id := c.Query("id")
+		object := c.Query("object")
 
 		// TODO 在这里进行db操作
 		// Select user by primary key.
 		var articles []ArticleList
-		err = db.Model(&articles).Column("collection_id","article_id").Where("collection_id = ?",cid).Select()
+		var err error
+		if object == "article" {
+			err = db.Model(&articles).Column("collection_id","article_id").Where("article_id = ?",id).Select()
+		}else{
+			err = db.Model(&articles).Column("collection_id","article_id").Where("collection_id = ?",id).Select()
+		}
 		if err != nil {
 			panic(err)
 		}
@@ -48,14 +51,19 @@ func GetCollectionArticleList(db *pg.DB) gin.HandlerFunc {
 
 
 //修改
-func PostArticleListByArticle(db *pg.DB) gin.HandlerFunc{
+func ArticleListUpdate(db *pg.DB) gin.HandlerFunc{
 	return func(c *gin.Context){
-		aid,err:= strconv.Atoi(c.Param("aid"))
-		if err != nil {
-			panic(err)
-		}
+		id := c.Query("id")
+		object := c.Query("object")
+
+
 		//先删除
-		_, err = db.Model((*ArticleList)(nil)).Where("article_id = ?",aid).Delete()
+		var err error
+		if object == "article" {
+			_, err = db.Model((*ArticleList)(nil)).Where("article_id = ?",id).Delete()
+		}else{
+			_, err = db.Model((*ArticleList)(nil)).Where("collection_id = ?",id).Delete()
+		}
 		if err != nil {
 			panic(err)
 		}
@@ -77,7 +85,7 @@ func PostArticleListByArticle(db *pg.DB) gin.HandlerFunc{
 		}
 		defer stmt.Close()
 		for _, value := range form.Items{
-			_, err = stmt.Exec(value.CollectionId,aid)
+			_, err = stmt.Exec(value.CollectionId,id)
 			if err != nil {
 				panic(err)
 			}

+ 160 - 0
api/mint/authorization.go

@@ -0,0 +1,160 @@
+package mint
+
+import (
+	"net/http"
+	"strconv"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type Authorization struct {
+	Id int `form:"id" json:"id" binding:"required"`
+
+	ResourceId   int    `form:"resource_id" json:"resource_id"`
+	ResourceType string `form:"resource_type" json:"resource_type"`
+
+	UserId   string `form:"user_id" json:"user_id"`
+	UserType string `form:"user_type" json:"user_type"`
+
+	ResRight string `form:"res_right" json:"res_right"`
+	OwnerId  int    `form:"owner_id" json:"owner_id"`
+
+	ExpiredAt  time.Time `form:"expired_at" json:"expired_at"`
+	AcceptedAt time.Time `form:"accepted_at" json:"accepted_at"`
+
+	Version int
+
+	CreatedAt time.Time
+	UpdatedAt time.Time
+}
+
+//查询display a list of all Authorizations
+func AuthorizationsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//按照标题搜索,或者按照authorization列出子课程
+		resource_id := c.Query("resource_id")
+		resource_type := c.Query("resource_type")
+
+		// TODO 在这里进行db操作
+		// Select user by primary key.
+		var authorizations []Authorization
+
+		err := db.Model(&authorizations).Column("id", "resource_id", "resource_type", "user_id", "user_type", "res_right", "expired_at", "accepted_at").Where("resource_id = ?", resource_id).Where("resource_type = ?", resource_type).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"message": authorizations,
+		})
+	}
+}
+
+//return an HTML form for creating a new Authorizations
+func AuthorizationsNew(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "authorizations/new.html", gin.H{
+			"message": "ok",
+		})
+	}
+}
+
+//新建create a new Authorizations
+func AuthorizationsCreate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		var form Channel
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+		_, err := db.Model(&form).Insert()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   form,
+		})
+	}
+}
+
+//查询display a specific Authorizations
+func AuthorizationsShow(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		authorization := Authorization{Id: id}
+		err = db.Model(&authorization).WherePK().Select()
+
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   authorization,
+		})
+
+	}
+}
+
+//return an HTML form for edit a Authorizations
+func AuthorizationsEdit(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "authorizations/edit.html", gin.H{
+			"message": "ok",
+		})
+	}
+}
+
+//update a specific Authorizations
+
+func AuthorizationsUpdate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		var form Authorization
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+
+		_, err := db.Model(&form).Column("res_right").WherePK().Update()
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK, gin.H{
+			"message": "update ok",
+		})
+	}
+}
+
+//删
+//delete a specific Authorizations
+func AuthorizationsDestroy(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		authorization := &Authorization{
+			Id: id,
+		}
+
+		_, err = db.Model(authorization).WherePK().Delete()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"message": c.Param("id"),
+		})
+	}
+}

+ 38 - 0
api/mint/bolds.go

@@ -0,0 +1,38 @@
+package mint
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type Bolds struct {
+	Id        int    `json:"id" `
+	BookId    int    `json:"book_id" `
+	Paragraph int    `json:"paragraph" `
+	WordSpell string `json:"word_spell" `
+	WordReal  string `json:"word_real" `
+	WordEn    string `json:"word_en" `
+	CreatedAt time.Time
+}
+
+//display a list of all palitexts
+func BoldsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		word := c.Query("word")
+
+		// TODO 补充业务逻辑
+		var bolds []Bolds
+		err := db.Model(&bolds).Where("word_real = ?", word).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   bolds,
+		})
+	}
+}

+ 186 - 0
api/mint/book.go

@@ -0,0 +1,186 @@
+package mint
+
+import (
+	"fmt"
+	"net/http"
+	"strconv"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+)
+
+type Book struct {
+	Id int `form:"id" json:"id" `
+
+	Title     string `form:"title" json:"title"`
+	Summary   string `form:"summary" json:"summary"`
+	Lang      string `form:"lang" json:"lang"`
+	ChannelId int    `form:"channel_id" json:"channel_id"`
+
+	Status string `form:"status" json:"status"`
+
+	OwnerId   int
+	Version   int
+	DeletedAt time.Time
+
+	CreatedAt time.Time
+	UpdatedAt time.Time
+}
+
+//display a list of all books
+func BooksIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		title := c.DefaultQuery("title", "")
+
+		// TODO 补充业务逻辑
+		var books []Book
+		err := db.Model(&books).Column("id", "title").Where("name like ?", title+"%").Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"data": books,
+		})
+	}
+}
+
+//return an HTML form for creating a new book
+func BooksNew(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "books/new.html", gin.H{
+			"message": "ok",
+		})
+	}
+}
+
+//create a new book
+func BooksCreate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		var form Book
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+		form.OwnerId = 1
+		_, err := db.Model(&form).Insert()
+		if err != nil {
+			panic(err)
+		}
+
+		//建立成功
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   form,
+		})
+	}
+}
+
+//display a specific Book
+func BooksShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		fmt.Println("get book id=" + c.Param("id"))
+		rkey := "book://id"
+		n, err := rdb.Exists(ctx, rkey).Result()
+		if err != nil {
+			fmt.Println(err)
+		} else if n == 0 {
+			fmt.Println("redis key not exist")
+		} else {
+			fmt.Println("redis key exist")
+			val, err := rdb.HGetAll(ctx, rkey).Result()
+			if err != nil || val == nil {
+				//有错误或者没查到
+				fmt.Println("redis error")
+
+			} else {
+				fmt.Println("redis no error")
+				c.JSON(http.StatusOK, gin.H{
+					"data": val,
+				})
+				return
+			}
+		}
+
+		book := &Book{Id: id}
+		err = db.Model(book).Column("id", "uid", "name", "description", "description_type", "owner_id", "setting", "status", "version", "updated_at").WherePK().Select()
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK, gin.H{
+			"data": book,
+		})
+		//写入redis
+		rdb.HSet(ctx, rkey, id, book)
+
+	}
+}
+
+//return an HTML form for edit a book
+func BooksEdit(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "books/edit.html", gin.H{
+			"name": "ok",
+		})
+	}
+}
+
+//update a specific book
+func BooksUpdate(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		var form Book
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+
+		//补充业务逻辑
+		_, err := db.Model(&form).Column("name", "description", "description_type", "status", "setting").WherePK().Update()
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK, gin.H{
+			"message": form,
+		})
+		//delete redis
+		rkey := "book://id/" + strconv.Itoa(form.Id)
+		rdb.Del(ctx, rkey)
+	}
+}
+
+//delete a specific book
+func BooksDestroy(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		book := &Book{
+			Id: int(id),
+		}
+
+		_, err = db.Model(book).WherePK().Delete()
+		if err != nil {
+			panic(err)
+		}
+
+		rkey := "book://id/" + c.Param("id")
+		rdb.Del(ctx, rkey)
+
+		c.JSON(http.StatusOK, gin.H{
+			"message": c.Param("id"),
+		})
+
+	}
+}

+ 198 - 0
api/mint/channel.go

@@ -0,0 +1,198 @@
+package mint
+
+import (
+	"net/http"
+	"strconv"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+	"time"
+)
+
+
+type Channel struct {
+	Id     int `form:"id" json:"id" `
+	Uid string `form:"uid" json:"uid" `
+	Title string `form:"title" json:"title"`
+	Summary string `form:"summary" json:"summary"`
+	Lang string `lang:"summary" json:"lang"`
+
+	Setting string `form:"setting" json:"setting"`
+	Status string `form:"status" json:"status"`
+
+	OwnerId int
+	Version int
+    DeletedAt time.Time
+    CreatedAt time.Time
+    UpdatedAt time.Time
+}
+
+
+//display a list of all channels
+func ChannelsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		name:= c.DefaultQuery("name","")
+
+		// TODO 补充业务逻辑
+		var channels []Channel
+		err := db.Model(&channels).Column("id","name").Where("name like ?",name+"%").Select()
+		if err != nil {
+			panic(err)
+		}
+		
+		c.JSON(http.StatusOK, gin.H{
+			"data": channels,
+		})
+	}
+}
+
+//return an HTML form for creating a new channel
+func ChannelsNew(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK,"channels/new.html",gin.H{
+			"message":"ok",
+		})
+	}
+}
+//create a new channel
+func ChannelsCreate(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+	
+		name := c.Query("title")
+		status := c.DefaultQuery("status","private")
+
+		newChannel := &Channel{
+			Title:   name,
+			Status: status,
+			OwnerId:1,//TODO user_id
+		}
+		_, err := db.Model(newChannel).Insert()
+		if err != nil {
+			panic(err)
+		}
+
+		//建立成功
+		c.JSON(http.StatusOK,gin.H{
+			"message":"ok",
+		})
+	}
+}
+
+//display a specific Channel
+func ChannelsShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id,err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		fmt.Println("get channel id=" + c.Param("id"))
+		rkey := "channel://id/"+c.Param("id")
+		n, err := rdb.Exists(ctx,rkey).Result()
+		if err != nil  {
+			fmt.Println(err)
+		}else if n == 0 {
+			fmt.Println("redis key not exist")
+		}else{
+			fmt.Println("redis key exist")
+			val, err := rdb.HGetAll(ctx, rkey).Result()
+			if err != nil || val == nil {
+				//有错误或者没查到
+				fmt.Println("redis error")
+					
+			}else{
+				fmt.Println("redis no error")
+				c.JSON(http.StatusOK, gin.H{
+					"data": val,
+				})
+				return
+			}	
+		}
+
+		channel := &Channel{Id: id}
+		err = db.Model(channel).Column("id","uid","name","description","description_type","owner_id","setting","status","version","updated_at").WherePK().Select()
+		if err != nil {
+			panic(err)
+		}			
+		c.JSON(http.StatusOK, gin.H{
+			"data": channel,
+		})
+		//写入redis
+		rdb.HSet(ctx,rkey,"id",channel.Id)
+		rdb.HSet(ctx,rkey,"uid",channel.Uid)
+		rdb.HSet(ctx,rkey,"title",channel.Title)
+		rdb.HSet(ctx,rkey,"summary",channel.Summary)
+		rdb.HSet(ctx,rkey,"lang",channel.Lang)
+		rdb.HSet(ctx,rkey,"owner_id",channel.OwnerId)
+		rdb.HSet(ctx,rkey,"setting",channel.Setting)
+		rdb.HSet(ctx,rkey,"status",channel.Status)
+		rdb.HSet(ctx,rkey,"version",channel.Version)
+		rdb.HSet(ctx,rkey,"updated_at",channel.UpdatedAt)
+		rdb.HSet(ctx,rkey,"created_at",channel.CreatedAt)
+			
+	}
+}
+
+//return an HTML form for edit a channel
+func ChannelsEdit(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK,"channels/edit.html",gin.H{
+			"name":"ok",
+		})
+	}
+}
+
+//update a specific channel
+func ChannelsUpdate(db *pg.DB,rdb *redis.Client) gin.HandlerFunc{
+	return func(c *gin.Context){
+		var form Channel
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+
+		//补充业务逻辑
+		_,err := db.Model(&form).Column("name","description","description_type","status","setting").WherePK().Update()
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK,gin.H{
+			"message":form,
+		})
+		//delete redis
+		rkey := "channel://id/"+strconv.Itoa(form.Id)
+		rdb.Del(ctx,rkey)
+	}
+}
+
+
+//delete a specific channel
+func ChannelsDestroy(db *pg.DB ,rdb *redis.Client) gin.HandlerFunc{
+	return func(c *gin.Context){
+		id,err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		channel := &Channel{
+			Id:int(id),
+		}
+
+		_, err = db.Model(channel).WherePK().Delete()
+		if err != nil {
+			panic(err)
+		}
+
+		rkey := "channel://id/"+c.Param("id")
+		rdb.Del(ctx,rkey)
+		
+		c.JSON(http.StatusOK,gin.H{
+			"message": c.Param("id"),
+		})
+
+
+
+	}
+}

+ 72 - 57
api/mint/collection.go

@@ -3,100 +3,102 @@ package mint
 import (
 	"net/http"
 	"strconv"
-	"fmt"
+	//"fmt"
 	"github.com/gin-gonic/gin"
 	"github.com/go-pg/pg/v10"
 	"time"
 )
-/*
-    id SERIAL PRIMARY KEY,
-    uuid         VARCHAR (36) ,
-    title        VARCHAR (32) NOT NULL,
-    subtitle     VARCHAR (32),
-    summary      VARCHAR (255),
-    article_list TEXT,
-    status       INTEGER   NOT NULL DEFAULT (10),
-    creator_id   INTEGER,
-    owner        VARCHAR (36),
-    lang         CHAR (8),
-	version     INTEGER NOT NULL DEFAULT (1),
-    deleted_at  TIMESTAMP,
-    created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-    updated_at  TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
-
-*/
+
 type Collection struct {
-	Id     int `form:"id" json:"id" binding:"required"`
-	Title string `form:"title" json:"title" binding:"required"`
-	Subtitle string `form:"subtitle" json:"subtitle" binding:"required"`
-	Summary string `form:"summary" json:"summary" binding:"required"`
-	ArticleList string `form:"article_list" json:"article_list" binding:"required"`
-	CreatorId int
-	Lang string `form:"lang" json:"lang" binding:"required"`
-	Status int `form:"status" json:"status" binding:"required"`
+	Id     int `form:"id" json:"id" `
+	Uid string `form:"uid" json:"uid" `
+	ParentId int `form:"parent_id" json:"parent_id"`
+	PrParentId int `form:"pr_parent_id" json:"pr_parent_id" `
+
+	Title string `form:"title" json:"title" `
+	Subtitle string `form:"subtitle" json:"subtitle" `
+	Summary string `form:"summary" json:"summary"`
+	
+	ArticleList string `form:"article_list" json:"article_list" `
+	
+	Lang string `form:"lang" json:"lang" `
+	Setting string `form:"setting" json:"setting" `
+	Status string `form:"status" json:"status" `
+
+	OwnerId int
 	Version int
     DeletedAt time.Time
     CreatedAt time.Time
     UpdatedAt time.Time
 }
 //查询
-func GetCollection(db *pg.DB) gin.HandlerFunc {
+	//display a list of all collections
+func CollectionsIndex(db *pg.DB) gin.HandlerFunc {
 	return func(c *gin.Context) {
-		lid,err := strconv.Atoi(c.Param("cid"))
-		if err != nil {
-			panic(err)
-		}
-		fmt.Println("get lesson")
+		title:= c.Param("ctitle")
+
 		// TODO 在这里进行db操作
 		// Select user by primary key.
-		collection := &Collection{Id: int(lid)}
-		err = db.Model(collection).Column("title","subtitle","summary","status").WherePK().Select()
+		var collections []Collection
+		err := db.Model(&collections).Column("id","title","subtitle").Where("title like ?",title+"%").Select()
 		if err != nil {
 			panic(err)
 		}
 		
 		c.JSON(http.StatusOK, gin.H{
-			"message": collection,
+			"message": collections,
 		})
 	}
 }
 
 //查询
-func GetCollectionByTitle(db *pg.DB) gin.HandlerFunc {
-	return func(c *gin.Context) {
-		title:= c.Param("ctitle")
+	//display a specific collections
 
+func CollectionsShow(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id,err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
 		// TODO 在这里进行db操作
 		// Select user by primary key.
-		var collections []Collection
-		err := db.Model(&collections).Column("id","title","subtitle").Where("title like ?",title+"%").Select()
+		collection := &Collection{Id: id}
+		err = db.Model(collection).Column("title","subtitle","summary","status").WherePK().Select()
 		if err != nil {
 			panic(err)
 		}
 		
 		c.JSON(http.StatusOK, gin.H{
-			"message": collections,
+			"message": collection,
+		})
+	}
+}
+
+//return an HTML form for creating a new Courses
+func CollectionsNew(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK,"collections/new.html",gin.H{
+			"message":"ok",
 		})
 	}
 }
 
 //新建-
-//PUT http://127.0.0.1:8080/api/lesson?title=lesson-one&course_id=1&status=10
-func PutCollection(db *pg.DB) gin.HandlerFunc{
+	//create a new collections
+
+func CollectionsCreate(db *pg.DB) gin.HandlerFunc{
 	return func(c *gin.Context){
 	
 		title := c.Query("title")
-		status1,err := strconv.Atoi(c.Query("status"))
-		if err != nil {
-			panic(err)
-		}
+		status :=c.Query("status")
 
 		newOne := &Collection{
 			Title:   title,
-			Status: int(status1),
-			CreatorId:1,
+			Status: status,
+			OwnerId:1,
 		}
-		_, err = db.Model(newOne).Insert()
+		_, err := db.Model(newOne).Insert()
 		if err != nil {
 			panic(err)
 		}
@@ -107,10 +109,21 @@ func PutCollection(db *pg.DB) gin.HandlerFunc{
 		})
 	}
 }
+//return an HTML form for edit a Courses
+func CollectionsEdit(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK,"collections/edit.html",gin.H{
+			"message":"ok",
+		})
+	}
+}
+
 
 
 //改
-func PostCollection(db *pg.DB) gin.HandlerFunc{
+//update a specific collections
+func CollectionsUpdate(db *pg.DB) gin.HandlerFunc{
 	return func(c *gin.Context){
 		var form Collection
 
@@ -124,30 +137,32 @@ func PostCollection(db *pg.DB) gin.HandlerFunc{
 			panic(err)
 		}
 		c.JSON(http.StatusOK,gin.H{
-			"message":"update ok",
+			"message":form,
 		})
 	}
 }
 
 
 //删
-func DeleteCollection(db *pg.DB) gin.HandlerFunc{
+//delete a specific collections
+func CollectionsDestroy(db *pg.DB) gin.HandlerFunc{
 	return func(c *gin.Context){
-		id,err := strconv.Atoi(c.Param("cid"))
+		id,err := strconv.Atoi(c.Param("id"))
 		if err != nil {
 			panic(err)
 		}
 		collection := &Collection{
 			Id:int(id),
 		}
-		//删之前获取 course_id
-		_, err = db.Model(collection).WherePK().Delete()
+
+		_, err = db.Model(collection).WherePK().Where("parent_id = ?",id).Where("pr_parent_id = ?",id).Delete()
 		if err != nil {
 			panic(err)
 		}
+		//TODO redis delete
 		
 		c.JSON(http.StatusOK,gin.H{
-			"message":"deleted "+c.Param("cid"),
+			"message":c.Param("id"),
 		})
 	}
 }

+ 205 - 0
api/mint/comment.go

@@ -0,0 +1,205 @@
+package mint
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"strconv"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+	"github.com/google/uuid"
+)
+
+type Comment struct {
+	Id          int    `form:"id" json:"id" `
+	Uid         string `form:"uid" json:"uid" `
+	ParentId    int    `form:"parent_id" json:"parent_id"`
+	ParentType  string `form:"parent_type" json:"parent_type"`
+	Title       string `form:"title" json:"title"`
+	Content     string `form:"content" json:"content"`
+	ContentType string `form:"content_type" json:"content_type"`
+	Status      string `form:"status" json:"status"`
+	OwnerId     int
+	Version     int
+	CreatedAt   time.Time
+	UpdatedAt   time.Time
+}
+
+//display a list of all comments
+func CommentsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		parentid := c.Query("parentid")
+		parenttype := c.Query("parenttype")
+
+		// TODO 补充业务逻辑
+		var comments []Comment
+		err := db.Model(&comments).Column("id", "title", "content", "content_type", "status").Where("parent_id = ?", parentid).Where("parent_type = ?", parenttype).Where("status = checked").Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "success",
+			"data":   comments,
+		})
+	}
+}
+
+//return an HTML form for creating a new comment
+func CommentsNew(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "comments_new.html", gin.H{
+			"message": "ok",
+		})
+	}
+}
+
+//create a new comment
+func CommentsCreate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		var newComment Comment
+
+		if err := c.ShouldBindJSON(&newComment); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{
+				"status":  "fail",
+				"message": err.Error(),
+			})
+			return
+		}
+		newComment.Uid = uuid.New().String()
+		newComment.Status = "checking"
+		newComment.OwnerId = 1
+		_, err := db.Model(&newComment).Column("id", "uid", "parent_id", "parent_type", "title", "content", "content_type", "status", "owner_id").Insert()
+		if err != nil {
+			panic(err)
+		}
+
+		//建立成功
+		c.JSON(http.StatusOK, gin.H{
+			"status": "success",
+			"data":   newComment,
+		})
+	}
+}
+
+//display a specific Comment
+func CommentsShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		rkey := "comment://id"
+		n, err := rdb.HExists(ctx, rkey, c.Param("id")).Result()
+		if err == nil && n {
+			val, err := rdb.HGet(ctx, rkey, c.Param("id")).Result()
+			if err == nil {
+				var redisData Comment
+				json.Unmarshal([]byte(val), &redisData)
+				c.JSON(http.StatusOK, gin.H{
+					"status": "success",
+					"data":   redisData,
+				})
+				return
+			} else {
+				fmt.Println(err)
+			}
+		} else {
+			fmt.Println(err)
+		}
+
+		comment := &Comment{Id: id}
+		err = db.Model(comment).Column("id", "uid", "parent_id", "parent_type", "title", "content", "content_type", "status", "owner_id").WherePK().First()
+		if err != nil {
+			if err.Error() == pg.ErrNoRows.Error() {
+				c.JSON(http.StatusOK, gin.H{
+					"status":  "fail",
+					"message": "no-rows",
+				})
+			} else {
+				panic(err)
+			}
+		} else {
+			c.JSON(http.StatusOK, gin.H{
+				"status": "sucess",
+				"data":   comment,
+			})
+			//写入redis
+			jsonData, err := json.Marshal(comment)
+			if err == nil {
+				rdb.HSet(ctx, rkey, c.Param("id"), string(jsonData))
+			}
+		}
+
+	}
+}
+
+//return an HTML form for edit a comment
+func CommentsEdit(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "comment_edit.html", gin.H{
+			"name": "ok",
+		})
+	}
+}
+
+//update a specific comment
+func CommentsUpdate(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		var form Comment
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{
+				"status":  "fail",
+				"message": err.Error(),
+			})
+			return
+		}
+
+		//补充业务逻辑
+		_, err := db.Model(&form).Column("title", "content", "content_type", "status").WherePK().Update()
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   form,
+		})
+		//delete redis
+		rkey := "comment://id"
+		rdb.HDel(ctx, rkey, c.Param("id"))
+	}
+}
+
+//delete a specific comment
+func CommentsDestroy(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		comment := &Comment{
+			Id: int(id),
+		}
+
+		_, err = db.Model(comment).WherePK().Delete()
+		if err != nil {
+			panic(err)
+		}
+
+		rkey := "comment://id"
+		rdb.HDel(ctx, rkey, c.Param("id"))
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   c.Param("id"),
+		})
+
+	}
+}

+ 227 - 86
api/mint/course.go

@@ -1,155 +1,296 @@
 package mint
 
 import (
+	"encoding/json"
+	"fmt"
 	"net/http"
 	"strconv"
-	"fmt"
+	"time"
+
 	"github.com/gin-gonic/gin"
 	"github.com/go-pg/pg/v10"
-	"time"
+	"github.com/go-redis/redis/v8"
 )
 
-
 type Course struct {
-	Id     int `form:"id" json:"id" binding:"required"`
-	Cover string
-	Title string `form:"title" json:"title"`
-	Subtitle string `form:"subtitle" json:"subtitle"`
-	Summary string `form:"summary" json:"summary"`
-	Teacher int `form:"teacher" json:"teacher"`
-	Lang string `form:"lang" json:"lang"`
-	Speech_lang string `form:"speech_lang" json:"speech_lang"`
-	Status int `form:"status" json:"status"`
-	Content string `form:"content" json:"content"`
-	Creator int
-    LessonNum int `form:"lesson_num" json:"lesson_num"`
-    Version int
-    CreatedAt time.Time
-    UpdatedAt time.Time
+	Id          int    `form:"id" json:"id" binding:"required"`
+	Uid         string `form:"uid" json:"uid"`
+	ParentId    int    `form:"parent_id" json:"parent_id"`
+	PrParentId  int    `form:"pr_parent_id" json:"pr_parent_id"`
+	Cover       string
+	Title       string    `form:"title" json:"title"`
+	Subtitle    string    `form:"subtitle" json:"subtitle"`
+	Summary     string    `form:"summary" json:"summary"`
+	TeacherId   int       `form:"teacher" json:"teacher"`
+	Lang        string    `form:"lang" json:"lang"`
+	Speech_lang string    `form:"speech_lang" json:"speech_lang"`
+	LessonNum   int       `form:"lesson_num" json:"lesson_num"`
+	StartAt     time.Time `form:"start_at" json:"start_at"`
+	EndAt       time.Time `form:"end_at" json:"end_at"`
+	Content     string    `form:"content" json:"content"`
+	ContentType string    `form:"content" json:"content_type"`
+	Status      string    `form:"status" json:"status"`
+	EditorId    int       `json:"editor_id"`
+	StudioId    int       `json:"studio_id"`
+	CreatorId   int       `json:"creator_id"`
+	Version     int
+	DeletedAt   time.Time
+	CreatedAt   time.Time
+	UpdatedAt   time.Time
+}
+
+func panicIf(err error) {
+	if err != nil {
+		panic(err)
+	}
 }
-//查询
-func GetCourse(db *pg.DB) gin.HandlerFunc {
+
+//查询display a list of all Courses
+func CoursesIndex(db *pg.DB) gin.HandlerFunc {
 	return func(c *gin.Context) {
-		cid,err := strconv.Atoi(c.Param("cid"))
-		if err != nil {
-			panic(err)
+		//按照标题搜索,或者按照course列出子课程
+		view := c.Query("view")
+		studio := c.DefaultQuery("studio", "")
+		status := c.DefaultQuery("status", "public")
+
+		columns := "id , parent_id , title , subtitle , updated_at"
+		var courses []Course
+		var err error
+		if studio == "" {
+			switch view {
+			case "title":
+				title := c.Query("title")
+				err = db.Model(&courses).ColumnExpr(columns).Where("title like ?", title+"%").Where("status = ?", "public").Select()
+			case "course":
+				err = db.Model(&courses).ColumnExpr(columns).Where("parent_id = 0").Where("status = ?", "public").Select()
+			case "lessson":
+				iCourseId := c.Query("courseid")
+				err = db.Model(&courses).ColumnExpr(columns).Where("parent_id = ?", iCourseId).Where("status = ?", "public").Select()
+			}
+		} else {
+			if status == "all" {
+				// 列出 studio course 全部数据 需要有 member权限
+				//TODO studio 鉴权
+				switch view {
+				case "title":
+					title := c.Query("title")
+					err = db.Model(&courses).ColumnExpr(columns).Where("title like ?", title+"%").Where("studio_id = ?", c.Query("studio")).Select()
+				case "course":
+					err = db.Model(&courses).ColumnExpr(columns).Where("parent_id = 0").Where("studio_id = ?", c.Query("studio")).Select()
+				case "lessson":
+					err = db.Model(&courses).ColumnExpr(columns).Where("parent_id = ?", c.Query("courseid")).Where("studio_id = ?", c.Query("studio")).Select()
+				}
+			} else {
+				// 列出 studio course 全部公开数据
+				switch view {
+				case "title":
+					title := c.Query("title")
+					err = db.Model(&courses).ColumnExpr(columns).Where("title like ?", title+"%").Where("studio_id = ?", c.Query("studio")).Where("status = ?", "public").Select()
+				case "course":
+					err = db.Model(&courses).ColumnExpr(columns).Where("parent_id = 0").Where("studio_id = ?", c.Query("studio")).Where("status = ?", "public").Select()
+				case "lessson":
+					err = db.Model(&courses).ColumnExpr(columns).Where("parent_id = ?", c.Query("courseid")).Where("studio_id = ?", c.Query("studio")).Where("status = ?", "public").Select()
+				}
+			}
+
 		}
-		fmt.Println("get course")
-		// TODO 在这里进行db操作
-		// Select user by primary key.
-		course := &Course{Id: cid}
-		err = db.Model(course).WherePK().Select()
 		if err != nil {
 			panic(err)
 		}
-		
+
 		c.JSON(http.StatusOK, gin.H{
-			"message": "course-"+course.Title,
+			"ok":   true,
+			"data": courses,
 		})
 	}
 }
 
-//查询
-func GetCourseByTitle(db *pg.DB) gin.HandlerFunc {
+//return an HTML form for creating a new Courses
+func CoursesNew(db *pg.DB) gin.HandlerFunc {
 	return func(c *gin.Context) {
-		ctitle:= c.Param("ctitle")
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "courses/new.html", gin.H{
+			"message": "ok",
+		})
+	}
+}
 
-		// TODO 在这里进行db操作
-		// Select user by primary key.
-		var courses []Course
-		err := db.Model(&courses).Column("id","title","subtitle").Where("title like ?",ctitle+"%").Select()
-		if err != nil {
-			panic(err)
+//新建create a new Courses
+func CoursesCreate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		var form Course
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{
+				"ok":    false,
+				"error": err.Error(),
+			})
+			return
+		}
+
+		//TODO studio 鉴权
+
+		if form.Title == "" {
+			c.JSON(http.StatusBadRequest, gin.H{
+				"ok":    false,
+				"error": ":no-title",
+			})
+			return
 		}
-		
+
+		if form.ParentId != 0 {
+			//子课程
+			//先查询母课程是否存在
+			countCourse, err := db.Model((*Course)(nil)).Where("id = ?", form.ParentId).Count()
+			if err != nil {
+				panic(err)
+			}
+			if countCourse == 0 {
+				c.JSON(http.StatusBadRequest, gin.H{
+					"ok":    false,
+					"error": ":no-parent-course",
+				})
+				return
+			}
+		}
+		//TODO 获取 userid
+		form.EditorId = 1
+		form.CreatorId = 1
+
+		_, err := db.Model(&form).Column("title", "status", "studio_id", "editor_id", "creator_id").Insert()
+		panicIf(err)
+
+		//子课程更新母课程LessonNum
+		if form.ParentId != 0 {
+			//获取课程数量
+			countLesson, err := db.Model((*Course)(nil)).Where("parent_id = ?", form.ParentId).Count()
+			if err != nil {
+				panic(err)
+			}
+
+			parentCourse := Course{Id: form.ParentId, LessonNum: countLesson}
+
+			_, err = db.Model(&parentCourse).Column("lesson_num").WherePK().Update()
+			if err != nil {
+				panic(err)
+			}
+		}
+
 		c.JSON(http.StatusOK, gin.H{
-			"message": courses,
+			"ok":   true,
+			"data": form,
 		})
 	}
 }
 
-//新建
-func PutCourse(db *pg.DB) gin.HandlerFunc{
-	return func(c *gin.Context){
-		title := c.Query("title")
-		status1,err := strconv.ParseInt(c.Query("status"),10,64)
+//查询display a specific Courses
+func CoursesShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
 		if err != nil {
 			panic(err)
 		}
-		fmt.Println("title:"+title)
 
-		newCouse := &Course{
-			Title:   title,
-			Status: int(status1),
-			Teacher:1,
-			Creator:1,
+		rkey := "course/:id"
+		n, err := rdb.HExists(ctx, rkey, c.Param("id")).Result()
+		if err == nil && n {
+			val, err := rdb.HGet(ctx, rkey, c.Param("id")).Result()
+			if err == nil {
+				var redisData Course
+				json.Unmarshal([]byte(val), &redisData)
+				c.JSON(http.StatusOK, gin.H{
+					"status": "success",
+					"data":   redisData,
+				})
+				return
+			} else {
+				//有错误
+				fmt.Println("redis error")
+			}
+		} else {
+			fmt.Println("redis error or key not exist")
 		}
-		_, err = db.Model(newCouse).Insert()
+		// Select by primary key.
+
+		course := &Course{Id: id}
+		err = db.Model(course).WherePK().First()
+
 		if err != nil {
 			panic(err)
 		}
-		c.JSON(http.StatusOK,gin.H{
-			"message":"new-Ok- hello "+title,
+
+		c.JSON(http.StatusOK, gin.H{
+			"ok":   true,
+			"data": course,
 		})
+		//写入redis
+		jsonData, err := json.Marshal(course)
+		if err == nil {
+			rdb.HSet(ctx, rkey, c.Param("id"), string(jsonData))
+		}
 	}
 }
 
-//改
-func PostCourse(db *pg.DB) gin.HandlerFunc{
-	return func(c *gin.Context){
-		var form Course
-
-		if err := c.ShouldBindJSON(&form); err != nil {
-			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
-			return
-		}
-
-		_,err := db.Model(&form).Table("courses").Column("title","subtitle","summary","teacher","lang","speech_lang","status","content").WherePK().Update()
-		if err != nil {
-			panic(err)
-		}
-		c.JSON(http.StatusOK,gin.H{
-			"message":"update ok",
+//return an HTML form for edit a Courses
+func CoursesEdit(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "courses/edit.html", gin.H{
+			"message": "ok",
 		})
 	}
 }
 
+//update a specific Courses
 
-//补
-func PatchLessonNumInCousrse(db *pg.DB) gin.HandlerFunc{
-	return func(c *gin.Context){
+func CoursesUpdate(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
 		var form Course
 
 		if err := c.ShouldBindJSON(&form); err != nil {
-			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			c.JSON(http.StatusBadRequest, gin.H{
+				"ok":    false,
+				"error": err.Error(),
+			})
 			return
 		}
 
-		_, err := db.Model(&form).Column("lesson_num").WherePK().Update()
+		_, err := db.Model(&form).Column("title", "subtitle", "summary", "teacher_id", "lang", "speech_lang", "status", "content", "content_type", "start_at", "end_at").WherePK().Update()
 		if err != nil {
 			panic(err)
 		}
-		c.JSON(http.StatusOK,gin.H{
-			"message":"patch ok",
+		c.JSON(http.StatusOK, gin.H{
+			"ok":   true,
+			"data": form,
 		})
+		//delete redis
+		rkey := "course/:id"
+		rdb.HDel(ctx, rkey, c.Param("id"))
 	}
 }
+
 //删
-func DeleteCourse(db *pg.DB) gin.HandlerFunc{
-	return func(c *gin.Context){
-		id,err := strconv.Atoi(c.Param("cid"))
+//delete a specific Courses
+func CoursesDestroy(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
 		if err != nil {
 			panic(err)
 		}
 		course := &Course{
-			Id:   id,
+			Id: id,
 		}
-		_, err = db.Model(course).WherePK().Delete()
+
+		_, err = db.Model(course).WherePK().Where("parent_id = ?", id).Delete()
 		if err != nil {
 			panic(err)
 		}
-		c.JSON(http.StatusOK,gin.H{
-			"message":"delete "+c.Param("cid"),
+		rkey := "course/:id"
+		rdb.HDel(ctx, rkey, c.Param("id"))
+
+		c.JSON(http.StatusOK, gin.H{
+			"ok":   true,
+			"data": course,
 		})
 	}
-}
+}

+ 39 - 0
api/mint/cs_para_number.go

@@ -0,0 +1,39 @@
+package mint
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type CsParanumber struct {
+	Id          int    `json:"id" `
+	BookId      int    `json:"book_id" `
+	Paragraph   int    `json:"paragraph" `
+	SubBookId   int    `json:"sub_book_id" `
+	CsParagraph int    `json:"cs_paragraph" `
+	BookName    string `json:"book_name" `
+	CreatedAt   time.Time
+}
+
+//display a list of all palitexts
+func CsParaNumbersIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		book := c.Query("book")
+		paragraph := c.Query("paragraph")
+
+		// TODO 补充业务逻辑
+		var cs_para_numbers []CsParanumber
+		err := db.Model(&cs_para_numbers).Where("book_id = ?", book).Where("paragraph = ?", paragraph).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   cs_para_numbers,
+		})
+	}
+}

+ 212 - 0
api/mint/dictionaries.go

@@ -0,0 +1,212 @@
+package mint
+
+import (
+	"net/http"
+	"strconv"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+	"time"
+)
+
+
+type Dictionary struct {
+	Id     int `form:"id" json:"id" `
+	Word string `form:"word" json:"word" `
+	Type string `form:"type" json:"type"`
+	Grammar string `form:"grammar" json:"grammar"`
+	Base string `form:"base" json:"base"`
+
+	Meaning string `form:"meaning" json:"meaning"`
+	Note string `form:"note" json:"note"`
+	Factors string `form:"factors" json:"factors"`
+	FactorsMeaning string `form:"factors_meaning" json:"factors_meaning"`
+	Lang string `form:"lang" json:"lang"`
+	Sourse string `form:"sourse" json:"sourse"`
+
+	OwnerId int
+	Version int
+    DeletedAt time.Time
+    CreatedAt time.Time
+    UpdatedAt time.Time
+}
+
+
+//display a list of all dictionaries
+func DictionariesIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		word:= c.DefaultQuery("word","")
+
+		// TODO 补充业务逻辑
+		var dictionaries []Dictionary
+		err := db.Model(&dictionaries).Column("id","word","type","grammar","meaning").Where("word = ? ",word).Select()
+		if err != nil {
+			panic(err)
+		}
+		
+		c.JSON(http.StatusOK, gin.H{
+			"message":"success",
+			"data": dictionaries,
+		})
+	}
+}
+
+//return an HTML form for creating a new dictionary
+func DictionariesNew(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK,"dictionaries/new.html",gin.H{
+			"message":"ok",
+		})
+	}
+}
+//create a new dictionary
+func DictionariesCreate(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+	
+		var form Dictionary
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+		form.OwnerId = 1
+		//TODO补充业务逻辑
+		_, err := db.Model(&form).Insert()
+		if err != nil {
+			panic(err)
+		}
+
+		//建立成功
+		c.JSON(http.StatusOK,gin.H{
+			"message":"success",
+			"data":form,
+		})
+	}
+}
+
+//display a specific Dictionary
+func DictionariesShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id,err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		fmt.Println("get dictionary id=" + c.Param("id"))
+		rkey := "dictionary://id/"+c.Param("id")
+		n, err := rdb.Exists(ctx,rkey).Result()
+		if err != nil  {
+			fmt.Println(err)
+		}else if n == 0 {
+			fmt.Println("redis key not exist")
+		}else{
+			fmt.Println("redis key exist")
+			val, err := rdb.HGetAll(ctx, rkey).Result()
+			if err != nil || val == nil {
+				//有错误或者没查到
+				fmt.Println("redis error")
+					
+			}else{
+				fmt.Println("redis no error")
+				c.JSON(http.StatusOK, gin.H{
+					"data": val,
+				})
+				return
+			}	
+		}
+
+		dictionary := &Dictionary{Id: id}
+		err = db.Model(dictionary).Column("id","uid","name","description","description_type","owner_id","setting","status","version","updated_at").WherePK().Select()
+		if err != nil {
+			panic(err)
+		}			
+
+		//写入redis
+		rdb.HSet(ctx,rkey,"id",dictionary.Id)
+		rdb.HSet(ctx,rkey,"word",dictionary.Word)
+		rdb.HSet(ctx,rkey,"type",dictionary.Type)
+		rdb.HSet(ctx,rkey,"grammar",dictionary.Grammar)
+		rdb.HSet(ctx,rkey,"base",dictionary.Base)
+		rdb.HSet(ctx,rkey,"meaning",dictionary.Meaning)
+		rdb.HSet(ctx,rkey,"note",dictionary.Note)
+		rdb.HSet(ctx,rkey,"factors",dictionary.Factors)
+		rdb.HSet(ctx,rkey,"factors_meaning",dictionary.FactorsMeaning)
+		rdb.HSet(ctx,rkey,"lang",dictionary.Lang)
+		rdb.HSet(ctx,rkey,"sourse",dictionary.Sourse)
+		rdb.HSet(ctx,rkey,"updated_at",dictionary.UpdatedAt)
+
+		c.JSON(http.StatusOK, gin.H{
+			"message":"success",
+			"data": dictionary,
+		})		
+			
+	}
+}
+
+//return an HTML form for edit a dictionary
+func DictionariesEdit(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK,"dictionaries/edit.html",gin.H{
+			"name":"ok",
+		})
+	}
+}
+
+//update a specific dictionary
+func DictionariesUpdate(db *pg.DB,rdb *redis.Client) gin.HandlerFunc{
+	return func(c *gin.Context){
+		var form Dictionary
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+
+		//补充业务逻辑
+		_,err := db.Model(&form).Column("type","grammar","base","meaning","note","factors","factors_meaning","lang","sourse").WherePK().Update()
+		if err != nil {
+			panic(err)
+		}
+		//delete redis
+		rkey := "dictionary://id/"+strconv.Itoa(form.Id)
+		rdb.Del(ctx,rkey)	
+
+		c.JSON(http.StatusOK,gin.H{
+			"message":"success",
+			"data":form,
+		})
+
+	}
+}
+
+
+//delete a specific dictionary
+func DictionariesDestroy(db *pg.DB ,rdb *redis.Client) gin.HandlerFunc{
+	return func(c *gin.Context){
+		id,err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		dictionary := &Dictionary{
+			Id:int(id),
+		}
+
+		_, err = db.Model(dictionary).WherePK().Delete()
+		if err != nil {
+			panic(err)
+		}
+
+		rkey := "dictionary://id/"+c.Param("id")
+		rdb.Del(ctx,rkey)
+		
+		c.JSON(http.StatusOK,gin.H{
+			"message": "success",
+			"data":c.Param("id"),
+		})
+
+
+
+	}
+}

+ 207 - 0
api/mint/group.go

@@ -0,0 +1,207 @@
+package mint
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"strconv"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+	"github.com/google/uuid"
+)
+
+type Group struct {
+	Id              int    `form:"id" json:"id" `
+	Uid             string `form:"uid" json:"uid" `
+	Name            string `form:"name" json:"name"`
+	Description     string `form:"description" json:"description"`
+	DescriptionType string `form:"description_type" json:"description_type"`
+	Setting         string `form:"setting" json:"setting"`
+	Status          string `form:"status" json:"status"`
+	OwnerId         int
+	Version         int
+	DeletedAt       time.Time
+	CreatedAt       time.Time
+	UpdatedAt       time.Time
+}
+
+//display a list of all groups
+func GroupsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		view := c.Query("view")
+		switch view {
+		case "owner":
+		case "write":
+		case "read":
+		}
+		// TODO 补充业务逻辑
+		var groups []Group
+		err := db.Model(&groups).Column("id", "uid", "name").Where("owner_id = ?", 1).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "success",
+			"data":   groups,
+		})
+	}
+}
+
+//return an HTML form for creating a new group
+func GroupsNew(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "group_new.html", gin.H{
+			"message": "ok",
+		})
+	}
+}
+
+//create a new group
+func GroupsCreate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		name := c.Query("name")
+		status := c.DefaultQuery("status", "private")
+
+		newGroup := &Group{
+			Uid:     uuid.New().String(),
+			Name:    name,
+			Status:  status,
+			OwnerId: 1, //TODO user_id
+		}
+		_, err := db.Model(newGroup).Column("name", "status").Insert()
+		if err != nil {
+			panic(err)
+		}
+
+		//建立成功
+		c.JSON(http.StatusOK, gin.H{
+			"status": "success",
+			"data":   newGroup,
+		})
+	}
+}
+
+//display a specific Group
+func GroupsShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+
+		rkey := "group://id"
+		n, err := rdb.HExists(ctx, rkey, c.Param("id")).Result()
+		if err == nil && n {
+			val, err := rdb.HGet(ctx, rkey, c.Param("id")).Result()
+			if err == nil {
+				var redisData Group
+				json.Unmarshal([]byte(val), &redisData)
+				c.JSON(http.StatusOK, gin.H{
+					"status": "success",
+					"data":   redisData,
+				})
+				return
+			} else {
+				fmt.Println(err)
+			}
+		} else {
+			fmt.Println(err)
+		}
+
+		group := &Group{Id: id}
+		err = db.Model(group).Column("id", "uid", "name", "description", "description_type", "owner_id", "setting", "status", "version", "updated_at").WherePK().First()
+		if err != nil {
+			if err.Error() == pg.ErrNoRows.Error() {
+				c.JSON(http.StatusOK, gin.H{
+					"status":  "fail",
+					"message": "no-rows",
+				})
+			} else {
+				panic(err)
+			}
+		} else {
+			c.JSON(http.StatusOK, gin.H{
+				"status": "sucess",
+				"data":   group,
+			})
+			//写入redis
+			jsonData, err := json.Marshal(group)
+			if err == nil {
+				rdb.HSet(ctx, rkey, c.Param("id"), string(jsonData))
+			}
+		}
+
+	}
+}
+
+//return an HTML form for edit a group
+func GroupsEdit(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "groups_edit.html", gin.H{
+			"name": "ok",
+		})
+	}
+}
+
+//update a specific group
+func GroupsUpdate(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		var form Group
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{
+				"status":  "fail",
+				"message": err.Error(),
+			})
+			return
+		}
+
+		//补充业务逻辑
+		_, err := db.Model(&form).Column("name", "description", "description_type", "status", "setting").WherePK().Update()
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   form,
+		})
+		//delete redis
+		rkey := "group://id"
+		rdb.HDel(ctx, rkey, c.Param("id"))
+	}
+}
+
+//delete a specific group
+func GroupsDestroy(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		group := &Group{
+			Id: id,
+		}
+
+		_, err = db.Model(group).WherePK().Delete()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   c.Param("id"),
+		})
+
+		rkey := "group://id"
+		rdb.Del(ctx, rkey, c.Param("id"))
+
+	}
+}

+ 90 - 0
api/mint/group_user.go

@@ -0,0 +1,90 @@
+package mint
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+)
+
+type GroupsUser struct {
+	Id        int `form:"id" json:"id" `
+	GroupId   int `form:"group_id" json:"group_id" `
+	UserId    int `form:"user_id" json:"user_id" `
+	CreatedAt time.Time
+}
+
+//display a list of all groups
+func GroupsUsersIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		var dbData []GroupsUser
+		view := c.Query("view")
+
+		switch view {
+		case "group":
+			err := db.Model(&dbData).Column("uid", "name").Where("group_id = ?", c.Query("group")).Select()
+			panicIf(err)
+		case "user":
+			err := db.Model(&dbData).Column("uid", "name").Where("user_id = ?", c.Query("user")).Select()
+			panicIf(err)
+		}
+		// TODO 补充业务逻辑
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "success",
+			"data":   dbData,
+		})
+	}
+}
+
+//create a new group-user
+func GroupsUsersCreate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		var form GroupsUser
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{
+				"status":  "fail",
+				"message": err.Error(),
+			})
+			return
+		}
+		_, err := db.Model(form).Column("group_id", "user_id").Insert()
+		if err != nil {
+			panic(err)
+		}
+
+		//建立成功
+		c.JSON(http.StatusOK, gin.H{
+			"status": "success",
+			"data":   form,
+		})
+	}
+}
+
+//delete a specific group-user
+func GroupsUsersDestroy(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		groupId := c.Query("group")
+		userId := c.DefaultQuery("user", "")
+
+		if userId == "" {
+			//删除整个组
+			_, err := db.Model((*GroupsUser)(nil)).Where("group_id = ?", groupId).Delete()
+			panicIf(err)
+		} else {
+			//删除一个成员
+			_, err := db.Model((*GroupsUser)(nil)).Where("group_id = ?", groupId).Where("user_id = ?", userId).Delete()
+			panicIf(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   groupId,
+		})
+
+	}
+}

+ 0 - 200
api/mint/lesson.go

@@ -1,200 +0,0 @@
-package mint
-
-import (
-	"net/http"
-	"io/ioutil"
-	/*"strings"*/
-	"bytes"
-	"encoding/json"
-	"strconv"
-	"fmt"
-	"github.com/gin-gonic/gin"
-	"github.com/go-pg/pg/v10"
-	"time"
-)
-
-type Lesson struct {
-	Id     int `form:"id" json:"id" binding:"required"`
-	CourseId     int `form:"course_id" json:"course_id" binding:"required"`
-	Cover string
-	Title string `form:"title" json:"title" binding:"required"`
-	Subtitle string `form:"subtitle" json:"subtitle" binding:"required"`
-	Summary string `form:"summary" json:"summary" binding:"required"`
-	Teacher int `form:"teacher" json:"teacher" binding:"required"`
-	Lang string `form:"lang" json:"lang" binding:"required"`
-	Speech_lang string `form:"speech_lang" json:"speech_lang" binding:"required"`
-	Status int `form:"status" json:"status" binding:"required"`
-	Content string `form:"content" json:"content" binding:"required"`
-	Creator int
-	StartDate time.Time `form:"date" json:"date" binding:"required"`
-    Duration int64 `form:"duration" json:"duration" binding:"required"` 
-	Version int64
-    CreatedAt time.Time
-    UpdatedAt time.Time
-}
-//查询
-func GetLesson(db *pg.DB) gin.HandlerFunc {
-	return func(c *gin.Context) {
-		lid,err := strconv.ParseInt(c.Param("lid"),10,64)
-		if err != nil {
-			panic(err)
-		}
-		fmt.Println("get lesson")
-		// TODO 在这里进行db操作
-		// Select user by primary key.
-		lesson := &Lesson{Id: int(lid)}
-		err = db.Model(lesson).WherePK().Select()
-		if err != nil {
-			panic(err)
-		}
-		
-		c.JSON(http.StatusOK, gin.H{
-			"message": "lesson-"+lesson.Title,
-		})
-	}
-}
-
-//查询
-func GetLessonByTitle(db *pg.DB) gin.HandlerFunc {
-	return func(c *gin.Context) {
-		title:= c.Param("ltitle")
-
-		// TODO 在这里进行db操作
-		// Select user by primary key.
-		var lessons []Lesson
-		err := db.Model(&lessons).Column("id","title","subtitle").Where("title like ?",title+"%").Select()
-		if err != nil {
-			panic(err)
-		}
-		
-		c.JSON(http.StatusOK, gin.H{
-			"message": lessons,
-		})
-	}
-}
-
-/*新建
-新建课以后,查询这个course 里有几个lesson 然后更新 courese 的 lesson_num
-*/
-//PUT http://127.0.0.1:8080/api/lesson?title=lesson-one&course_id=1&status=10
-func PutLesson(db *pg.DB) gin.HandlerFunc{
-	return func(c *gin.Context){
-	
-		title := c.Query("title")
-		courseId,err := strconv.Atoi(c.Query("course_id"))
-		status1,err := strconv.Atoi(c.Query("status"))
-		if err != nil {
-			panic(err)
-		}
-
-		newLesson := &Lesson{
-			Title:   title,
-			CourseId: courseId,
-			Status: status1,
-			Teacher:0,
-			Creator:1,
-		}
-		_, err = db.Model(newLesson).Insert()
-		if err != nil {
-			panic(err)
-		}
-		//修改 course 的 lesson_num
-		courseMessage := _updateLessonCount(db,courseId)
-		
-		c.JSON(http.StatusOK,gin.H{
-			"message":courseMessage,
-		})
-	}
-}
-
-func _updateLessonCount(db *pg.DB,courseId int) string{
-			//查询这个course 里面有几个课程
-			countLesson, err := db.Model((*Lesson)(nil)).Where("course_id = ?",courseId).Count()
-			if err != nil {
-				panic(err)
-			}		
-	
-			//修改course lesson number
-			url := "http://127.0.0.1:8080/api/course/lessonnum"
-			values := Course{
-				Id : courseId,
-				LessonNum : countLesson,
-			}
-			json_data, err := json.Marshal(values);
-			if err != nil {
-				panic(err)
-			}
-	
-			client := &http.Client{}
-			req, err := http.NewRequest("PATCH",url, bytes.NewBuffer(json_data))
-			if err != nil {
-				panic(err)
-			}
-			req.Header.Set("Content-Type","application/json")
-			resp,err := client.Do(req)
-			if err != nil {
-				panic(err)
-			}
-			 defer resp.Body.Close()
-			b, err := ioutil.ReadAll(resp.Body)
-			if err != nil {
-				panic(err)
-			}
-	
-		return(string(b))
-}
-
-//改
-func PostLesson(db *pg.DB) gin.HandlerFunc{
-	return func(c *gin.Context){
-		var form Lesson
-
-		if err := c.ShouldBindJSON(&form); err != nil {
-			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
-			return
-		}
-
-		_,err := db.Model(&form).Table("lessons").Column("title","subtitle","summary","teacher","tag","lang","speech_lang","status","content","start_date","duration").WherePK().Update()
-		if err != nil {
-			panic(err)
-		}
-		c.JSON(http.StatusOK,gin.H{
-			"message":"update ok",
-		})
-	}
-}
-
-
-//删
-func DeleteLesson(db *pg.DB) gin.HandlerFunc{
-	return func(c *gin.Context){
-		id,err := strconv.ParseInt(c.Param("lid"),10,64)
-		if err != nil {
-			panic(err)
-		}
-		lesson := &Lesson{
-			Id:int(id),
-			CourseId: int(0) ,
-		}
-		//删之前获取 course_id
-		err = db.Model(lesson).Column("course_id").WherePK().Select()
-		if err != nil {
-			panic(err)
-		}
-		course_id := lesson.CourseId
-
-		_, err = db.Model(lesson).WherePK().Delete()
-		if err != nil {
-			panic(err)
-		}
-
-		//修改 course 的 lesson_num
-		courseMessage := _updateLessonCount(db,course_id)
-
-	
-		c.JSON(http.StatusOK,gin.H{
-			"message":"delete "+c.Param("lid"),
-			"lesson_num":courseMessage,
-		})
-	}
-}

+ 91 - 0
api/mint/like.go

@@ -0,0 +1,91 @@
+package mint
+
+import (
+	"net/http"
+	"strconv"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type Like struct {
+	Id int `form:"id" json:"id" binding:"required"`
+
+	LikeType string `form:"like_type" json:"like_type"`
+
+	ResourceId   string `form:"resource_id" json:"resource_id"`
+	ResourceType string `form:"resource_type" json:"resource_type"`
+
+	UserId int    `form:"user_id" json:"user_id"`
+	Emoji  string `form:"emoji" json:"emoji"`
+
+	CreatedAt time.Time
+}
+
+//查询display a list of all Likes
+func LikesIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//按照标题搜索
+		resource_id := c.Query("resource_id")
+		resource_type := c.Query("resource_type")
+
+		// TODO 在这里进行db操作
+		// Select user by primary key.
+		var likes []Like
+
+		err := db.Model(&likes).Column("id", "resource_id", "resource_type", "like_type", "user_id", "emoji").Where("resource_id = ?", resource_id).Where("resource_type = ?", resource_type).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"message": likes,
+		})
+	}
+}
+
+//新建create a new Likes
+func LikesCreate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		var form Channel
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+		_, err := db.Model(&form).Insert()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   form,
+		})
+	}
+}
+
+//删
+//delete a specific Likes
+func LikesDestroy(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		like := &Like{
+			Id: id,
+		}
+
+		_, err = db.Model(like).WherePK().Delete()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"message": c.Param("id"),
+		})
+	}
+}

+ 39 - 0
api/mint/multi_edition_page_number.go

@@ -0,0 +1,39 @@
+package mint
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type MultiEditionPageNumber struct {
+	Id        int    `json:"id" `
+	Edition   string `json:"edition" `
+	BookId    int    `json:"book_id" `
+	Paragraph int    `json:"paragraph" `
+	Vol       int    `json:"vol" `
+	Page      string `json:"page" `
+	CreatedAt time.Time
+}
+
+//display a list of all palitexts
+func MultiEditionPageNumbersIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		book := c.Query("book")
+		paragraph := c.Query("paragraph")
+
+		// TODO 补充业务逻辑
+		var multi_edition_page_numbers []MultiEditionPageNumber
+		err := db.Model(&multi_edition_page_numbers).Where("book_id = ?", book).Where("paragraph = ?", paragraph).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   multi_edition_page_numbers,
+		})
+	}
+}

+ 41 - 0
api/mint/nissaya_book_map.go

@@ -0,0 +1,41 @@
+package mint
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type NissayaBookMap struct {
+	Id int `json:"id" `
+
+	NsyBookId int    `json:"nsy_book_id" `
+	BookId    int    `json:"book_id" `
+	Vol       int    `json:"vol" `
+	Title     string `json:"title" `
+	Type      string `json:"type" `
+
+	CreatedAt time.Time
+}
+
+//display a list of all palitexts
+func NissayaBookMapsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		book := c.Query("book")
+		paragraph := c.Query("paragraph")
+
+		// TODO 补充业务逻辑
+		var nissaya_book_maps []NissayaBookMap
+		err := db.Model(&nissaya_book_maps).Where("book_id = ?", book).Where("paragraph = ?", paragraph).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   nissaya_book_maps,
+		})
+	}
+}

+ 40 - 0
api/mint/nissaya_page_map.go

@@ -0,0 +1,40 @@
+package mint
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type NissayaPageMap struct {
+	Id             int    `json:"id" `
+	Type           string `json:"type" `
+	NsyBookId      int    `json:"nsy_book_id" `
+	BookPageNumber int    `json:"book_page_number" `
+	NsyId          int    `json:"nsy_id" `
+	NsyPageNumber  string `json:"nsy_page_number" `
+	NsyName        string `json:"nsy_name" `
+	CreatedAt      time.Time
+}
+
+//display a list of all palitexts
+func NissayaPageMapsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		book := c.Query("book")
+		paragraph := c.Query("paragraph")
+
+		// TODO 补充业务逻辑
+		var nissaya_page_maps []NissayaPageMap
+		err := db.Model(&nissaya_page_maps).Where("book_id = ?", book).Where("paragraph = ?", paragraph).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   nissaya_page_maps,
+		})
+	}
+}

+ 60 - 0
api/mint/pali_text.go

@@ -0,0 +1,60 @@
+package mint
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type PaliTextPath struct {
+	Title     string `json:"title" `
+	Book      int    `json:"book" `
+	Paragraph int    `json:"paragraph" `
+}
+
+type PaliText struct {
+	Id int `form:"id" json:"id" `
+
+	BookId    int
+	Paragraph int
+	Level     int
+	Class     string
+
+	Text string
+	Html string
+	Toc  string
+
+	StrLength     int
+	ChapterLen    int
+	NextChapter   int
+	PrevChapter   int
+	Parent        int
+	ChapterStrlen int
+	Path          []PaliTextPath
+
+	Version int
+
+	CreatedAt time.Time
+	UpdatedAt time.Time
+}
+
+//display a list of all palitexts
+func PaliTextsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		book := c.Query("book")
+
+		// TODO 补充业务逻辑
+		var palitexts []PaliText
+		err := db.Model(&palitexts).Where("book = ?", book).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   palitexts,
+		})
+	}
+}

+ 39 - 0
api/mint/pali_word.go

@@ -0,0 +1,39 @@
+package mint
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type PaliWord struct {
+	Id              int    `json:"id" `
+	BookId          int    `json:"book_id" `
+	Paragraph       int    `json:"paragraph" `
+	PaliWordIndexId int    `json:"pali_word_index_id" `
+	IsBase          bool   `json:"is_base" `
+	Weight          string `json:"weight" `
+	CreatedAt       time.Time
+}
+
+//display a list of all palitexts
+func PaliWordsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		book := c.Query("book")
+		paragraph := c.Query("paragraph")
+
+		// TODO 补充业务逻辑
+		var pali_words []PaliWord
+		err := db.Model(&pali_words).Where("book_id = ?", book).Where("paragraph = ?", paragraph).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   pali_words,
+		})
+	}
+}

+ 42 - 0
api/mint/pali_word_index.go

@@ -0,0 +1,42 @@
+package mint
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type PaliWordIndex struct {
+	Id        int    `json:"id" `
+	Word      int    `json:"word" `
+	BookId    int    `json:"book_id" `
+	WordEn    int    `json:"word_en" `
+	Count     string `json:"count" `
+	Normal    string `json:"normal" `
+	Bold      string `json:"bold" `
+	IsBase    bool   `json:"is_base" `
+	StrLen    string `json:"str_len" `
+	CreatedAt time.Time
+}
+
+//display a list of all palitexts
+func PaliWordIndexsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		book := c.Query("book")
+		paragraph := c.Query("paragraph")
+
+		// TODO 补充业务逻辑
+		var pali_word_indexs []PaliWordIndex
+		err := db.Model(&pali_word_indexs).Where("book_id = ?", book).Where("paragraph = ?", paragraph).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   pali_word_indexs,
+		})
+	}
+}

+ 98 - 0
api/mint/refdicts.go

@@ -0,0 +1,98 @@
+package mint
+
+import (
+	"net/http"
+	"strconv"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+	"time"
+)
+
+
+type RefDict struct {
+	Id     int `form:"id" json:"id" `
+	Word string `form:"word" json:"word" `
+	WordEn string `form:"type" json:"type"`
+
+	Meaning string `form:"meaning" json:"meaning"`
+	Lang string `form:"lang" json:"lang"`
+
+	RefDictNameId int
+    CreatedAt time.Time
+}
+
+
+//display a list of all dictionaries
+func RefDictsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		word:= c.DefaultQuery("word","")
+
+		// TODO 补充业务逻辑
+		var dictionaries []RefDict
+		err := db.Model(&dictionaries).Column("id","word","type","grammar","meaning").Where("word = ? ",word).Select()
+		if err != nil {
+			panic(err)
+		}
+		
+		c.JSON(http.StatusOK, gin.H{
+			"message":"success",
+			"data": dictionaries,
+		})
+	}
+}
+
+
+//display a specific RefDict
+func RefDictsShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id,err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		fmt.Println("get refdict id=" + c.Param("id"))
+		rkey := "refdict://id/"+c.Param("id")
+		n, err := rdb.Exists(ctx,rkey).Result()
+		if err != nil  {
+			fmt.Println(err)
+		}else if n == 0 {
+			fmt.Println("redis key not exist")
+		}else{
+			fmt.Println("redis key exist")
+			val, err := rdb.HGetAll(ctx, rkey).Result()
+			if err != nil || val == nil {
+				//有错误或者没查到
+				fmt.Println("redis error")
+					
+			}else{
+				fmt.Println("redis no error")
+				c.JSON(http.StatusOK, gin.H{
+					"data": val,
+				})
+				return
+			}	
+		}
+
+		refdict := &RefDict{Id: id}
+		err = db.Model(refdict).Column("id","uid","name","description","description_type","owner_id","setting","status","version","updated_at").WherePK().Select()
+		if err != nil {
+			panic(err)
+		}			
+
+		//写入redis
+		rdb.HSet(ctx,rkey,"id",refdict.Id)
+		rdb.HSet(ctx,rkey,"word",refdict.Word)
+		rdb.HSet(ctx,rkey,"word_en",refdict.WordEn)
+		rdb.HSet(ctx,rkey,"meaning",refdict.Meaning)
+		rdb.HSet(ctx,rkey,"lang",refdict.Lang)
+		rdb.HSet(ctx,rkey,"ref_dict_name_id",refdict.RefDictNameId)
+
+		c.JSON(http.StatusOK, gin.H{
+			"message":"success",
+			"data": refdict,
+		})		
+			
+	}
+}
+

+ 246 - 0
api/mint/sentence.go

@@ -0,0 +1,246 @@
+package mint
+
+import (
+	"net/http"
+	"strconv"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+	"time"
+	"encoding/json"
+)
+
+
+type Sentence struct {
+	Id     int `form:"id" json:"id" `
+	IsPr bool `form:"is_pr" json:"is_pr" `
+	BlockId string `form:"block_id" json:"block_id"`
+	
+	ChannelId int `form:"channel_id" json:"channel_id"`
+	BookId int `form:"book_id" json:"book_id"`
+	Paragraph int `form:"paragraph" json:"paragraph"`
+	WordStart int `form:"word_start" json:"word_start"`
+	WordEnd int `form:"word_end" json:"word_end"`
+
+	Content string `form:"content" json:"content"`
+	ContentType string `form:"content_type" json:"content_type"`
+	
+	Type string `form:"type" json:"type"`
+	Lang string `form:"lang" json:"lang"`
+	Status string `form:"status" json:"status"`
+
+	EditorId int
+	OwnerId int
+
+	Version int
+    DeletedAt time.Time
+
+    CreatedAt time.Time
+    UpdatedAt time.Time
+}
+type SentenceHolder struct{
+	Data []Sentence
+}
+func (i *SentenceHolder) UnmarshalJSON(b []byte) error{
+	return json.Unmarshal(b, &i.Data)
+}
+
+//display a list of all sentences
+func SentencesIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		active:= c.Query("active")
+
+		// TODO 补充业务逻辑
+		var sentences []Sentence
+		switch active {
+			case "channel":
+				//某channel句子列表
+				channel := c.Query("channel")
+
+				//request body sentence array with book para star end
+			var form SentenceHolder
+
+			if err := c.ShouldBindJSON(&form); err != nil {
+				c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+				return
+			}
+			sentences = make([]Sentence,0,len(form.Data))
+			var oneSent Sentence
+			count := 0 
+			for _, value := range form.Data{
+				err := db.Model(&oneSent).Column("id","book_id","paragraph","word_start","word_end","content","content_type").Where("channel = ?",channel).Where("book_id = ?",value.BookId).Where("paragraph = ?",value.Paragraph).Where("word_start = ?",value.WordStart).Where("word_end = ?",value.WordEnd).First()
+				//errors.Is(err, gorm.ErrRecordNotFound)
+				if err != nil {
+					panic(err)
+				}
+
+				sentences[count] = oneSent
+			}
+			case "sentence": 
+			//某句子所有channel记录
+				book_id := c.Query("book")
+				para := c.Query("para")
+				start := c.Query("start")
+				end := c.Query("end")
+				err := db.Model(&sentences).Column("id","book_id","paragraph","word_start","word_end","content","content_type").Where("book_id = ?",book_id).Where("paragraph = ?",para).Where("word_start = ?",start).Where("word_end = ?",end).Select()
+				if err != nil {
+					panic(err)
+				}
+	
+		}
+		
+		c.JSON(http.StatusOK, gin.H{
+			"status":"succes",
+			"message":"",
+			"data": sentences,
+		})
+	}
+}
+
+//return an HTML form for creating a new sentence
+func SentencesNew(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK,"sentences_new.html",gin.H{
+			"message":"ok",
+		})
+	}
+}
+
+
+//create new sentence
+func SentencesCreate(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+		//channel := c.Query("channel")
+		active := c.Query("active")
+
+		var form SentenceHolder
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+		//TODO 查询权限
+		switch active {
+		case "create":
+		case "pr":
+		}
+/*
+		_, err := db.Model(newSentence).Insert()
+		if err != nil {
+			panic(err)
+		}
+*/
+		//建立成功
+		c.JSON(http.StatusOK,gin.H{
+			"status":"succes",
+			"message":"",
+			"data":form.Data,
+		})
+	}
+}
+
+//display a specific Sentence
+func SentencesShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id,err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		fmt.Println("get sentence id=" + c.Param("id"))
+		rkey := "sentence://id"
+		n, err := rdb.Exists(ctx,rkey).Result()
+		if err != nil  {
+			fmt.Println(err)
+		}else if n == 0 {
+			fmt.Println("redis key not exist")
+		}else{
+			fmt.Println("redis key exist")
+			val, err := rdb.HGetAll(ctx, rkey).Result()
+			if err != nil || val == nil {
+				//有错误或者没查到
+				fmt.Println("redis error")
+					
+			}else{
+				fmt.Println("redis no error")
+				c.JSON(http.StatusOK, gin.H{
+					"data": val,
+				})
+				return
+			}	
+		}
+
+		sentence := &Sentence{Id: id}
+		err = db.Model(sentence).Column("id","uid","name","description","description_type","owner_id","setting","status","version","updated_at").WherePK().Select()
+		if err != nil {
+			panic(err)
+		}			
+		c.JSON(http.StatusOK, gin.H{
+			"data": sentence,
+		})
+		//写入redis
+		rdb.HSet(ctx,rkey,id,sentence)
+
+	}
+}
+
+//return an HTML form for edit a sentence
+func SentencesEdit(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK,"sentences_edit.html",gin.H{
+			"name":"ok",
+		})
+	}
+}
+//update a specific sentence
+func SentencesUpdate(db *pg.DB,rdb *redis.Client) gin.HandlerFunc{
+	return func(c *gin.Context){
+		var form Sentence
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+
+		//补充业务逻辑
+		_,err := db.Model(&form).Column("name","description","description_type","status","setting").WherePK().Update()
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK,gin.H{
+			"message":form,
+		})
+		//delete redis
+		rkey := "sentence://id/"+strconv.Itoa(form.Id)
+		rdb.Del(ctx,rkey)
+	}
+}
+
+
+//delete a specific sentence
+func SentencesDestroy(db *pg.DB ,rdb *redis.Client) gin.HandlerFunc{
+	return func(c *gin.Context){
+		id,err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		sentence := &Sentence{
+			Id:int(id),
+		}
+		//删之前获取 course_id
+		_, err = db.Model(sentence).WherePK().Delete()
+		if err != nil {
+			panic(err)
+		}
+		//删除article_list表相关项目
+		c.JSON(http.StatusOK,gin.H{
+			"message": c.Param("id"),
+		})
+
+		rkey := "sentence://id/"+c.Param("id")
+		rdb.Del(ctx,rkey)
+
+	}
+}

+ 88 - 0
api/mint/sentences_historay.go

@@ -0,0 +1,88 @@
+package mint
+
+import (
+	"net/http"
+	"strconv"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+)
+
+type SentencesHistoray struct {
+	Id          int    `form:"id" json:"id" `
+	SentenceId  int    `form:"sentence_id" json:"sentence_id" `
+	Content     string `form:"content" json:"content" `
+	ContentType string `form:"content_type" json:"content_type"`
+
+	EditorId int
+
+	CreatedAt time.Time
+}
+
+//display a list of all sentencesHistorays
+func SentencesHistoraiesIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		sentence_id := c.Query("sentence_id")
+
+		// TODO 补充业务逻辑
+		var sentencesHistorays []SentencesHistoray
+		err := db.Model(&sentencesHistorays).Column("id", "sentence_id", "content", "content_type", "editor_id", "created_at").Where("sentence_id = ?", sentence_id).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "success",
+			"data":   sentencesHistorays,
+		})
+	}
+}
+
+//create a new sentencesHistoray
+func SentencesHistoraiesCreate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		var form SentencesHistoray
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+		form.EditorId = 1
+		//TODO补充业务逻辑
+		_, err := db.Model(&form).Insert()
+		if err != nil {
+			panic(err)
+		}
+
+		//建立成功
+		c.JSON(http.StatusOK, gin.H{
+			"status": "success",
+			"data":   form,
+		})
+	}
+}
+
+//display a specific SentencesHistoray
+func SentencesHistoraiesShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+
+		sentencesHistoray := &SentencesHistoray{Id: id}
+		err = db.Model(sentencesHistoray).Column("id", "sentence_id", "content", "content_type", "editor_id", "created_at").WherePK().First()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "success",
+			"data":   sentencesHistoray,
+		})
+
+	}
+}

+ 38 - 0
api/mint/subbook.go

@@ -0,0 +1,38 @@
+package mint
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type SubBook struct {
+	Id        int    `json:"id" `
+	BookId    int    `json:"book_id" `
+	Paragraph int    `json:"paragraph" `
+	Title     string `json:"title" `
+	SetTitle  string `json:"set_title" `
+	CreatedAt time.Time
+}
+
+//display a list of all palitexts
+func SubBooksIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		book := c.Query("book")
+		paragraph := c.Query("paragraph")
+
+		// TODO 补充业务逻辑
+		var subBook []SubBook
+		err := db.Model(&subBook).Where("book_id = ?", book).Where("paragraph = ?", paragraph).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   subBook,
+		})
+	}
+}

+ 216 - 0
api/mint/term.go

@@ -0,0 +1,216 @@
+package mint
+
+import (
+	"net/http"
+	"strconv"
+	"fmt"
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+	"time"
+)
+
+
+type Term struct {
+	Id     int `form:"id" json:"id" `
+	PrParentId     int `form:"pr_parent_id" json:"pr_parent_id" `
+	Word string `form:"word" json:"word" `
+	WordEn string `form:"word_en" json:"word_en"`
+	Tag string `form:"tag" json:"tag"`
+	ChannelId string `form:"channel_id" json:"channel_id"`
+
+	Meaning string `form:"meaning" json:"meaning"`
+	Meaning2 string `form:"meaning2" json:"meaning2"`
+	Note string `form:"note" json:"note"`
+	Lang string `form:"lang" json:"lang"`
+	Sourse string `form:"sourse" json:"sourse"`
+
+	Confidence int `form:"confidence" json:"confidence"`
+
+	OwnerId int
+	Version int
+    CreatedAt time.Time
+    UpdatedAt time.Time
+}
+
+
+//display a list of all terms
+func TermsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		word:= c.DefaultQuery("word","")
+
+		// TODO 补充业务逻辑
+		var terms []Term
+		err := db.Model(&terms).Column("id","word","type","grammar","meaning").Where("word = ? ",word).Select()
+		if err != nil {
+			panic(err)
+		}
+		
+		c.JSON(http.StatusOK, gin.H{
+			"message":"success",
+			"data": terms,
+		})
+	}
+}
+
+//return an HTML form for creating a new term
+func TermsNew(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK,"terms/new.html",gin.H{
+			"message":"ok",
+		})
+	}
+}
+//create a new term
+func TermsCreate(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+	
+		var form Term
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+		form.OwnerId = 1
+		//TODO补充业务逻辑
+		_, err := db.Model(&form).Insert()
+		if err != nil {
+			panic(err)
+		}
+
+		//建立成功
+		c.JSON(http.StatusOK,gin.H{
+			"message":"success",
+			"data":form,
+		})
+	}
+}
+
+//display a specific Term
+func TermsShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id,err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		fmt.Println("get term id=" + c.Param("id"))
+		rkey := "term://id/"+c.Param("id")
+		n, err := rdb.Exists(ctx,rkey).Result()
+		if err != nil  {
+			fmt.Println(err)
+		}else if n == 0 {
+			fmt.Println("redis key not exist")
+		}else{
+			fmt.Println("redis key exist")
+			val, err := rdb.HGetAll(ctx, rkey).Result()
+			if err != nil || val == nil {
+				//有错误或者没查到
+				fmt.Println("redis error")
+					
+			}else{
+				fmt.Println("redis no error")
+				c.JSON(http.StatusOK, gin.H{
+					"data": val,
+				})
+				return
+			}	
+		}
+
+		term := &Term{Id: id}
+		err = db.Model(term).Column("id","uid","name","description","description_type","owner_id","setting","status","version","updated_at").WherePK().Select()
+		if err != nil {
+			panic(err)
+		}			
+
+		//写入redis
+		rdb.HSet(ctx,rkey,"id",term.Id)
+		rdb.HSet(ctx,rkey,"pr_parent_id",term.PrParentId)
+		rdb.HSet(ctx,rkey,"word",term.Word)
+		rdb.HSet(ctx,rkey,"word_en",term.WordEn)
+		rdb.HSet(ctx,rkey,"tag",term.Tag)
+		rdb.HSet(ctx,rkey,"channel_id",term.ChannelId)
+		rdb.HSet(ctx,rkey,"meaning",term.Meaning)
+		rdb.HSet(ctx,rkey,"meaning2",term.Meaning2)
+		rdb.HSet(ctx,rkey,"note",term.Note)
+		rdb.HSet(ctx,rkey,"lang",term.Lang)
+		rdb.HSet(ctx,rkey,"sourse",term.Sourse)
+		rdb.HSet(ctx,rkey,"confidence",term.Confidence)
+		rdb.HSet(ctx,rkey,"owner_id",term.OwnerId)
+		rdb.HSet(ctx,rkey,"version",term.Version)
+		rdb.HSet(ctx,rkey,"updated_at",term.UpdatedAt)
+
+		c.JSON(http.StatusOK, gin.H{
+			"message":"success",
+			"data": term,
+		})		
+			
+	}
+}
+
+//return an HTML form for edit a term
+func TermsEdit(db *pg.DB) gin.HandlerFunc{
+	return func(c *gin.Context){
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK,"terms/edit.html",gin.H{
+			"name":"ok",
+		})
+	}
+}
+
+//update a specific term
+func TermsUpdate(db *pg.DB,rdb *redis.Client) gin.HandlerFunc{
+	return func(c *gin.Context){
+		var form Term
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+
+		//补充业务逻辑
+		_,err := db.Model(&form).Column("type","grammar","base","meaning","note","factors","factors_meaning","lang","sourse").WherePK().Update()
+		if err != nil {
+			panic(err)
+		}
+		//delete redis
+		rkey := "term://id/"+strconv.Itoa(form.Id)
+		rdb.Del(ctx,rkey)	
+
+		c.JSON(http.StatusOK,gin.H{
+			"message":"success",
+			"data":form,
+		})
+
+	}
+}
+
+
+//delete a specific term
+func TermsDestroy(db *pg.DB ,rdb *redis.Client) gin.HandlerFunc{
+	return func(c *gin.Context){
+		id,err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		term := &Term{
+			Id:int(id),
+		}
+
+		_, err = db.Model(term).WherePK().Delete()
+		if err != nil {
+			panic(err)
+		}
+
+		rkey := "term://id/"+c.Param("id")
+		rdb.Del(ctx,rkey)
+		
+		c.JSON(http.StatusOK,gin.H{
+			"message": "success",
+			"data":c.Param("id"),
+		})
+
+
+
+	}
+}

+ 248 - 0
api/mint/wbw.go

@@ -0,0 +1,248 @@
+package mint
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"strconv"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+)
+
+type Wbw struct {
+	Id          int    `form:"id" json:"id" `
+	PrParentId  int    `form:"pr_parent_id" json:"pr_parent_id" `
+	WbwsIndexId int    `form:"wbws_index_id" json:"wbws_index_id"`
+	ChannelId   int    `form:"channel_id" json:"channel_id"`
+	BookId      int    `form:"book_id" json:"book_id"`
+	Paragraph   int    `form:"paragraph" json:"paragraph"`
+	Sn          int    `form:"sn" json:"sn"`
+	Word        string `form:"word" json:"word"`
+	Data        string `form:"data" json:"data"`
+	Lang        string `form:"lang" json:"lang"`
+	Status      string `form:"status" json:"status"`
+	EditorId    int
+	OwnerId     int
+	Version     int
+	DeletedAt   time.Time
+	CreatedAt   time.Time
+	UpdatedAt   time.Time
+}
+type WbwHolder struct {
+	Data []Wbw
+}
+
+func (i *WbwHolder) UnmarshalJSON(b []byte) error {
+	return json.Unmarshal(b, &i.Data)
+}
+
+//display a list of all wbws
+func WbwsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		active := c.Query("active")
+
+		// TODO 补充业务逻辑
+		var wbws []Wbw
+		switch active {
+		case "channel":
+			//某channel
+			channel := c.Query("channel")
+			book := c.Query("book")
+			paragraph := c.Query("paragraph")
+
+			err := db.Model(&wbws).Column("id", "book_id", "paragraph", "sn", "data", "lang", "status").Where("channel = ?", channel).Where("book_id = ?", book).Where("paragraph = ?", paragraph).First()
+			//errors.Is(err, gorm.ErrRecordNotFound)
+			if err != nil {
+				panic(err)
+			}
+
+		case "blockid":
+			//某句子所有channel记录
+			blockid := c.Query("blockid")
+			err := db.Model(&wbws).Column("id", "book_id", "paragraph", "sn", "data", "lang", "status").Where("wbws_index_id = ?", blockid).Select()
+			if err != nil {
+				panic(err)
+			}
+
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status":  "succes",
+			"message": "",
+			"data":    wbws,
+		})
+	}
+}
+
+//return an HTML form for creating a new wbw
+func WbwsNew(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "wbws_new.html", gin.H{
+			"message": "ok",
+		})
+	}
+}
+
+//create new wbw
+func WbwsCreate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		/*
+			cookie, err := c.Cookie("userid")
+			if err != nil {
+				fmt.Println("not login")
+				c.JSON(http.StatusOK, gin.H{
+					"status":  "fail",
+					"message": "not login",
+				})
+				return
+			}
+			fmt.Println(cookie)
+		*/
+		iChannelId := c.Query("channel")
+		//TODO 查询权限
+
+		var form WbwHolder
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+
+		tx, err := db.Begin()
+		if err != nil {
+			panic(err)
+		}
+		defer tx.Rollback()
+		stmt, err := tx.Prepare("INSERT INTO wbws ( channel_id, book_id,paragraph,sn,word,data,lang,status,editor_id,owner_id ) VALUES( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10)")
+		if err != nil {
+			panic(err)
+		}
+		defer stmt.Close()
+		for _, value := range form.Data {
+			_, err = stmt.Exec(iChannelId, value.BookId, value.Paragraph, value.Sn, value.Word, value.Data, "en", "public", 1, 1)
+			if err != nil {
+				panic(err)
+			}
+
+		}
+		err = tx.Commit()
+		if err != nil {
+			panic(err)
+		}
+		//建立成功
+		c.JSON(http.StatusOK, gin.H{
+			"status":  "succes",
+			"message": "",
+			"data":    form.Data,
+		})
+	}
+}
+
+//display a specific Wbw
+func WbwsShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		fmt.Println("get wbw id=" + c.Param("id"))
+		rkey := "wbw://id"
+		n, err := rdb.Exists(ctx, rkey).Result()
+		if err != nil {
+			fmt.Println(err)
+		} else if n == 0 {
+			fmt.Println("redis key not exist")
+		} else {
+			fmt.Println("redis key exist")
+			val, err := rdb.HGetAll(ctx, rkey).Result()
+			if err != nil || val == nil {
+				//有错误或者没查到
+				fmt.Println("redis error")
+
+			} else {
+				fmt.Println("redis no error")
+				c.JSON(http.StatusOK, gin.H{
+					"data": val,
+				})
+				return
+			}
+		}
+
+		wbw := &Wbw{Id: id}
+		err = db.Model(wbw).Column("id", "uid", "name", "description", "description_type", "owner_id", "setting", "status", "version", "updated_at").WherePK().Select()
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK, gin.H{
+			"data": wbw,
+		})
+		//写入redis
+		rdb.HSet(ctx, rkey, id, wbw)
+
+	}
+}
+
+//return an HTML form for edit a wbw
+func WbwsEdit(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "wbws_edit.html", gin.H{
+			"name": "ok",
+		})
+	}
+}
+
+//update a specific wbw
+func WbwsUpdate(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		var form Wbw
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+
+		//补充业务逻辑
+		_, err := db.Model(&form).Column("name", "description", "description_type", "status", "setting").WherePK().Update()
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK, gin.H{
+			"message": form,
+		})
+		//delete redis
+		rkey := "wbw://id/" + strconv.Itoa(form.Id)
+		rdb.Del(ctx, rkey)
+	}
+}
+
+//delete a specific wbw
+func WbwsDestroy(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		wbw := &Wbw{
+			Id: int(id),
+		}
+		//删之前获取 course_id
+		_, err = db.Model(wbw).WherePK().Delete()
+		if err != nil {
+			panic(err)
+		}
+		//删除article_list表相关项目
+		c.JSON(http.StatusOK, gin.H{
+			"message": c.Param("id"),
+		})
+
+		rkey := "wbw://id/" + c.Param("id")
+		rdb.Del(ctx, rkey)
+
+	}
+}

+ 179 - 0
api/mint/wbw_index.go

@@ -0,0 +1,179 @@
+package mint
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+	"strconv"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+)
+
+type WbwIndex struct {
+	Id        int `form:"id" json:"id" `
+	ChannelId int `form:"channel_id" json:"channel_id"`
+	BookId    int `form:"book_id" json:"book_id"`
+	Paragraph int `form:"paragraph" json:"paragraph"`
+	OwnerId   int
+	CreatedAt time.Time
+}
+type WbwIndexHolder struct {
+	Data []WbwIndex
+}
+
+func (i *WbwIndexHolder) UnmarshalJSON(b []byte) error {
+	return json.Unmarshal(b, &i.Data)
+}
+
+//display a list of all wbws
+func WbwIndexsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		active := c.Query("active")
+
+		// TODO 补充业务逻辑
+		var wbws []Wbw
+		switch active {
+		case "channel":
+			//某channel
+			channel := c.Query("channel")
+			book := c.Query("book")
+			paragraph := c.Query("paragraph")
+
+			err := db.Model(&wbws).Column("id", "book_id", "paragraph", "sn", "data", "lang", "status").Where("channel = ?", channel).Where("book_id = ?", book).Where("paragraph = ?", paragraph).First()
+			//errors.Is(err, gorm.ErrRecordNotFound)
+			if err != nil {
+				panic(err)
+			}
+
+		case "blockid":
+			//某句子所有channel记录
+			blockid := c.Query("blockid")
+			err := db.Model(&wbws).Column("id", "book_id", "paragraph", "sn", "data", "lang", "status").Where("wbws_index_id = ?", blockid).Select()
+			if err != nil {
+				panic(err)
+			}
+
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status":  "succes",
+			"message": "",
+			"data":    wbws,
+		})
+	}
+}
+
+//create new wbw
+func WbwIndexsCreate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//channel := c.Query("channel")
+
+		var form WbwHolder
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+		//TODO 查询权限
+		tx, err := db.Begin()
+		if err != nil {
+			panic(err)
+		}
+		defer tx.Rollback()
+		stmt, err := tx.Prepare("INSERT INTO wbw( channel_id, book_id,paragraph,sn,word,data,lang,status,editor_id,owner_id ) VALUES( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10)")
+		if err != nil {
+			panic(err)
+		}
+		defer stmt.Close()
+		for _, value := range form.Data {
+			_, err = stmt.Exec(value.ChannelId, value.BookId, value.Paragraph, value.Sn, value.Word, value.Data, value.Lang, value.Status, 1, 1)
+			if err != nil {
+				panic(err)
+			}
+
+		}
+		err = tx.Commit()
+		if err != nil {
+			panic(err)
+		}
+		//建立成功
+		c.JSON(http.StatusOK, gin.H{
+			"status":  "succes",
+			"message": "",
+			"data":    form.Data,
+		})
+	}
+}
+
+//display a specific Wbw
+func WbwIndexsShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		fmt.Println("get wbw id=" + c.Param("id"))
+		rkey := "wbw://id"
+		n, err := rdb.Exists(ctx, rkey).Result()
+		if err != nil {
+			fmt.Println(err)
+		} else if n == 0 {
+			fmt.Println("redis key not exist")
+		} else {
+			fmt.Println("redis key exist")
+			val, err := rdb.HGetAll(ctx, rkey).Result()
+			if err != nil || val == nil {
+				//有错误或者没查到
+				fmt.Println("redis error")
+
+			} else {
+				fmt.Println("redis no error")
+				c.JSON(http.StatusOK, gin.H{
+					"data": val,
+				})
+				return
+			}
+		}
+
+		wbw := &Wbw{Id: id}
+		err = db.Model(wbw).Column("id", "uid", "name", "description", "description_type", "owner_id", "setting", "status", "version", "updated_at").WherePK().Select()
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK, gin.H{
+			"data": wbw,
+		})
+		//写入redis
+		rdb.HSet(ctx, rkey, id, wbw)
+
+	}
+}
+
+//delete a specific wbw
+func WbwIndexsDestroy(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		wbw := &Wbw{
+			Id: int(id),
+		}
+		//删之前获取 course_id
+		_, err = db.Model(wbw).WherePK().Delete()
+		if err != nil {
+			panic(err)
+		}
+		//删除article_list表相关项目
+		c.JSON(http.StatusOK, gin.H{
+			"message": c.Param("id"),
+		})
+
+		rkey := "wbw://id/" + c.Param("id")
+		rdb.Del(ctx, rkey)
+
+	}
+}

+ 44 - 0
api/mint/wbw_template.go

@@ -0,0 +1,44 @@
+package mint
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type WbwTemplate struct {
+	Id int `json:"id" `
+
+	BookId    int    `json:"book_id" `
+	Paragraph int    `json:"paragraph" `
+	WordSn    int    `json:"word_sn" `
+	Word      string `json:"word" `
+	RealWord  string `json:"real_word" `
+	Type      string `json:"type" `
+	Grammar   string `json:"grammar" `
+	Factors   string `json:"factors" `
+
+	CreatedAt time.Time
+}
+
+//display a list of all palitexts
+func WbwTemplatesIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		book := c.Query("book")
+		paragraph := c.Query("paragraph")
+
+		// TODO 补充业务逻辑
+		var wbw_template []WbwTemplate
+		err := db.Model(&wbw_template).Where("book_id = ?", book).Where("paragraph = ?", paragraph).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   wbw_template,
+		})
+	}
+}

+ 181 - 0
api/mint/wbws_list.go

@@ -0,0 +1,181 @@
+package mint
+
+import (
+	"fmt"
+	"net/http"
+	"strconv"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+	"github.com/go-redis/redis/v8"
+)
+
+type WbwsList struct {
+	Id        int    `form:"id" json:"id" `
+	ParentId  int    `form:"parent_id" json:"parent_id" `
+	ChannelId int    `form:"channel_id" json:"channel_id" `
+	BookId    int    `form:"book_id" json:"book_id" `
+	Paragraph int    `form:"paragraph" json:"paragraph" `
+	Title     string `form:"title" json:"title"`
+	Content   string `form:"content" json:"content"`
+	Lang      string `form:"lang" json:"lang"`
+	Setting   string `form:"setting" json:"setting"`
+	Status    string `form:"status" json:"status"`
+	OwnerId   int
+	Version   int
+	DeletedAt time.Time
+	CreatedAt time.Time
+	UpdatedAt time.Time
+}
+
+//display a list of all wbwsLists
+func WbwsListsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		name := c.DefaultQuery("name", "")
+
+		// TODO 补充业务逻辑
+		var wbwsLists []WbwsList
+		err := db.Model(&wbwsLists).Column("id", "name").Where("name like ?", name+"%").Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"data": wbwsLists,
+		})
+	}
+}
+
+//return an HTML form for creating a new wbwsList
+func WbwsListsNew(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "wbwsLists/new.html", gin.H{
+			"message": "ok",
+		})
+	}
+}
+
+//create a new wbwsList
+func WbwsListsCreate(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+
+		name := c.Query("title")
+		status := c.DefaultQuery("status", "private")
+
+		newWbwsList := &WbwsList{
+			Title:   name,
+			Status:  status,
+			OwnerId: 1, //TODO user_id
+		}
+		_, err := db.Model(newWbwsList).Insert()
+		if err != nil {
+			panic(err)
+		}
+
+		//建立成功
+		c.JSON(http.StatusOK, gin.H{
+			"message": "ok",
+		})
+	}
+}
+
+//display a specific WbwsList
+func WbwsListsShow(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		fmt.Println("get wbwsList id=" + c.Param("id"))
+		rkey := "wbwslist://id"
+		n, err := rdb.HExists(ctx, rkey, c.Param("id")).Result()
+		if err == nil && n {
+			val, err := rdb.HGet(ctx, rkey, c.Param("id")).Result()
+			if err == nil {
+				c.JSON(http.StatusOK, gin.H{
+					"data": val,
+				})
+				return
+			} else {
+				//有错误或者没查到
+				fmt.Println("redis error")
+			}
+		} else {
+			fmt.Println("redis error or key not exist")
+		}
+
+		wbwsList := &WbwsList{Id: id}
+		err = db.Model(wbwsList).Column("id", "parent_id", "channel_id", "book_id", "paragraph", "title", "status", "setting", "content", "version", "updated_at").WherePK().Select()
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK, gin.H{
+			"data": wbwsList,
+		})
+		//写入redis
+		rdb.HSet(ctx, rkey, id, wbwsList)
+
+	}
+}
+
+//return an HTML form for edit a wbwsList
+func WbwsListsEdit(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		//TODO 业务逻辑
+		c.HTML(http.StatusOK, "wbwsLists/edit.html", gin.H{
+			"name": "ok",
+		})
+	}
+}
+
+//update a specific wbwsList
+func WbwsListsUpdate(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		var form WbwsList
+
+		if err := c.ShouldBindJSON(&form); err != nil {
+			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+			return
+		}
+
+		//补充业务逻辑
+		_, err := db.Model(&form).Column("name", "description", "description_type", "status", "setting").WherePK().Update()
+		if err != nil {
+			panic(err)
+		}
+		c.JSON(http.StatusOK, gin.H{
+			"message": form,
+		})
+		//delete redis
+		rkey := "wbwslist://id"
+		rdb.HDel(ctx, rkey, strconv.Itoa(form.Id))
+	}
+}
+
+//delete a specific wbwsList
+func WbwsListsDestroy(db *pg.DB, rdb *redis.Client) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		id, err := strconv.Atoi(c.Param("id"))
+		if err != nil {
+			panic(err)
+		}
+		wbwsList := &WbwsList{
+			Id: int(id),
+		}
+
+		_, err = db.Model(wbwsList).WherePK().Delete()
+		if err != nil {
+			panic(err)
+		}
+
+		rkey := "wbwslist://id"
+		rdb.HDel(ctx, rkey, c.Param("id"))
+
+		c.JSON(http.StatusOK, gin.H{
+			"message": c.Param("id"),
+		})
+
+	}
+}

+ 37 - 0
api/mint/word_in_book_index.go

@@ -0,0 +1,37 @@
+package mint
+
+import (
+	"net/http"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/go-pg/pg/v10"
+)
+
+type WordInBookIndex struct {
+	Id              int `json:"id" `
+	BookId          int `json:"book_id" `
+	PaliWordIndexId int `json:"pali_word_index_id" `
+	Count           int `json:"count" `
+	CreatedAt       time.Time
+}
+
+//display a list of all palitexts
+func WordInBookIndexsIndex(db *pg.DB) gin.HandlerFunc {
+	return func(c *gin.Context) {
+		book := c.Query("book")
+		paragraph := c.Query("paragraph")
+
+		// TODO 补充业务逻辑
+		var word_in_book_indexs []WordInBookIndex
+		err := db.Model(&word_in_book_indexs).Where("book_id = ?", book).Where("paragraph = ?", paragraph).Select()
+		if err != nil {
+			panic(err)
+		}
+
+		c.JSON(http.StatusOK, gin.H{
+			"status": "sucess",
+			"data":   word_in_book_indexs,
+		})
+	}
+}