Compare commits
1
Commits
main
...
v0.7.4-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5a40a6fc8 |
No files matched your search
@@ -2,6 +2,15 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. For commit guidelines, please refer to [Standard Version](https://github.com/conventional-changelog/standard-version).
|
||||
|
||||
## v0.7.4-beta
|
||||
|
||||
**Notes**:
|
||||
- Updated German translation. https://github.com/gtsteffaniak/filebrowser/pull/644
|
||||
|
||||
**BugFixes**:
|
||||
- windows control click https://github.com/gtsteffaniak/filebrowser/issues/642
|
||||
- create user issue https://github.com/gtsteffaniak/filebrowser/issues/647
|
||||
|
||||
## v0.7.3-beta
|
||||
|
||||
Note: OIDC changes require config update.
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
|
||||
storm "github.com/asdine/storm/v3"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/auth"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/errors"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/logger"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/settings"
|
||||
"github.com/gtsteffaniak/filebrowser/backend/common/utils"
|
||||
@@ -110,8 +109,8 @@ func quickSetup(store *Storage) {
|
||||
func CreateUser(userInfo users.User, asAdmin bool) error {
|
||||
newUser := &userInfo
|
||||
if userInfo.LoginMethod == "password" {
|
||||
if userInfo.Password != "" {
|
||||
return errors.ErrInvalidRequestParams
|
||||
if userInfo.Password == "" {
|
||||
return fmt.Errorf("password is required to create a password login user")
|
||||
}
|
||||
} else {
|
||||
hashpass, err := users.HashPwd(userInfo.Username)
|
||||
@@ -122,7 +121,7 @@ func CreateUser(userInfo users.User, asAdmin bool) error {
|
||||
}
|
||||
// must have username or password to create
|
||||
if userInfo.Username == "" {
|
||||
return errors.ErrInvalidRequestParams
|
||||
return fmt.Errorf("username is required to create a user")
|
||||
}
|
||||
logger.Debug(fmt.Sprintf("Creating user: %v %v", userInfo.Username, userInfo.Scopes))
|
||||
settings.ApplyUserDefaults(newUser)
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
@mouseup="cancelContext($event)"
|
||||
>
|
||||
<div @click="toggleClick" :class="{ 'gallery-div': galleryView }">
|
||||
<Icon :mimetype="type" :active="isSelected" :thumbnailUrl />
|
||||
<Icon :mimetype="type" :active="isSelected" :thumbnailUrl="thumbnailUrl" />
|
||||
</div>
|
||||
|
||||
<div class="text" :class="{ activecontent: isMaximized && isSelected }">
|
||||
@@ -364,7 +364,6 @@ export default {
|
||||
mutations.removeSelected(this.index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.shiftKey && this.selected.length > 0) {
|
||||
let fi = 0;
|
||||
let la = 0;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<input
|
||||
class="input input--block form-form"
|
||||
:class="{ 'invalid-form': invalidPassword }"
|
||||
aria-label="Password1"
|
||||
type="password"
|
||||
:placeholder="$t('settings.enterPassword')"
|
||||
v-model="passwordRef"
|
||||
@@ -21,6 +22,7 @@
|
||||
<input
|
||||
class="input input--block form-form"
|
||||
:class="{ 'flat-right': !isNew, 'invalid-form': invalidPassword }"
|
||||
aria-label="Password2"
|
||||
type="password"
|
||||
:placeholder="$t('settings.enterPasswordAgain')"
|
||||
v-model="user.password"
|
||||
@@ -50,34 +52,36 @@
|
||||
</p>
|
||||
|
||||
<div v-if="user.loginMethod == 'password' && passwordAvailable && isNew">
|
||||
<label for="password">{{ $t("settings.password") }}</label>
|
||||
<div class="form-group">
|
||||
<input
|
||||
class="input input--block form-form"
|
||||
:class="{ 'invalid-form': invalidPassword }"
|
||||
type="password"
|
||||
:placeholder="$t('settings.enterPassword')"
|
||||
v-model="passwordRef"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input
|
||||
class="input input--block form-form"
|
||||
:class="{ 'flat-right': !isNew, 'invalid-form': invalidPassword }"
|
||||
type="password"
|
||||
:placeholder="$t('settings.enterPasswordAgain')"
|
||||
v-model="user.password"
|
||||
id="password"
|
||||
/>
|
||||
<button
|
||||
v-if="!isNew"
|
||||
type="button"
|
||||
class="button form-button"
|
||||
@click="submitUpdatePassword"
|
||||
>
|
||||
{{ $t("buttons.update") }}
|
||||
</button>
|
||||
</div>
|
||||
<label for="password">{{ $t("settings.password") }}</label>
|
||||
<div class="form-group">
|
||||
<input
|
||||
class="input input--block form-form"
|
||||
:class="{ 'invalid-form': invalidPassword }"
|
||||
aria-label="Password1"
|
||||
type="password"
|
||||
:placeholder="$t('settings.enterPassword')"
|
||||
v-model="passwordRef"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input
|
||||
class="input input--block form-form"
|
||||
:class="{ 'flat-right': !isNew, 'invalid-form': invalidPassword }"
|
||||
type="password"
|
||||
:placeholder="$t('settings.enterPasswordAgain')"
|
||||
aria-label="Password2"
|
||||
v-model="user.password"
|
||||
id="password"
|
||||
/>
|
||||
<button
|
||||
v-if="!isNew"
|
||||
type="button"
|
||||
class="button form-button"
|
||||
@click="submitUpdatePassword"
|
||||
>
|
||||
{{ $t("buttons.update") }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -153,9 +157,9 @@
|
||||
<div v-if="stateUser.permissions.admin">
|
||||
<label for="loginMethod">{{ $t("settings.loginMethodDescription") }}</label>
|
||||
<select v-model="user.loginMethod" class="input input--block" id="loginMethod">
|
||||
<option value="password">Password</option>
|
||||
<option value="oidc">OIDC</option>
|
||||
<option value="proxy">Proxy</option>
|
||||
<option value="password">Password</option> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<option value="oidc">OIDC</option> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<option value="proxy">Proxy</option> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
</select>
|
||||
</div>
|
||||
<permissions v-if="stateUser.permissions.admin" :permissions="user.permissions" />
|
||||
@@ -221,7 +225,8 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
invalidPassword() {
|
||||
const matching = this.user.password != this.passwordRef && this.user.password.length > 0 ;
|
||||
const matching =
|
||||
this.user.password != this.passwordRef && this.user.password.length > 0;
|
||||
return matching;
|
||||
},
|
||||
passwordAvailable: () => passwordAvailable,
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
@action="multiAction"
|
||||
/>
|
||||
<search v-if="showSearch" />
|
||||
<title v-else-if="isSettings" class="topTitle">{{ $t('sidebar.settings') }}</title>
|
||||
<title v-else-if="isSettings" class="topTitle">{{ $t("sidebar.settings") }}</title>
|
||||
<title v-else class="topTitle">{{ req.name }}</title>
|
||||
<action
|
||||
v-if="isListingView"
|
||||
@@ -30,7 +30,6 @@
|
||||
<script>
|
||||
import router from "@/router";
|
||||
import { getters, state, mutations } from "@/store";
|
||||
import { removeLastDir } from "@/utils/url";
|
||||
import Action from "@/components/Action.vue";
|
||||
import Search from "@/components/Search.vue";
|
||||
|
||||
@@ -124,7 +123,7 @@ export default {
|
||||
} else {
|
||||
mutations.closeHovers();
|
||||
if (listingView === "settings") {
|
||||
router.push({path: "/files" });
|
||||
router.push({ path: "/files" });
|
||||
return;
|
||||
}
|
||||
mutations.replaceRequest({});
|
||||
|
||||
@@ -254,9 +254,7 @@ export default {
|
||||
if (!elem) {
|
||||
return 1;
|
||||
}
|
||||
let columns = Math.floor(
|
||||
elem.offsetWidth / this.columnWidth
|
||||
);
|
||||
let columns = Math.floor(elem.offsetWidth / this.columnWidth);
|
||||
if (columns === 0) columns = 1;
|
||||
return columns;
|
||||
},
|
||||
@@ -596,7 +594,7 @@ export default {
|
||||
let newPath = currentPath.substring(0, currentPath.lastIndexOf("/"));
|
||||
|
||||
if (modifierKeys) {
|
||||
if (!ctrlKey) {
|
||||
if (ctrlKey) {
|
||||
this.ctrKeyPressed = true;
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
<form @submit="save" class="card active" v-if="loaded">
|
||||
<div class="card-title">
|
||||
<h2 v-if="isNew">{{ $t("settings.newUser") }}</h2>
|
||||
<h2 v-else-if="actor.id == user.id"> {{ $t('settings.modifyCurrentUser') }} ({{ user.username }})</h2> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<h2 v-else> {{ $t('settings.modifyOtherUser') }} {{ user.username }}</h2>
|
||||
<h2 v-else-if="actor.id == user.id">
|
||||
{{ $t("settings.modifyCurrentUser") }} {{ user.username }}
|
||||
</h2>
|
||||
<h2 v-else>{{ $t("settings.modifyOtherUser") }} {{ user.username }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="card-content minimal-card">
|
||||
@@ -18,16 +20,21 @@
|
||||
|
||||
<div v-if="actor.permissions.admin" class="card-action">
|
||||
<button
|
||||
v-if="!isNew && actor.permissions.admin"
|
||||
v-if="!isNew"
|
||||
@click.prevent="deletePrompt"
|
||||
type="button"
|
||||
class="button button--flat button--red"
|
||||
:aria-label="$t('buttons.delete')"
|
||||
aria-label="Delete User"
|
||||
:title="$t('buttons.delete')"
|
||||
>
|
||||
{{ $t("buttons.delete") }}
|
||||
</button>
|
||||
<input class="button button--flat" type="submit" :value="$t('buttons.save')" />
|
||||
<input
|
||||
aria-label="Save User"
|
||||
class="button button--flat"
|
||||
type="submit"
|
||||
:value="$t('buttons.save')"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
@@ -107,7 +114,7 @@ export default {
|
||||
async save(event) {
|
||||
event.preventDefault();
|
||||
try {
|
||||
let fields = ["all"]
|
||||
let fields = ["all"];
|
||||
if (!state.user.permissions.admin) {
|
||||
notify.showError(this.$t("settings.userNotAdmin"));
|
||||
return;
|
||||
|
||||
@@ -4,18 +4,18 @@
|
||||
<div class="card-title">
|
||||
<h2>{{ $t("settings.users") }}</h2>
|
||||
<router-link v-if="isAdmin" to="/settings/users/new">
|
||||
<button class="button">
|
||||
<button class="button" aria-label="Add New User">
|
||||
{{ $t("buttons.new") }}
|
||||
</button>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<div class="card-content full">
|
||||
<table>
|
||||
<table aria-label="Users">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ $t("settings.username") }}</th>
|
||||
<th> {{ $t("settings.loginMethod") }} </th>
|
||||
<th>{{ $t("settings.loginMethod") }}</th>
|
||||
<th>{{ $t("settings.admin") }}</th>
|
||||
<th>Scopes</th> <!-- eslint-disable-line @intlify/vue-i18n/no-raw-text -->
|
||||
<th></th>
|
||||
@@ -30,7 +30,7 @@
|
||||
<i v-else class="material-icons">close</i>
|
||||
</td>
|
||||
<td>{{ user.scopes }}</td>
|
||||
<td class="small">
|
||||
<td class="small" aria-label="Edit User">
|
||||
<router-link :to="'/settings/users/' + user.id">
|
||||
<i class="material-icons">mode_edit</i>
|
||||
</router-link>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { test, expect } from '../test-setup'
|
||||
|
||||
test('create and delete testuser', async ({
|
||||
page,
|
||||
checkForErrors,
|
||||
context
|
||||
}) => {
|
||||
await page.goto('/settings')
|
||||
await expect(page).toHaveTitle("Graham's Filebrowser - Settings")
|
||||
await page.locator('button[aria-label="Add New User"]').click()
|
||||
await page.locator('#username').fill('testuser')
|
||||
await page.locator('input[aria-label="Password1"]').fill('testpassword')
|
||||
await page.locator('input[aria-label="Password2"]').fill('testpass')
|
||||
// check that the invalid-field class is added properly
|
||||
await expect(page.locator('input[aria-label="Password2"]')).toHaveClass(
|
||||
'input input--block form-form invalid-form'
|
||||
)
|
||||
await page.locator('input[aria-label="Password2"]').fill('testpassword')
|
||||
await page.locator('input[aria-label="Save User"]').click()
|
||||
|
||||
// click the edit button for testuser
|
||||
const userRow = page.locator('tr.item', { hasText: 'testuser' })
|
||||
const editLink = await userRow
|
||||
.locator('td[aria-label="Edit User"] a')
|
||||
.getAttribute('href')
|
||||
await page.goto(editLink!)
|
||||
checkForErrors()
|
||||
})
|
||||
@@ -12,3 +12,4 @@ test("Create first new file", async ({ page, checkForErrors, context }) => {
|
||||
await expect(page.locator('#listingView .file-items')).toHaveCount(1);
|
||||
checkForErrors();
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user