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