mirror of
https://github.com/aykhans/slash-e.git
synced 2025-04-20 22:07:15 +00:00
chore: remove username field from user table
This commit is contained in:
parent
8dfae8a6aa
commit
2aae515544
@ -21,12 +21,12 @@ func getUserIDContextKey() string {
|
||||
}
|
||||
|
||||
type SignInRequest struct {
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type SignUpRequest struct {
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
@ -39,20 +39,20 @@ func (s *APIV1Service) registerAuthRoutes(g *echo.Group, secret string) {
|
||||
}
|
||||
|
||||
user, err := s.Store.GetUser(ctx, &store.FindUser{
|
||||
Username: &signin.Username,
|
||||
Email: &signin.Email,
|
||||
})
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to find user by username %s", signin.Username)).SetInternal(err)
|
||||
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to find user by email %s", signin.Email)).SetInternal(err)
|
||||
}
|
||||
if user == nil {
|
||||
return echo.NewHTTPError(http.StatusUnauthorized, fmt.Sprintf("User not found with username %s", signin.Username))
|
||||
return echo.NewHTTPError(http.StatusUnauthorized, fmt.Sprintf("User not found with email %s", signin.Email))
|
||||
} else if user.RowStatus == store.Archived {
|
||||
return echo.NewHTTPError(http.StatusForbidden, fmt.Sprintf("User has been archived with username %s", signin.Username))
|
||||
return echo.NewHTTPError(http.StatusForbidden, fmt.Sprintf("User has been archived with email %s", signin.Email))
|
||||
}
|
||||
|
||||
// Compare the stored hashed password, with the hashed version of the password that was received.
|
||||
if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(signin.Password)); err != nil {
|
||||
return echo.NewHTTPError(http.StatusUnauthorized, "Unmatched username and password").SetInternal(err)
|
||||
return echo.NewHTTPError(http.StatusUnauthorized, "Unmatched email and password").SetInternal(err)
|
||||
}
|
||||
|
||||
if err := auth.GenerateTokensAndSetCookies(c, user, secret); err != nil {
|
||||
@ -74,8 +74,8 @@ func (s *APIV1Service) registerAuthRoutes(g *echo.Group, secret string) {
|
||||
}
|
||||
|
||||
create := &store.User{
|
||||
Username: signup.Username,
|
||||
Nickname: signup.Username,
|
||||
Email: signup.Email,
|
||||
Nickname: signup.Email,
|
||||
PasswordHash: string(passwordHash),
|
||||
}
|
||||
existingUsers, err := s.Store.ListUsers(ctx, &store.FindUser{})
|
||||
|
@ -42,30 +42,25 @@ type User struct {
|
||||
RowStatus RowStatus `json:"rowStatus"`
|
||||
|
||||
// Domain specific fields
|
||||
Username string `json:"username"`
|
||||
Nickname string `json:"nickname"`
|
||||
Email string `json:"email"`
|
||||
Nickname string `json:"nickname"`
|
||||
Role Role `json:"role"`
|
||||
}
|
||||
|
||||
type CreateUserRequest struct {
|
||||
Username string `json:"username"`
|
||||
Nickname string `json:"nickname"`
|
||||
Email string `json:"email"`
|
||||
Nickname string `json:"nickname"`
|
||||
Password string `json:"password"`
|
||||
Role Role `json:"-"`
|
||||
}
|
||||
|
||||
func (create CreateUserRequest) Validate() error {
|
||||
if len(create.Username) < 3 {
|
||||
return fmt.Errorf("username is too short, minimum length is 3")
|
||||
}
|
||||
if create.Nickname != "" && len(create.Nickname) < 3 {
|
||||
return fmt.Errorf("username is too short, minimum length is 3")
|
||||
}
|
||||
if create.Email != "" && !validateEmail(create.Email) {
|
||||
return fmt.Errorf("invalid email format")
|
||||
}
|
||||
if create.Nickname != "" && len(create.Nickname) < 3 {
|
||||
return fmt.Errorf("nickname is too short, minimum length is 3")
|
||||
}
|
||||
if len(create.Password) < 3 {
|
||||
return fmt.Errorf("password is too short, minimum length is 3")
|
||||
}
|
||||
@ -228,9 +223,8 @@ func convertUserFromStore(user *store.User) *User {
|
||||
CreatedTs: user.CreatedTs,
|
||||
UpdatedTs: user.UpdatedTs,
|
||||
RowStatus: RowStatus(user.RowStatus),
|
||||
Username: user.Username,
|
||||
Nickname: user.Nickname,
|
||||
Email: user.Email,
|
||||
Nickname: user.Nickname,
|
||||
Role: Role(user.Role),
|
||||
}
|
||||
}
|
||||
|
@ -46,26 +46,26 @@ type claimsMessage struct {
|
||||
}
|
||||
|
||||
// GenerateAPIToken generates an API token.
|
||||
func GenerateAPIToken(userName string, userID int, secret string) (string, error) {
|
||||
func GenerateAPIToken(username string, userID int, secret string) (string, error) {
|
||||
expirationTime := time.Now().Add(apiTokenDuration)
|
||||
return generateToken(userName, userID, AccessTokenAudienceName, expirationTime, []byte(secret))
|
||||
return generateToken(username, userID, AccessTokenAudienceName, expirationTime, []byte(secret))
|
||||
}
|
||||
|
||||
// GenerateAccessToken generates an access token for web.
|
||||
func GenerateAccessToken(userName string, userID int, secret string) (string, error) {
|
||||
func GenerateAccessToken(username string, userID int, secret string) (string, error) {
|
||||
expirationTime := time.Now().Add(accessTokenDuration)
|
||||
return generateToken(userName, userID, AccessTokenAudienceName, expirationTime, []byte(secret))
|
||||
return generateToken(username, userID, AccessTokenAudienceName, expirationTime, []byte(secret))
|
||||
}
|
||||
|
||||
// GenerateRefreshToken generates a refresh token for web.
|
||||
func GenerateRefreshToken(userName string, userID int, secret string) (string, error) {
|
||||
func GenerateRefreshToken(username string, userID int, secret string) (string, error) {
|
||||
expirationTime := time.Now().Add(refreshTokenDuration)
|
||||
return generateToken(userName, userID, RefreshTokenAudienceName, expirationTime, []byte(secret))
|
||||
return generateToken(username, userID, RefreshTokenAudienceName, expirationTime, []byte(secret))
|
||||
}
|
||||
|
||||
// GenerateTokensAndSetCookies generates jwt token and saves it to the http-only cookie.
|
||||
func GenerateTokensAndSetCookies(c echo.Context, user *store.User, secret string) error {
|
||||
accessToken, err := GenerateAccessToken(user.Username, user.ID, secret)
|
||||
accessToken, err := GenerateAccessToken(user.Email, user.ID, secret)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate access token")
|
||||
}
|
||||
@ -74,7 +74,7 @@ func GenerateTokensAndSetCookies(c echo.Context, user *store.User, secret string
|
||||
setTokenCookie(c, AccessTokenCookieName, accessToken, cookieExp)
|
||||
|
||||
// We generate here a new refresh token and saving it to the cookie.
|
||||
refreshToken, err := GenerateRefreshToken(user.Username, user.ID, secret)
|
||||
refreshToken, err := GenerateRefreshToken(user.Email, user.ID, secret)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate refresh token")
|
||||
}
|
||||
|
@ -16,9 +16,8 @@ CREATE TABLE user (
|
||||
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',
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
nickname TEXT NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
role TEXT NOT NULL CHECK (role IN ('ADMIN', 'USER')) DEFAULT 'USER'
|
||||
);
|
||||
|
@ -16,9 +16,8 @@ CREATE TABLE user (
|
||||
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',
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
email TEXT NOT NULL UNIQUE,
|
||||
nickname TEXT NOT NULL,
|
||||
email TEXT NOT NULL,
|
||||
password_hash TEXT NOT NULL,
|
||||
role TEXT NOT NULL CHECK (role IN ('ADMIN', 'USER')) DEFAULT 'USER'
|
||||
);
|
||||
|
@ -26,9 +26,8 @@ type User struct {
|
||||
RowStatus RowStatus
|
||||
|
||||
// Domain specific fields
|
||||
Username string
|
||||
Nickname string
|
||||
Email string
|
||||
Nickname string
|
||||
PasswordHash string
|
||||
Role Role
|
||||
}
|
||||
@ -37,9 +36,8 @@ type UpdateUser struct {
|
||||
ID int
|
||||
|
||||
RowStatus *RowStatus
|
||||
Username *string
|
||||
Nickname *string
|
||||
Email *string
|
||||
Nickname *string
|
||||
PasswordHash *string
|
||||
Role *Role
|
||||
}
|
||||
@ -47,9 +45,8 @@ type UpdateUser struct {
|
||||
type FindUser struct {
|
||||
ID *int
|
||||
RowStatus *RowStatus
|
||||
Username *string
|
||||
Nickname *string
|
||||
Email *string
|
||||
Nickname *string
|
||||
Role *Role
|
||||
}
|
||||
|
||||
@ -66,19 +63,17 @@ func (s *Store) CreateUser(ctx context.Context, create *User) (*User, error) {
|
||||
|
||||
query := `
|
||||
INSERT INTO user (
|
||||
username,
|
||||
nickname,
|
||||
email,
|
||||
nickname,
|
||||
password_hash,
|
||||
role
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
VALUES (?, ?, ?, ?)
|
||||
RETURNING id, created_ts, updated_ts, row_status
|
||||
`
|
||||
if err := tx.QueryRowContext(ctx, query,
|
||||
create.Username,
|
||||
create.Nickname,
|
||||
create.Email,
|
||||
create.Nickname,
|
||||
create.PasswordHash,
|
||||
create.Role,
|
||||
).Scan(
|
||||
@ -110,15 +105,12 @@ func (s *Store) UpdateUser(ctx context.Context, update *UpdateUser) (*User, erro
|
||||
if v := update.RowStatus; v != nil {
|
||||
set, args = append(set, "row_status = ?"), append(args, *v)
|
||||
}
|
||||
if v := update.Username; v != nil {
|
||||
set, args = append(set, "username = ?"), append(args, *v)
|
||||
if v := update.Email; v != nil {
|
||||
set, args = append(set, "email = ?"), append(args, *v)
|
||||
}
|
||||
if v := update.Nickname; v != nil {
|
||||
set, args = append(set, "nickname = ?"), append(args, *v)
|
||||
}
|
||||
if v := update.Email; v != nil {
|
||||
set, args = append(set, "email = ?"), append(args, *v)
|
||||
}
|
||||
if v := update.PasswordHash; v != nil {
|
||||
set, args = append(set, "password_hash = ?"), append(args, *v)
|
||||
}
|
||||
@ -134,7 +126,7 @@ func (s *Store) UpdateUser(ctx context.Context, update *UpdateUser) (*User, erro
|
||||
UPDATE user
|
||||
SET ` + strings.Join(set, ", ") + `
|
||||
WHERE id = ?
|
||||
RETURNING id, created_ts, updated_ts, row_status, username, nickname, email, password_hash, role
|
||||
RETURNING id, created_ts, updated_ts, row_status, email, nickname, password_hash, role
|
||||
`
|
||||
args = append(args, update.ID)
|
||||
user := &User{}
|
||||
@ -143,9 +135,8 @@ func (s *Store) UpdateUser(ctx context.Context, update *UpdateUser) (*User, erro
|
||||
&user.CreatedTs,
|
||||
&user.UpdatedTs,
|
||||
&user.RowStatus,
|
||||
&user.Username,
|
||||
&user.Nickname,
|
||||
&user.Email,
|
||||
&user.Nickname,
|
||||
&user.PasswordHash,
|
||||
&user.Role,
|
||||
); err != nil {
|
||||
@ -236,15 +227,12 @@ func listUsers(ctx context.Context, tx *sql.Tx, find *FindUser) ([]*User, error)
|
||||
if v := find.RowStatus; v != nil {
|
||||
where, args = append(where, "row_status = ?"), append(args, v.String())
|
||||
}
|
||||
if v := find.Username; v != nil {
|
||||
where, args = append(where, "username = ?"), append(args, *v)
|
||||
if v := find.Email; v != nil {
|
||||
where, args = append(where, "email = ?"), append(args, *v)
|
||||
}
|
||||
if v := find.Nickname; v != nil {
|
||||
where, args = append(where, "nickname = ?"), append(args, *v)
|
||||
}
|
||||
if v := find.Email; v != nil {
|
||||
where, args = append(where, "email = ?"), append(args, *v)
|
||||
}
|
||||
if v := find.Role; v != nil {
|
||||
where, args = append(where, "role = ?"), append(args, *v)
|
||||
}
|
||||
@ -255,9 +243,8 @@ func listUsers(ctx context.Context, tx *sql.Tx, find *FindUser) ([]*User, error)
|
||||
created_ts,
|
||||
updated_ts,
|
||||
row_status,
|
||||
username,
|
||||
nickname,
|
||||
email,
|
||||
nickname,
|
||||
password_hash,
|
||||
role
|
||||
FROM user
|
||||
@ -278,9 +265,8 @@ func listUsers(ctx context.Context, tx *sql.Tx, find *FindUser) ([]*User, error)
|
||||
&user.CreatedTs,
|
||||
&user.UpdatedTs,
|
||||
&user.RowStatus,
|
||||
&user.Username,
|
||||
&user.Nickname,
|
||||
&user.Email,
|
||||
&user.Nickname,
|
||||
&user.PasswordHash,
|
||||
&user.Role,
|
||||
); err != nil {
|
||||
|
@ -40,9 +40,8 @@ func TestUserStore(t *testing.T) {
|
||||
func createTestingAdminUser(ctx context.Context, ts *store.Store) (*store.User, error) {
|
||||
userCreate := &store.User{
|
||||
Role: store.RoleAdmin,
|
||||
Username: "test",
|
||||
Nickname: "test_nickname",
|
||||
Email: "test@test.com",
|
||||
Nickname: "test_nickname",
|
||||
}
|
||||
passwordHash, err := bcrypt.GenerateFromPassword([]byte("test-password"), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
|
@ -4,16 +4,16 @@ export function getSystemStatus() {
|
||||
return axios.get<SystemStatus>("/api/v1/status");
|
||||
}
|
||||
|
||||
export function signin(username: string, password: string) {
|
||||
export function signin(email: string, password: string) {
|
||||
return axios.post<User>("/api/v1/auth/signin", {
|
||||
username,
|
||||
email,
|
||||
password,
|
||||
});
|
||||
}
|
||||
|
||||
export function signup(username: string, password: string) {
|
||||
export function signup(email: string, password: string) {
|
||||
return axios.post<User>("/api/v1/auth/signup", {
|
||||
username,
|
||||
email,
|
||||
password,
|
||||
});
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import Icon from "../components/Icon";
|
||||
|
||||
const Auth: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const [username, setUsername] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const actionBtnLoadingState = useLoading(false);
|
||||
|
||||
@ -20,9 +20,9 @@ const Auth: React.FC = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleUsernameInputChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const handleEmailInputChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const text = e.target.value as string;
|
||||
setUsername(text);
|
||||
setEmail(text);
|
||||
};
|
||||
|
||||
const handlePasswordInputChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
@ -37,7 +37,7 @@ const Auth: React.FC = () => {
|
||||
|
||||
try {
|
||||
actionBtnLoadingState.setLoading();
|
||||
await api.signin(username, password);
|
||||
await api.signin(email, password);
|
||||
const user = await userService.doSignIn();
|
||||
if (user) {
|
||||
navigate("/", {
|
||||
@ -60,7 +60,7 @@ const Auth: React.FC = () => {
|
||||
|
||||
try {
|
||||
actionBtnLoadingState.setLoading();
|
||||
await api.signup(username, password);
|
||||
await api.signup(email, password);
|
||||
const user = await userService.doSignIn();
|
||||
if (user) {
|
||||
navigate("/", {
|
||||
@ -89,8 +89,8 @@ const Auth: React.FC = () => {
|
||||
</div>
|
||||
<div className={`flex flex-col justify-start items-start w-full ${actionBtnLoadingState.isLoading ? "opacity-80" : ""}`}>
|
||||
<div className="w-full flex flex-col mb-2">
|
||||
<span className="leading-8 mb-1 text-gray-600">Username</span>
|
||||
<Input className="w-full py-3" type="username" value={username} onChange={handleUsernameInputChanged} />
|
||||
<span className="leading-8 mb-1 text-gray-600">Email</span>
|
||||
<Input className="w-full py-3" type="email" value={email} onChange={handleEmailInputChanged} />
|
||||
</div>
|
||||
<div className="w-full flex flex-col mb-2">
|
||||
<span className="leading-8 text-gray-600">Password</span>
|
||||
|
@ -16,13 +16,11 @@ const UserDetail: React.FC = () => {
|
||||
showChangePasswordDialog: false,
|
||||
});
|
||||
|
||||
console.log("here");
|
||||
useEffect(() => {
|
||||
if (!userService.getState().user) {
|
||||
navigate("/user/auth");
|
||||
return;
|
||||
}
|
||||
console.log("here");
|
||||
}, []);
|
||||
|
||||
const handleChangePasswordBtnClick = async () => {
|
||||
|
3
web/src/types/modules/user.d.ts
vendored
3
web/src/types/modules/user.d.ts
vendored
@ -9,9 +9,8 @@ interface User {
|
||||
updatedTs: TimeStamp;
|
||||
rowStatus: RowStatus;
|
||||
|
||||
username: string;
|
||||
nickname: string;
|
||||
email: string;
|
||||
nickname: string;
|
||||
role: Role;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user