support for users without a password to change their password

This commit is contained in:
MaysWind
2025-10-22 00:15:39 +08:00
parent a42c5fa988
commit 6395e3b5c1
5 changed files with 12 additions and 9 deletions
+1 -1
View File
@@ -277,7 +277,7 @@ func (a *UsersApi) UserUpdateProfileHandler(c *core.WebContext) (any, *errs.Erro
return nil, errs.ErrNotPermittedToPerformThisAction return nil, errs.ErrNotPermittedToPerformThisAction
} }
if !a.users.IsPasswordEqualsUserPassword(userUpdateReq.OldPassword, user) { if user.Password != "" && !a.users.IsPasswordEqualsUserPassword(userUpdateReq.OldPassword, user) {
return nil, errs.ErrUserPasswordWrong return nil, errs.ErrUserPasswordWrong
} }
+2
View File
@@ -225,6 +225,7 @@ type UserProfileUpdateResponse struct {
// UserProfileResponse represents a view-object of user profile // UserProfileResponse represents a view-object of user profile
type UserProfileResponse struct { type UserProfileResponse struct {
*UserBasicInfo *UserBasicInfo
NoPassword bool `json:"noPassword,omitempty"`
LastLoginAt int64 `json:"lastLoginAt"` LastLoginAt int64 `json:"lastLoginAt"`
} }
@@ -313,6 +314,7 @@ func (u *User) ToUserBasicInfo(avatarProvider core.UserAvatarProviderType, avata
func (u *User) ToUserProfileResponse(basicInfo *UserBasicInfo) *UserProfileResponse { func (u *User) ToUserProfileResponse(basicInfo *UserBasicInfo) *UserProfileResponse {
return &UserProfileResponse{ return &UserProfileResponse{
UserBasicInfo: basicInfo, UserBasicInfo: basicInfo,
NoPassword: u.Password == "",
LastLoginAt: u.LastLoginUnixTime, LastLoginAt: u.LastLoginUnixTime,
} }
} }
+1
View File
@@ -233,6 +233,7 @@ export interface UserProfileUpdateResponse {
} }
export interface UserProfileResponse extends UserBasicInfo { export interface UserProfileResponse extends UserBasicInfo {
readonly noPassword?: boolean;
readonly lastLoginAt: number; readonly lastLoginAt: number;
} }
@@ -54,7 +54,7 @@
</v-card-text> </v-card-text>
<v-card-text class="d-flex flex-wrap gap-4"> <v-card-text class="d-flex flex-wrap gap-4">
<v-btn :disabled="!currentPassword || !newPassword || !confirmPassword || updatingPassword" @click="updatePassword"> <v-btn :disabled="!newPassword || !confirmPassword || updatingPassword" @click="updatePassword">
{{ tt('Save Changes') }} {{ tt('Save Changes') }}
<v-progress-circular indeterminate size="22" class="ms-2" v-if="updatingPassword"></v-progress-circular> <v-progress-circular indeterminate size="22" class="ms-2" v-if="updatingPassword"></v-progress-circular>
</v-btn> </v-btn>
@@ -213,9 +213,7 @@ const sessions = computed<DesktopPageSessionInfo[]>(() => {
}); });
const inputProblemMessage = computed<string | null>(() => { const inputProblemMessage = computed<string | null>(() => {
if (!currentPassword.value) { if (!newPassword.value && !confirmPassword.value) {
return 'Current password cannot be blank';
} else if (!newPassword.value && !confirmPassword.value) {
return 'Nothing has been modified'; return 'Nothing has been modified';
} else if (!newPassword.value && confirmPassword.value) { } else if (!newPassword.value && confirmPassword.value) {
return 'New password cannot be blank'; return 'New password cannot be blank';
+6 -4
View File
@@ -5,7 +5,7 @@
<f7-nav-title :title="tt('User Profile')"></f7-nav-title> <f7-nav-title :title="tt('User Profile')"></f7-nav-title>
<f7-nav-right class="navbar-compact-icons"> <f7-nav-right class="navbar-compact-icons">
<f7-link icon-f7="ellipsis" :class="{ 'disabled': !isUserVerifyEmailEnabled() || loading || emailVerified }" @click="showMoreActionSheet = true"></f7-link> <f7-link icon-f7="ellipsis" :class="{ 'disabled': !isUserVerifyEmailEnabled() || loading || emailVerified }" @click="showMoreActionSheet = true"></f7-link>
<f7-link :class="{ 'disabled': inputIsNotChanged || inputIsInvalid || saving }" :text="tt('Save')" @click="save"></f7-link> <f7-link :class="{ 'disabled': inputIsNotChanged || inputIsInvalid || saving }" :text="tt('Save')" @click="save(currentNoPassword)"></f7-link>
</f7-nav-right> </f7-nav-right>
</f7-navbar> </f7-navbar>
@@ -551,7 +551,7 @@
:cancel-disabled="saving" :cancel-disabled="saving"
v-model:show="showInputPasswordSheet" v-model:show="showInputPasswordSheet"
v-model="currentPassword" v-model="currentPassword"
@password:confirm="save()"> @password:confirm="save(true)">
</password-input-sheet> </password-input-sheet>
</f7-page> </f7-page>
</template> </template>
@@ -639,6 +639,7 @@ const userStore = useUserStore();
const accountsStore = useAccountsStore(); const accountsStore = useAccountsStore();
const currentPassword = ref<string>(''); const currentPassword = ref<string>('');
const currentNoPassword = ref<boolean>(false);
const loadingError = ref<unknown | null>(null); const loadingError = ref<unknown | null>(null);
const showInputPasswordSheet = ref<boolean>(false); const showInputPasswordSheet = ref<boolean>(false);
const showAccountSheet = ref<boolean>(false); const showAccountSheet = ref<boolean>(false);
@@ -690,6 +691,7 @@ function init(): void {
Promise.all(promises).then(responses => { Promise.all(promises).then(responses => {
const profile = responses[1] as UserProfileResponse; const profile = responses[1] as UserProfileResponse;
setCurrentUserProfile(profile); setCurrentUserProfile(profile);
currentNoPassword.value = !!profile.noPassword;
loading.value = false; loading.value = false;
}).catch(error => { }).catch(error => {
if (error.processed) { if (error.processed) {
@@ -701,7 +703,7 @@ function init(): void {
}); });
} }
function save(): void { function save(confirm?: boolean): void {
const router = props.f7router; const router = props.f7router;
showInputPasswordSheet.value = false; showInputPasswordSheet.value = false;
@@ -713,7 +715,7 @@ function save(): void {
return; return;
} }
if (newProfile.value.password && !currentPassword.value) { if (newProfile.value.password && !confirm) {
showInputPasswordSheet.value = true; showInputPasswordSheet.value = true;
return; return;
} }