-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
43 changed files
with
2,180 additions
and
128 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,6 @@ version: 0.1.0 | |
log_level: debug | ||
|
||
listen_addr: ":10086" | ||
|
||
cql: | ||
cluster: | ||
- "10.77.64.46:9042" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,25 @@ | ||
package ecode | ||
|
||
// account | ||
// common | ||
const ( | ||
NotSignIn = 1001 | ||
NotSignInMsg = "user need sign in" | ||
|
||
ParamInvalid = 1002 | ||
ParamInvalidMsg = "param invalid" | ||
|
||
CommonErrorMsg = "Oh no, an unexpected error happend" | ||
DatabaseError = 1003 | ||
|
||
NoPermission = 1004 | ||
NoPermissionMsg = "You don't have permission" | ||
) | ||
|
||
// article | ||
const ( | ||
ArticleNotFound = 1100 | ||
ArticleNotFoundMsg = "Target article not found" | ||
|
||
PostNotFound = 1101 | ||
PostNotFoundMsg = "Target post not found" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package misc | ||
|
||
import "github.com/gocql/gocql" | ||
|
||
// CQL is the cql session for access cassandra | ||
var CQL *gocql.Session | ||
|
||
const ( | ||
//CQLNotFound when acess cql, get the not found result | ||
CQLNotFound = "not found" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package misc | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/sony/sonyflake" | ||
) | ||
|
||
// IDGen generate ditrubuted unique id | ||
var IDGen *sonyflake.Sonyflake | ||
|
||
func init() { | ||
var st sonyflake.Settings | ||
IDGen = sonyflake.NewSonyflake(st) | ||
} | ||
|
||
// GenID return a hex number string | ||
func GenID() string { | ||
id, _ := IDGen.NextID() | ||
return fmt.Sprintf("%x", id) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
package post | ||
|
||
import ( | ||
"encoding/json" | ||
"net/http" | ||
"time" | ||
|
||
"github.com/labstack/echo" | ||
"github.com/thinkindev/im.dev/internal/ecode" | ||
"github.com/thinkindev/im.dev/internal/misc" | ||
"github.com/thinkindev/im.dev/internal/session" | ||
"github.com/thinkindev/im.dev/internal/utils" | ||
"go.uber.org/zap" | ||
) | ||
|
||
// ArContent represent article content | ||
type ArContent struct { | ||
ID string `json:"id"` | ||
Title string `json:"title"` | ||
Tags []string `json:"tags"` | ||
MD string `json:"md"` | ||
Render string `json:"render"` | ||
Lang string `json:"lang"` | ||
Status int `json:"status"` | ||
} | ||
|
||
// NewArticle create a new article | ||
func NewArticle(c echo.Context) error { | ||
opType := c.FormValue("type") | ||
if opType != "1" && opType != "2" { | ||
return c.JSON(http.StatusBadRequest, misc.HTTPResp{ | ||
ErrCode: ecode.ParamInvalid, | ||
Message: ecode.ParamInvalidMsg, | ||
}) | ||
} | ||
|
||
content := c.FormValue("content") | ||
ar := &ArContent{} | ||
err := json.Unmarshal([]byte(content), &ar) | ||
if err != nil { | ||
return c.JSON(http.StatusBadRequest, misc.HTTPResp{ | ||
ErrCode: ecode.ParamInvalid, | ||
Message: ecode.ParamInvalidMsg, | ||
}) | ||
} | ||
|
||
sess := session.Get(c) | ||
|
||
// generate id for article | ||
ar.ID = misc.GenID() | ||
|
||
// modify render | ||
ar.Render = modify(ar.Render) | ||
|
||
err = misc.CQL.Query(`INSERT INTO article (id,uid,title,tags,md,render,status,edit_date,lang) | ||
VALUES (?,?,?,?,?,?,?,?,?)`, ar.ID, sess.ID, ar.Title, ar.Tags, ar.MD, ar.Render, opType, time.Now().Unix(), ar.Lang).Exec() | ||
if err != nil { | ||
misc.Log.Warn("access database error", zap.Error(err)) | ||
return c.JSON(http.StatusInternalServerError, misc.HTTPResp{ | ||
ErrCode: ecode.DatabaseError, | ||
Message: ecode.CommonErrorMsg, | ||
}) | ||
} | ||
|
||
saveTags(ar.ID, ar.Tags) | ||
return c.JSON(http.StatusOK, misc.HTTPResp{ | ||
Data: sess.Name + "/" + ar.ID, | ||
}) | ||
} | ||
|
||
// ArticleDetail contains detail data of article | ||
type ArticleDetail struct { | ||
ID string `json:"id"` | ||
UID string `json:"uid"` | ||
Title string `json:"title"` | ||
Tags []string `json:"tags"` | ||
Render string `json:"render"` | ||
Status int `json:"status"` | ||
PublishDate string `json:"publish_date"` | ||
EditDate string `json:"edit_date"` | ||
Lang string `json:"lang"` | ||
pubDate int64 | ||
editDate int64 | ||
} | ||
|
||
// GetArticleDetail return detail data of the article | ||
func GetArticleDetail(c echo.Context) error { | ||
arID := c.FormValue("article_id") | ||
if arID == "" { | ||
return c.JSON(http.StatusBadRequest, misc.HTTPResp{ | ||
ErrCode: ecode.ParamInvalid, | ||
Message: ecode.ParamInvalidMsg, | ||
}) | ||
} | ||
|
||
detail := &ArticleDetail{ID: arID} | ||
err := misc.CQL.Query(`SELECT uid,title,tags,render,status,publish_date,edit_date,lang FROM article WHERE id=?`, arID).Scan( | ||
&detail.UID, &detail.Title, &detail.Tags, &detail.Render, &detail.Status, &detail.pubDate, &detail.editDate, &detail.Lang, | ||
) | ||
if err != nil { | ||
if err.Error() == misc.CQLNotFound { | ||
return c.JSON(http.StatusNotFound, misc.HTTPResp{ | ||
ErrCode: ecode.ArticleNotFound, | ||
Message: ecode.ArticleNotFoundMsg, | ||
}) | ||
} | ||
misc.Log.Warn("access database error", zap.Error(err)) | ||
return c.JSON(http.StatusInternalServerError, misc.HTTPResp{ | ||
ErrCode: ecode.DatabaseError, | ||
Message: ecode.CommonErrorMsg, | ||
}) | ||
} | ||
|
||
if detail.pubDate != 0 { | ||
detail.PublishDate = utils.Time2ReadableString(time.Unix(detail.pubDate, 0)) | ||
} | ||
if detail.editDate != 0 { | ||
detail.EditDate = utils.Time2ReadableString(time.Unix(detail.editDate, 0)) | ||
} | ||
return c.JSON(http.StatusOK, misc.HTTPResp{ | ||
Data: detail, | ||
}) | ||
} | ||
|
||
// BeforeEditAr deal some pre-things before editing article | ||
func BeforeEditAr(c echo.Context) error { | ||
arID := c.FormValue("article_id") | ||
if arID == "" { | ||
return c.JSON(http.StatusBadRequest, misc.HTTPResp{ | ||
ErrCode: ecode.ParamInvalid, | ||
Message: ecode.ParamInvalidMsg, | ||
}) | ||
} | ||
|
||
var uid, title, md, lang string | ||
var tags []string | ||
var status int | ||
err := misc.CQL.Query(`SELECT uid,title,tags,md,lang,status FROM article WHERE id=?`, arID).Scan( | ||
&uid, &title, &tags, &md, &lang, &status, | ||
) | ||
if err != nil { | ||
if err.Error() == misc.CQLNotFound { | ||
return c.JSON(http.StatusNotFound, misc.HTTPResp{ | ||
ErrCode: ecode.ArticleNotFound, | ||
Message: ecode.ArticleNotFoundMsg, | ||
}) | ||
} | ||
misc.Log.Warn("access database error", zap.Error(err)) | ||
return c.JSON(http.StatusInternalServerError, misc.HTTPResp{ | ||
ErrCode: ecode.DatabaseError, | ||
Message: ecode.CommonErrorMsg, | ||
}) | ||
} | ||
|
||
sess := session.Get(c) | ||
|
||
// check whether user has permission to do so | ||
if uid != sess.ID { | ||
return c.JSON(http.StatusInternalServerError, misc.HTTPResp{ | ||
ErrCode: ecode.NoPermission, | ||
Message: ecode.NoPermissionMsg, | ||
}) | ||
} | ||
|
||
ar := &ArContent{ | ||
ID: arID, | ||
Title: title, | ||
MD: md, | ||
Tags: tags, | ||
Lang: lang, | ||
Status: status, | ||
} | ||
|
||
return c.JSON(http.StatusOK, misc.HTTPResp{ | ||
Data: ar, | ||
}) | ||
} | ||
|
||
// SaveArticleChanges save changes when edit article | ||
func SaveArticleChanges(c echo.Context) error { | ||
content := c.FormValue("content") | ||
ar := &ArContent{} | ||
err := json.Unmarshal([]byte(content), &ar) | ||
if err != nil { | ||
return c.JSON(http.StatusBadRequest, misc.HTTPResp{ | ||
ErrCode: ecode.ParamInvalid, | ||
Message: ecode.ParamInvalidMsg, | ||
}) | ||
} | ||
|
||
// check the article is exist and user has permission | ||
var uid string | ||
err = misc.CQL.Query(`SELECT uid FROM article WHERE id=?`, ar.ID).Scan(&uid) | ||
if err != nil { | ||
if err.Error() == misc.CQLNotFound { | ||
return c.JSON(http.StatusNotFound, misc.HTTPResp{ | ||
ErrCode: ecode.ArticleNotFound, | ||
Message: ecode.ArticleNotFoundMsg, | ||
}) | ||
} | ||
misc.Log.Warn("access database error", zap.Error(err)) | ||
return c.JSON(http.StatusInternalServerError, misc.HTTPResp{ | ||
ErrCode: ecode.DatabaseError, | ||
Message: ecode.CommonErrorMsg, | ||
}) | ||
} | ||
sess := session.Get(c) | ||
if sess.ID != uid { | ||
return c.JSON(http.StatusInternalServerError, misc.HTTPResp{ | ||
ErrCode: ecode.NoPermission, | ||
Message: ecode.NoPermissionMsg, | ||
}) | ||
} | ||
|
||
// modify render | ||
ar.Render = modify(ar.Render) | ||
|
||
err = misc.CQL.Query(`UPDATE article SET title=?,tags=?,md=?,render=?,edit_date=?,lang=? WHERE id=?`, | ||
ar.Title, ar.Tags, ar.MD, ar.Render, time.Now().Unix(), ar.Lang, ar.ID).Exec() | ||
if err != nil { | ||
misc.Log.Warn("access database error", zap.Error(err)) | ||
return c.JSON(http.StatusInternalServerError, misc.HTTPResp{ | ||
ErrCode: ecode.DatabaseError, | ||
Message: ecode.CommonErrorMsg, | ||
}) | ||
} | ||
|
||
saveTags(ar.ID, ar.Tags) | ||
return c.JSON(http.StatusOK, misc.HTTPResp{ | ||
Data: sess.Name + "/" + ar.ID, | ||
}) | ||
} | ||
|
||
func saveTags(arID string, tags []string) { | ||
for _, tag := range tags { | ||
err := misc.CQL.Query(`INSERT INTO tags (name,article_id) VALUES (?,?)`, tag, arID).Exec() | ||
if err != nil { | ||
misc.Log.Warn("access database error", zap.Error(err)) | ||
} | ||
} | ||
} |
Oops, something went wrong.