memos
memos
是一个开源的、自托管的知识库,可与 SQLite db
文件一起使用。 使用SQLite db
还是很有必要的,因为有的时候我们需要把我们的日志进行转移,直接把数据库拷走就可以了。
github的地址在这里。
这个界面让人看起来还是觉得蛮舒服的,设置的也非常的简单,日常记录的,我觉得这样就很方便了。
主要的特性:
- 🦄完全开源;
- 📜用纯文本区域书写,没有任何负担,
- 并支持一些有用的markdown语法💪.
- 🌄在漂亮的图片或个人页面(如 Twitter)中分享备忘录;
- 🚀快速自托管Docker;
- 🤠令人愉快的用户界面和用户体验;
安装
直接用docker 进行安装,方便:
docker run -d --name memos -p 5230:5230 -v ~/.memos/:/var/opt/memos neosmemo/memos:latest
memos
应该在http://localhost:5230
运行。如果~/.memos/
没有memos_prod.db
文件,则memos
将自动生成它。
看看建成的memos
。
记录自己的文字,非常的方便。
代码分析
go语言作为后端,看起来非常的方便,这里分析几个 功能,新建用户:
g.POST("/user", func(c echo.Context) error {
ctx := c.Request().Context()
userID, ok := c.Get(getUserIDContextKey()).(int)
if !ok {
return echo.NewHTTPError(http.StatusUnauthorized, "Missing auth session")
}
currentUser, err := s.Store.FindUser(ctx, &api.UserFind{
ID: &userID,
})
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find user by id").SetInternal(err)
}
if currentUser.Role != api.Host {
return echo.NewHTTPError(http.StatusUnauthorized, "Only Host user can create member.")
}
userCreate := &api.UserCreate{
OpenID: common.GenUUID(),
}
if err := json.NewDecoder(c.Request().Body).Decode(userCreate); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Malformatted post user request").SetInternal(err)
}
if err := userCreate.Validate(); err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Invalid user create format.").SetInternal(err)
}
passwordHash, err := bcrypt.GenerateFromPassword([]byte(userCreate.Password), bcrypt.DefaultCost)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to generate password hash").SetInternal(err)
}
userCreate.PasswordHash = string(passwordHash)
user, err := s.Store.CreateUser(ctx, userCreate)
if err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to create user").SetInternal(err)
}
c.Response().Header().Set(echo.HeaderContentType, echo.MIMEApplicationJSONCharsetUTF8)
if err := json.NewEncoder(c.Response().Writer).Encode(composeResponse(user)); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to encode user response").SetInternal(err)
}
return nil
})
数据库的操作:
func createUser(ctx context.Context, tx *sql.Tx, create *api.UserCreate) (*userRaw, error) {
query := `
INSERT INTO user (
email,
role,
name,
password_hash,
open_id
)
VALUES (?, ?, ?, ?, ?)
RETURNING id, email, role, name, password_hash, open_id, created_ts, updated_ts, row_status
`
var userRaw userRaw
if err := tx.QueryRowContext(ctx, query,
create.Email,
create.Role,
create.Name,
create.PasswordHash,
create.OpenID,
).Scan(
&userRaw.ID,
&userRaw.Email,
&userRaw.Role,
&userRaw.Name,
&userRaw.PasswordHash,
&userRaw.OpenID,
&userRaw.CreatedTs,
&userRaw.UpdatedTs,
&userRaw.RowStatus,
); err != nil {
return nil, FormatError(err)
}
return &userRaw, nil
}