// new site init data func NewSiteInitData(engine *xorm.Engine) { // default user user := &model.User{ Name: "admin", Nick: "admin", Email: "*****@*****.**", Url: "#", AvatarUrl: utils.GravatarLink("*****@*****.**"), Profile: "this is an administrator", Role: model.USER_ROLE_ADMIN, Status: model.USER_STATUS_ACTIVE, } user.Salt = utils.Md5String("123456789")[8:24] user.Password = utils.Sha256String("123456789" + user.Salt) if _, err := engine.Insert(user); err != nil { log.Error("NewSite | %s", err.Error()) return } // default article article := &model.Article{ Title: "Welcome to Purine", Link: "welcome-to-purine", Preview: blogPreview, Body: blogContent, TagString: "blog", Hits: 1, Comments: 0, Status: model.ARTICLE_STATUS_PUBLISH, CommentStatus: model.ARTICLE_COMMENT_OPEN, AuthorId: user.Id, } if _, err := engine.Insert(article); err != nil { log.Error("NewSite | %s", err.Error()) return } // default settings settings := make([]interface{}, 0) settings = append(settings, &model.Setting{"title", "Purine", 0}) settings = append(settings, &model.Setting{"subtitle", "a simple blog engine", 0}) settings = append(settings, &model.Setting{"desc", "a simple blog engine by golang", 0}) settings = append(settings, &model.Setting{"keyword", "purine,blog,golang", 0}) settings = append(settings, &model.Setting{"theme", "default", 0}) settings = append(settings, &model.Setting{"baseurl", "http://localhost:9999/", 0}) settings = append(settings, &model.Setting{"media_imageext", ".jpg,.jpeg,.png,.gif", 0}) settings = append(settings, &model.Setting{"media_fileext", ".txt,.zip,.doc,.xls,.ppt,.pdf", 0}) settings = append(settings, &model.Setting{"media_nameformat", ":hash", 0}) settings = append(settings, &model.Setting{"media_maxsize", strconv.Itoa(2 * 1024 * 1024), 0}) if _, err := engine.Insert(settings...); err != nil { log.Error("NewSite | %s", err.Error()) return } }
// save a comment, // always insert new func SaveComment(c *Comment) error { if _, err := vars.Db.Insert(c); err != nil { log.Error("Db|SaveComment|%s", err.Error()) return err } return nil }
// save setting with key, value and owner id func SaveSetting(key, value string, uid int64) error { if _, err := vars.Db.Where("name = ?", key).Delete(new(Setting)); err != nil { log.Error("Db|SaveSetting|%s,%s,%d|%s", key, value, uid, err.Error()) return err } s := &Setting{ Name: key, Value: value, UserId: uid, } if _, err := vars.Db.Insert(s); err != nil { log.Error("Db|SaveSetting|%s,%s,%d|%s", key, value, uid, err.Error()) return err } return nil }
// get current theme func GetCurrentTheme() (*Theme, error) { themeSetting, err := GetSettings("theme") if err != nil { return nil, err } t := new(Theme) t.Directory = themeSetting["theme"] t.IsCurrent = true tomlFile := path.Join("static", t.Directory, "theme.toml") if com.IsFile(tomlFile) { if _, err := toml.DecodeFile(tomlFile, t); err != nil { log.Error("Db|GetCurrentTheme|%s|%s", tomlFile, err.Error()) return nil, err } } // fill data if t.Name == "" { t.Name = t.Directory } if t.Version == "" { t.Version = "0.0" } return t, nil }
func saveTags(id int64, tagStr string) error { // delete old tags if _, err := vars.Db.Where("article_id = ?", id).Delete(new(Tag)); err != nil { log.Error("Db|SaveTags|%d,%s|%s", id, tagStr, err.Error()) return err } // save new tags tags := strings.Split(strings.Replace(tagStr, ",", ",", -1), ",") for _, t := range tags { if _, err := vars.Db.Insert(&Tag{ArticleId: id, Tag: t}); err != nil { log.Error("Db|SaveTags|%d,%s|%s", id, t, err.Error()) return err } } return nil }
// check email's approved comment count func CountApprovedCommentsByEmail(email string) int64 { c, err := vars.Db.Where("status = ? AND email = ?", COMMENT_STATUS_APPROVED, email).Count(new(Comment)) if err != nil { log.Error("Db|CountApprovedCommentsByEmail|%s|%s", email, err.Error()) return 0 } return c }
// save page. // if page.Id, update page, // or insert new page; // return the saved page. func SavePage(p *Page) (*Page, error) { if p.Id > 0 { if _, err := vars.Db.Where("id = ?", p.Id). Cols("title,link,update_time,body,topic,status,comment_status"). Update(p); err != nil { log.Error("Db|SavePage|%d|%s", p.Id, err.Error()) return nil, err } } else { if _, err := vars.Db.Insert(p); err != nil { log.Error("Db|SavePage|%d|%s", p.Id, err.Error()) return nil, err } } return GetPageBy("id", p.Id) }
// update user profile columns func UpdateUser(u *User) error { if _, err := vars.Db.Cols("name,nick,email,url,profile,avatar_url"). Where("id = ?", u.Id).Update(u); err != nil { log.Error("Db|UpdateUser|%d|%s", u.Id, err.Error()) return err } return nil }
// change comment status func ChangeCommentStatus(cid int64, status string) (*Comment, error) { c := &Comment{Status: status} if _, err := vars.Db.Id(cid).Cols("status").Update(c); err != nil { log.Error("Db|ChangeCommentStatus|%d,%s|%s", cid, status, err.Error()) return nil, err } return GetCommentBy("id", cid) }
// get article by column and value func GetArticleBy(col string, v interface{}) (*Article, error) { a := new(Article) if isIdColumn(col) { if _, err := vars.Db.Id(v).Get(a); err != nil { log.Error("Db|GetArticleBy|%s,%v|%s", col, v, err.Error()) return nil, err } } else { if _, err := vars.Db.Where(col+" = ?", v).Get(a); err != nil { log.Error("Db|GetArticleBy|%s,%v|%s", col, v, err.Error()) return nil, err } } if a.Id > 0 { return a, nil } return nil, nil }
// list general articles, // contains publish and draft articles func ListGeneralArticle(page, size int64, order string) ([]*Article, error) { articles := make([]*Article, 0) if err := vars.Db.Where("status != ?", ARTICLE_STATUS_DELETE). Limit(int(size), int((page-1)*size)).OrderBy(order).Find(&articles); err != nil { log.Error("Db|ListGeneralArticle|%d,%d|%s|%s", page, size, order, err.Error()) return nil, err } return articles, nil }
// remove article by id func RemoveArticle(id int64) error { a := new(Article) a.Status = ARTICLE_STATUS_DELETE if _, err := vars.Db.Where("id = ?", id).Cols("status").Update(a); err != nil { log.Error("Db|RemoveArticle|%d|%s", id, err.Error()) return err } return nil }
// list articles with one status func ListStatusArticle(status string, page, size int64, order string) ([]*Article, error) { articles := make([]*Article, 0) if err := vars.Db.Where("status = ?", status). Limit(int(size), int((page-1)*size)).OrderBy(order).Find(&articles); err != nil { log.Error("Db|ListStatusArticle|%s|%d,%d|%s|%s", status, page, size, order, err.Error()) return nil, err } return articles, nil }
// get page by column and value func GetPageBy(col string, v interface{}) (*Page, error) { p := new(Page) if isIdColumn(col) { if _, err := vars.Db.Id(v).Get(p); err != nil { log.Error("Db|GetPageBy|%s,%v|%s", col, v, err.Error()) return nil, err } } else { if _, err := vars.Db.Where(col+" = ?", v).Get(p); err != nil { log.Error("Db|GetPageBy|%s,%v|%s", col, v, err.Error()) return nil, err } } if p.Id > 0 { return p, nil } return nil, nil }
// get a comment by column and value func GetCommentBy(col string, v interface{}) (*Comment, error) { c := new(Comment) if isIdColumn(col) { if _, err := vars.Db.Id(v).Get(c); err != nil { log.Error("Db|GetCommentBy|%s,%v|%s", col, v, err.Error()) return nil, err } } else { if _, err := vars.Db.Where(col+" = ?", v).Get(c); err != nil { log.Error("Db|GetCommentBy|%s,%v|%s", col, v, err.Error()) return nil, err } } if c.Id > 0 { return c, nil } return nil, nil }
// get user by column and value func GetUserBy(col string, v interface{}) (*User, error) { u := new(User) if isIdColumn(col) { if _, err := vars.Db.Id(v).Get(u); err != nil { log.Error("Db|GetUserBy|%s,%v|%s", col, v, err.Error()) return nil, err } } else { if _, err := vars.Db.Where(col+" = ?", v).Get(u); err != nil { log.Error("Db|GetUserBy|%s,%v|%s", col, v, err.Error()) return nil, err } } if u.Id == 0 { return nil, nil } return u, nil }
// list comments in specific status func ListStatusComments(status string, page, size int64, order string) ([]*Comment, error) { comments := make([]*Comment, 0) if err := vars.Db.Where("status = ?", status).OrderBy(order). Limit(int(size), int((page-1)*size)).Find(&comments); err != nil { log.Error("Db|ListStatusComments|%s|%d,%d|%s|%s", status, page, size, order, err.Error()) return nil, err } return comments, nil }
// update user password with user id and new password func UpdatePassword(id int64, newPassword string) error { u := new(User) u.Salt = utils.Md5String(newPassword)[8:24] u.Password = utils.Sha256String(newPassword + u.Salt) if _, err := vars.Db.Cols("password,salt").Where("id = ?", id).Update(u); err != nil { log.Error("Db|UpdatePassword|%d|%s", id, err.Error()) return err } return nil }
// list all comments func ListAllComments(page, size int64, order string) ([]*Comment, error) { comments := make([]*Comment, 0) if err := vars.Db.OrderBy(order). Where("status != ?", COMMENT_STATUS_DELETED). Limit(int(size), int((page-1)*size)).Find(&comments); err != nil { log.Error("Db|ListAllComments|%s|%d,%d|%s|%s", "all", page, size, order, err.Error()) return nil, err } return comments, nil }
// list comments by status in article func ListStatusCommentsInArticle(status string, aid, page, size int64, order string) ([]*Comment, error) { comments := make([]*Comment, 0) if err := vars.Db. Where("status = ? AND `from` = ? AND `from_id` = ?", status, COMMENT_FROM_ARTICLE, aid). OrderBy(order). Limit(int(size), int((page-1)*size)).Find(&comments); err != nil { log.Error("Db|ListStatusCommentsInArticle|%s|%d,%d|%s|%s", status, page, size, order, err.Error()) return nil, err } return comments, nil }
// list media files func ListMedia(page, size int64) ([]*Media, error) { media := make([]*Media, 0) if err := vars.Db. Limit(int(size), int((page-1)*size)). OrderBy("id DESC"). Find(&media); err != nil { log.Error("Db|ListMedia|%d,%d|%s", page, size, err.Error()) return nil, err } return media, nil }
// create new token with user id and expiration duration func CreateToken(user, expire int64) (*Token, error) { t := &Token{ UserId: user, ExpireTime: time.Now().Unix() + expire, } t.Token = utils.Md5String(fmt.Sprintf("%d,%d", t.UserId, t.ExpireTime)) if _, err := vars.Db.Insert(t); err != nil { log.Error("Db|CreateToken|%v|%s", t, err.Error()) return nil, err } return t, nil }
// new site data func NewSiteData(ctx *cli.Context) { sqliteVersion, _, _ := sqlite3.Version() log.Info("NewSite | %-8s | %s | %s", "SQLite", sqliteVersion, vars.DATA_FILE) engine, err := xorm.NewEngine("sqlite3", vars.DATA_FILE) if err != nil { log.Error("NewSite | %s", err.Error()) return } engine.SetLogger(nil) // close logger if err = engine.Sync2(new(model.User), new(model.Token), new(model.Article), new(model.Page), new(model.Tag), new(model.Setting), new(model.Media), new(model.Comment)); err != nil { log.Error("NewSite | %s", err.Error()) return } log.Info("NewSite | %-8s | SyncDb | %s,%s,%s,%s,%s,%s,%s,%s", "SQLite", reflect.TypeOf(new(model.User)).String(), reflect.TypeOf(new(model.Token)).String(), reflect.TypeOf(new(model.Article)).String(), reflect.TypeOf(new(model.Page)).String(), reflect.TypeOf(new(model.Tag)).String(), reflect.TypeOf(new(model.Setting)).String(), reflect.TypeOf(new(model.Media)).String(), reflect.TypeOf(new(model.Comment)).String(), ) // site init data NewSiteInitData(engine) log.Info("NewSite | %-8s | Success", "SQLite") engine.Close() }
// new site func NewSite(ctx *cli.Context) { config := model.NewConfig() // encode config if err := model.WriteConfig(config, vars.CONFIG_FILE); err != nil { log.Error("NewSite | %s", err.Error()) return } log.Info("NewSite | %-8s | %s", "Init", vars.CONFIG_FILE) log.Info("NewSite | %-8s | %s", "Version", config.Version) log.Info("NewSite | %-8s | %s:%s", "Server", config.Server.Host, config.Server.Port) }
// upgrade action func UpgradeAction(cfg *model.Config) { t := time.Now() log.Debug("Upgrade | %-8s | %s(%s) -> %s(%s)", "Upgrade", cfg.Version, cfg.Date, vars.VERSION, vars.VERSION_DATE) opt := &PrepareOption{true, true, false} pre, err := Prepare(opt) if err != nil { log.Error("Upgrade | %-8s | %s", "Prepare", err.Error()) return } log.Info("Upgrade | %-8s | %s", "Prepare", opt.String()) oldVersion, _ := strconv.Atoi(pre.Config.Date) scriptIndex := []int{} for vr, _ := range upg.Script { if vr > oldVersion { scriptIndex = append(scriptIndex, vr) } } sort.Sort(sort.IntSlice(scriptIndex)) for _, cv := range scriptIndex { log.Debug("Upgrade | %-8s | %d ", "Process", cv) if err := upg.Script[cv](); err != nil { log.Error("Upgrade | %-8s | %s", "Process", err.Error()) return } } pre.Config.Version = vars.VERSION pre.Config.Date = vars.VERSION_DATE if err := model.WriteConfig(pre.Config, vars.CONFIG_FILE); err != nil { log.Error("Upgrade | %-8s | SyncFail", "Config") return } log.Info("Upgrade | %-8s | Sync | %s", "Config", vars.CONFIG_FILE) log.Info("Upgrade | %-8s | %.1fms", "Done", time.Since(t).Seconds()*1000) }
// get settings by keys func GetSettings(keys ...string) (map[string]string, error) { str := `"` + strings.Join(keys, `","`) + `"` settings := make([]*Setting, 0) if err := vars.Db.Where("name IN (" + str + ")").Find(&settings); err != nil { log.Error("Db|GetSettings|%v|%s", keys, err.Error()) return nil, err } m := make(map[string]string) for _, s := range settings { m[s.Name] = s.Value } return m, nil }
// save article. // if Article.Id, update article, // or insert new article; // return the saved article. func SaveArticle(a *Article) (*Article, error) { if a.Id > 0 { if _, err := vars.Db.Where("id = ?", a.Id). Cols("title,link,update_time,preview,body,topic,tag_string,status,comment_status"). Update(a); err != nil { log.Error("Db|SaveArticle|%d|%s", a.Id, err.Error()) return nil, err } } else { if _, err := vars.Db.Insert(a); err != nil { log.Error("Db|SaveArticle|%d|%s", a.Id, err.Error()) return nil, err } } if a.TagString != "" { if err := saveTags(a.Id, a.TagString); err != nil { return nil, err } } return GetArticleBy("id", a.Id) }
// get themes in diretory func GetThemes() ([]*Theme, error) { themeSetting, err := GetSettings("theme") if err != nil { return nil, err } dirs, err := ioutil.ReadDir("static") if err != nil { return nil, err } themes := make([]*Theme, 0) for _, d := range dirs { if !d.IsDir() { continue } // ignore admin and upload directory if d.Name() == "admin" || d.Name() == "upload" { continue } t := new(Theme) t.Directory = d.Name() // read theme file tomlFile := path.Join("static", d.Name(), "theme.toml") if com.IsFile(tomlFile) { if _, err := toml.DecodeFile(tomlFile, t); err != nil { log.Error("Db|GetThemes|%s|%s", tomlFile, err.Error()) return nil, err } } else { continue } // fill data if t.Name == "" { t.Name = d.Name() } if t.Version == "" { t.Version = "0.0" } // is current if t.Directory == themeSetting["theme"] { t.IsCurrent = true } themes = append(themes, t) } return themes, nil }
// pack static files to source func PackSrc(ctx *cli.Context) { t := time.Now() log.Info("Pack | %-8s", "Source") file, err := packSrcZip() if err != nil { log.Error("Pack | %-8s | %s", "ZipSrc", err.Error()) return } bytes, err := ioutil.ReadFile(file) if err != nil { log.Error("Pack | %-8s | %s", "ZipSrc", err.Error()) return } zipWriter, err := os.OpenFile("cmd/asset.go", os.O_WRONLY|os.O_TRUNC|os.O_CREATE, os.ModePerm) if err != nil { log.Error("Pack | %-8s | %s", "ZipSrc", err.Error()) return } header := `package cmd const zipBytes="` zipWriter.Write([]byte(header)) encoder := base64.NewEncoder(base64.StdEncoding, zipWriter) encoder.Write(bytes) encoder.Close() zipWriter.Write([]byte(`"`)) zipWriter.Sync() zipWriter.Close() if err = os.Remove(file); err != nil { log.Error("Pack | %-8s | %s", "ZipSrc", err.Error()) return } log.Info("Pack | %-8s | %s", "ZipSrc", utils.FriendBytesSize(int64(len(bytes)))) log.Info("Pack | %-8s | %.1fms", "ZipSrc", time.Since(t).Seconds()*1000) }
// get valid token. // it checks expiration. func GetValidToken(token string) (*Token, error) { t := new(Token) if _, err := vars.Db.Where("token = ?", token).Get(t); err != nil { log.Error("Db|GetValidToken|%s|%s", token, err.Error()) return nil, err } // wrong token if t.Token != token { return nil, nil } // expired if time.Now().Unix() > t.ExpireTime { return nil, nil } return t, nil }