mirror of
https://github.com/usememos/memos.git
synced 2025-01-03 03:38:23 +03:00
chore: rename user role (#108)
* chore: rename user role to `host` * chore: related frontend changes * chore: fix migration file * chore: use tricky sql
This commit is contained in:
parent
6f32643d7c
commit
bdc9632b5b
@ -3,6 +3,6 @@ package api
|
||||
import "github.com/usememos/memos/server/profile"
|
||||
|
||||
type SystemStatus struct {
|
||||
Owner *User `json:"owner"`
|
||||
Host *User `json:"host"`
|
||||
Profile *profile.Profile `json:"profile"`
|
||||
}
|
||||
|
@ -4,16 +4,16 @@ package api
|
||||
type Role string
|
||||
|
||||
const (
|
||||
// Owner is the OWNER role.
|
||||
Owner Role = "OWNER"
|
||||
// Host is the HOST role.
|
||||
Host Role = "HOST"
|
||||
// NormalUser is the USER role.
|
||||
NormalUser Role = "USER"
|
||||
)
|
||||
|
||||
func (e Role) String() string {
|
||||
switch e {
|
||||
case Owner:
|
||||
return "OWNER"
|
||||
case Host:
|
||||
return "HOST"
|
||||
case NormalUser:
|
||||
return "USER"
|
||||
}
|
||||
|
@ -60,17 +60,17 @@ func (s *Server) registerAuthRoutes(g *echo.Group) {
|
||||
})
|
||||
|
||||
g.POST("/auth/signup", func(c echo.Context) error {
|
||||
// Don't allow to signup by this api if site owner existed.
|
||||
ownerUserType := api.Owner
|
||||
ownerUserFind := api.UserFind{
|
||||
Role: &ownerUserType,
|
||||
// Don't allow to signup by this api if site host existed.
|
||||
hostUserType := api.Host
|
||||
hostUserFind := api.UserFind{
|
||||
Role: &hostUserType,
|
||||
}
|
||||
ownerUser, err := s.Store.FindUser(&ownerUserFind)
|
||||
hostUser, err := s.Store.FindUser(&hostUserFind)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find owner user").SetInternal(err)
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find host user").SetInternal(err)
|
||||
}
|
||||
if ownerUser != nil {
|
||||
return echo.NewHTTPError(http.StatusUnauthorized, "Site Owner existed, please contact the site owner to signin account firstly.").SetInternal(err)
|
||||
if hostUser != nil {
|
||||
return echo.NewHTTPError(http.StatusUnauthorized, "Site Host existed, please contact the site host to signin account firstly.").SetInternal(err)
|
||||
}
|
||||
|
||||
signup := &api.Signup{}
|
||||
|
@ -21,22 +21,22 @@ func (s *Server) registerSystemRoutes(g *echo.Group) {
|
||||
})
|
||||
|
||||
g.GET("/status", func(c echo.Context) error {
|
||||
ownerUserType := api.Owner
|
||||
ownerUserFind := api.UserFind{
|
||||
Role: &ownerUserType,
|
||||
hostUserType := api.Host
|
||||
hostUserFind := api.UserFind{
|
||||
Role: &hostUserType,
|
||||
}
|
||||
ownerUser, err := s.Store.FindUser(&ownerUserFind)
|
||||
hostUser, err := s.Store.FindUser(&hostUserFind)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find owner user").SetInternal(err)
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, "Failed to find host user").SetInternal(err)
|
||||
}
|
||||
|
||||
if ownerUser != nil {
|
||||
if hostUser != nil {
|
||||
// data desensitize
|
||||
ownerUser.OpenID = ""
|
||||
hostUser.OpenID = ""
|
||||
}
|
||||
|
||||
systemStatus := api.SystemStatus{
|
||||
Owner: ownerUser,
|
||||
Host: hostUser,
|
||||
Profile: s.Profile,
|
||||
}
|
||||
|
||||
|
@ -143,7 +143,7 @@ func (s *Server) registerUserRoutes(g *echo.Group) {
|
||||
}
|
||||
if currentUser == nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Current session user not found with ID: %d", currentUserID)).SetInternal(err)
|
||||
} else if currentUser.Role != api.Owner {
|
||||
} else if currentUser.Role != api.Host {
|
||||
return echo.NewHTTPError(http.StatusForbidden, "Access forbidden for current session user").SetInternal(err)
|
||||
}
|
||||
|
||||
|
56
store/db/migration/0.2/00__user_role.sql
Normal file
56
store/db/migration/0.2/00__user_role.sql
Normal file
@ -0,0 +1,56 @@
|
||||
-- change user role field from "OWNER"/"USER" to "HOST"/"USER".
|
||||
|
||||
PRAGMA foreign_keys = off;
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
DROP TABLE IF EXISTS _user_old;
|
||||
|
||||
ALTER TABLE
|
||||
user RENAME TO _user_old;
|
||||
|
||||
CREATE TABLE user (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
created_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
updated_ts BIGINT NOT NULL DEFAULT (strftime('%s', 'now')),
|
||||
row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL',
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
role TEXT NOT NULL CHECK (role IN ('HOST', 'USER')) DEFAULT 'USER',
|
||||
name TEXT NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
open_id TEXT NOT NULL UNIQUE
|
||||
);
|
||||
|
||||
INSERT INTO user (
|
||||
id, created_ts, updated_ts, row_status,
|
||||
email, name, password_hash, open_id
|
||||
)
|
||||
SELECT
|
||||
id,
|
||||
created_ts,
|
||||
updated_ts,
|
||||
row_status,
|
||||
email,
|
||||
name,
|
||||
password_hash,
|
||||
open_id
|
||||
FROM
|
||||
_user_old;
|
||||
|
||||
UPDATE
|
||||
user
|
||||
SET
|
||||
role = 'HOST'
|
||||
WHERE
|
||||
id IN (
|
||||
SELECT
|
||||
id
|
||||
FROM
|
||||
_user_old
|
||||
WHERE
|
||||
role = 'OWNER'
|
||||
);
|
||||
|
||||
DROP TABLE IF EXISTS _user_old;
|
||||
|
||||
COMMIT;
|
||||
PRAGMA foreign_keys = on;
|
@ -13,7 +13,7 @@ CREATE TABLE user (
|
||||
-- allowed row status are 'NORMAL', 'ARCHIVED'.
|
||||
row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL',
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
role TEXT NOT NULL CHECK (role IN ('OWNER', 'USER')) DEFAULT 'USER',
|
||||
role TEXT NOT NULL CHECK (role IN ('HOST', 'USER')) DEFAULT 'USER',
|
||||
name TEXT NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
open_id TEXT NOT NULL UNIQUE
|
||||
|
@ -11,8 +11,8 @@ VALUES
|
||||
(
|
||||
101,
|
||||
'demo@usememos.com',
|
||||
'OWNER',
|
||||
'Demo Owner',
|
||||
'HOST',
|
||||
'Demo Host',
|
||||
'demo_open_id',
|
||||
-- raw password: secret
|
||||
'$2a$14$ajq8Q7fbtFRQvXpdCq7Jcuy.Rx1h/L4J60Otx.gyNLbAYctGMJ9tK'
|
||||
|
@ -106,7 +106,7 @@ func createUser(db *sql.DB, create *api.UserCreate) (*userRaw, error) {
|
||||
open_id
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
RETURNING id, email, role, name, password_hash, open_id, created_ts, updated_ts
|
||||
RETURNING id, email, role, name, password_hash, open_id, created_ts, updated_ts, row_status
|
||||
`,
|
||||
create.Email,
|
||||
create.Role,
|
||||
@ -130,6 +130,7 @@ func createUser(db *sql.DB, create *api.UserCreate) (*userRaw, error) {
|
||||
&userRaw.OpenID,
|
||||
&userRaw.CreatedTs,
|
||||
&userRaw.UpdatedTs,
|
||||
&userRaw.RowStatus,
|
||||
); err != nil {
|
||||
return nil, FormatError(err)
|
||||
}
|
||||
@ -162,7 +163,7 @@ func patchUser(db *sql.DB, patch *api.UserPatch) (*userRaw, error) {
|
||||
UPDATE user
|
||||
SET `+strings.Join(set, ", ")+`
|
||||
WHERE id = ?
|
||||
RETURNING id, email, role, name, password_hash, open_id, created_ts, updated_ts
|
||||
RETURNING id, email, role, name, password_hash, open_id, created_ts, updated_ts, row_status
|
||||
`, args...)
|
||||
if err != nil {
|
||||
return nil, FormatError(err)
|
||||
@ -180,6 +181,7 @@ func patchUser(db *sql.DB, patch *api.UserPatch) (*userRaw, error) {
|
||||
&userRaw.OpenID,
|
||||
&userRaw.CreatedTs,
|
||||
&userRaw.UpdatedTs,
|
||||
&userRaw.RowStatus,
|
||||
); err != nil {
|
||||
return nil, FormatError(err)
|
||||
}
|
||||
@ -218,7 +220,8 @@ func findUserList(db *sql.DB, find *api.UserFind) ([]*userRaw, error) {
|
||||
password_hash,
|
||||
open_id,
|
||||
created_ts,
|
||||
updated_ts
|
||||
updated_ts,
|
||||
row_status
|
||||
FROM user
|
||||
WHERE `+strings.Join(where, " AND ")+`
|
||||
ORDER BY created_ts DESC`,
|
||||
@ -241,6 +244,7 @@ func findUserList(db *sql.DB, find *api.UserFind) ([]*userRaw, error) {
|
||||
&userRaw.OpenID,
|
||||
&userRaw.CreatedTs,
|
||||
&userRaw.UpdatedTs,
|
||||
&userRaw.RowStatus,
|
||||
); err != nil {
|
||||
fmt.Println(err)
|
||||
return nil, FormatError(err)
|
||||
|
@ -48,7 +48,7 @@ const SettingDialog: React.FC<Props> = (props: Props) => {
|
||||
<span className="icon-text">🏟</span> Preferences
|
||||
</span>
|
||||
</div>
|
||||
{user?.role === "OWNER" ? (
|
||||
{user?.role === "HOST" ? (
|
||||
<>
|
||||
<span className="section-title">Admin</span>
|
||||
<div className="section-items-container">
|
||||
|
@ -28,7 +28,7 @@ const UserBanner: React.FC<Props> = () => {
|
||||
if (locationService.getState().pathname === "/") {
|
||||
api.getSystemStatus().then(({ data }) => {
|
||||
const { data: status } = data;
|
||||
setUsername(status.owner.name);
|
||||
setUsername(status.host.name);
|
||||
});
|
||||
} else {
|
||||
const currentUserId = userService.getCurrentUserId();
|
||||
@ -51,7 +51,7 @@ const UserBanner: React.FC<Props> = () => {
|
||||
<div className="user-banner-container">
|
||||
<div className="username-container" onClick={handleUsernameClick}>
|
||||
<span className="username-text">{username}</span>
|
||||
{user?.role === "OWNER" ? <span className="tag">MOD</span> : null}
|
||||
{user?.role === "HOST" ? <span className="tag">MOD</span> : null}
|
||||
</div>
|
||||
<span className="action-btn menu-popup-btn" onClick={handlePopupBtnClick}>
|
||||
<img src="/icons/more.svg" className="icon-img" />
|
||||
|
@ -69,7 +69,7 @@
|
||||
> .tip-text {
|
||||
@apply w-auto inline-block float-right text-sm mt-4 text-gray-500 text-right whitespace-pre-wrap;
|
||||
|
||||
&.owner-tip {
|
||||
&.host-tip {
|
||||
@apply bg-blue-500 text-white px-2 py-1 rounded;
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ const validateConfig: ValidatorConfig = {
|
||||
|
||||
const Signin: React.FC<Props> = () => {
|
||||
const pageLoadingState = useLoading(true);
|
||||
const [siteOwner, setSiteOwner] = useState<User>();
|
||||
const [siteHost, setSiteHost] = useState<User>();
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const actionBtnLoadingState = useLoading(false);
|
||||
@ -25,7 +25,7 @@ const Signin: React.FC<Props> = () => {
|
||||
useEffect(() => {
|
||||
api.getSystemStatus().then(({ data }) => {
|
||||
const { data: status } = data;
|
||||
setSiteOwner(status.owner);
|
||||
setSiteHost(status.host);
|
||||
if (status.profile.mode === "dev") {
|
||||
setEmail("demo@usememos.com");
|
||||
setPassword("secret");
|
||||
@ -77,7 +77,7 @@ const Signin: React.FC<Props> = () => {
|
||||
actionBtnLoadingState.setFinish();
|
||||
};
|
||||
|
||||
const handleSignUpAsOwnerBtnsClick = async () => {
|
||||
const handleSignUpAsHostBtnsClick = async () => {
|
||||
if (actionBtnLoadingState.isLoading) {
|
||||
return;
|
||||
}
|
||||
@ -96,7 +96,7 @@ const Signin: React.FC<Props> = () => {
|
||||
|
||||
try {
|
||||
actionBtnLoadingState.setLoading();
|
||||
await api.signup(email, password, "OWNER");
|
||||
await api.signup(email, password, "HOST");
|
||||
const user = await userService.doSignIn();
|
||||
if (user) {
|
||||
locationService.replaceHistory("/");
|
||||
@ -132,7 +132,7 @@ const Signin: React.FC<Props> = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="action-btns-container">
|
||||
{siteOwner || pageLoadingState.isLoading ? (
|
||||
{siteHost || pageLoadingState.isLoading ? (
|
||||
<button
|
||||
className={`btn signin-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
|
||||
onClick={() => handleSigninBtnsClick()}
|
||||
@ -142,16 +142,16 @@ const Signin: React.FC<Props> = () => {
|
||||
) : (
|
||||
<button
|
||||
className={`btn signin-btn ${actionBtnLoadingState.isLoading ? "requesting" : ""}`}
|
||||
onClick={() => handleSignUpAsOwnerBtnsClick()}
|
||||
onClick={() => handleSignUpAsHostBtnsClick()}
|
||||
>
|
||||
Sign up as Owner
|
||||
Sign up as Host
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
<p className={`tip-text ${siteOwner || pageLoadingState.isLoading ? "" : "owner-tip"}`}>
|
||||
{siteOwner || pageLoadingState.isLoading
|
||||
? "If you don't have an account, please\ncontact the site owner."
|
||||
: "You are registering as the Site Owner."}
|
||||
<p className={`tip-text ${siteHost || pageLoadingState.isLoading ? "" : "host-tip"}`}>
|
||||
{siteHost || pageLoadingState.isLoading
|
||||
? "If you don't have an account, please\ncontact the site host."
|
||||
: "You are registering as the Site Host."}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
2
web/src/types/modules/system.d.ts
vendored
2
web/src/types/modules/system.d.ts
vendored
@ -4,6 +4,6 @@ interface Profile {
|
||||
}
|
||||
|
||||
interface SystemStatus {
|
||||
owner: User;
|
||||
host: User;
|
||||
profile: Profile;
|
||||
}
|
||||
|
2
web/src/types/modules/user.d.ts
vendored
2
web/src/types/modules/user.d.ts
vendored
@ -1,5 +1,5 @@
|
||||
type UserId = number;
|
||||
type UserRole = "OWNER" | "USER";
|
||||
type UserRole = "HOST" | "USER";
|
||||
|
||||
interface User {
|
||||
id: UserId;
|
||||
|
Loading…
Reference in New Issue
Block a user