Add ability to force the queried icons collection on the Advanced form

This commit is contained in:
Bubka 2025-06-05 13:06:03 +02:00
parent 9e3794a956
commit c693c840b2
5 changed files with 62 additions and 31 deletions

View File

@ -11,6 +11,7 @@ use App\Models\TwoFAccount;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Arr;
class IconController extends Controller
{
@ -52,7 +53,11 @@ class IconController extends Controller
{
$validated = $request->validated();
$icon = LogoLib::driver('tfa')->getIcon($validated['service']);
$iconCollection = Arr::has($validated, 'iconCollection') && $validated['iconCollection']
? $validated['iconCollection']
: $request->user()->preferences['iconCollection'];
$icon = LogoLib::driver($iconCollection)->getIcon($validated['service']);
return $icon
? response()->json(['filename' => $icon], 201)

View File

@ -25,7 +25,8 @@ class IconFetchRequest extends FormRequest
public function rules()
{
return [
'service' => 'string',
'service' => 'string',
'iconCollection' => 'nullable|string|in:tfa,selfh,dashboardicons',
];
}

View File

@ -23,8 +23,8 @@ export default {
return apiClient.post('/twofaccounts', { uri: uri }, { ...config })
},
getLogo(service, config = {}) {
return apiClient.post('/icons/default', { service: service }, { ...config })
getLogo(service, iconCollection, config = {}) {
return apiClient.post('/icons/default', { service: service, iconCollection: iconCollection }, { ...config })
},
deleteIcon(icon, config = {}) {

View File

@ -37,6 +37,11 @@
const iconForm = reactive(new Form({
icon: null
}))
const iconCollections = [
{ text: 'selfh.st', value: 'selfh' },
{ text: 'dashboardicons.com', value: 'dashboardicons' },
{ text: '2fa.directory', value: 'tfa' },
]
const otpDisplayProps = ref({
otp_type: '',
account : '',
@ -69,6 +74,7 @@
const showAdvancedForm = ref(false)
const ShowTwofaccountInModal = ref(false)
const fetchingLogo = ref(false)
const iconCollection = ref(user.preferences.iconCollection)
// $refs
const iconInput = ref(null)
@ -379,7 +385,7 @@
if (user.preferences.getOfficialIcons) {
fetchingLogo.value = true
twofaccountService.getLogo(form.service, { returnError: true })
twofaccountService.getLogo(form.service, iconCollection.value, { returnError: true })
.then(response => {
if (response.status === 201) {
// clean possible already uploaded temp icon
@ -486,33 +492,52 @@
<FormField v-model="form.account" fieldName="account" :fieldError="form.errors.get('account')" label="twofaccounts.account" :placeholder="$t('twofaccounts.forms.account.placeholder')" />
<!-- icon upload -->
<label for="filUploadIcon" class="label">{{ $t('twofaccounts.icon') }}</label>
<div class="field is-grouped">
<!-- Try my luck button -->
<div class="control" v-if="user.preferences.getOfficialIcons">
<VueButton @click="fetchLogo" :color="mode == 'dark' ? 'is-dark' : ''" :nativeType="'button'" :is-loading="fetchingLogo" :isDisabled="!form.service" aria-describedby="lgdTryMyLuck">
<span class="icon is-small">
<FontAwesomeIcon :icon="['fas', 'globe']" />
</span>
<span>{{ $t('twofaccounts.forms.i_m_lucky') }}</span>
</VueButton>
</div>
<!-- upload icon button -->
<div class="control is-flex">
<div role="button" tabindex="0" class="file mr-3" :class="mode == 'dark' ? 'is-dark' : 'is-white'" @keyup.enter="iconInputLabel.click()">
<label for="filUploadIcon" class="file-label" ref="iconInputLabel">
<input id="filUploadIcon" tabindex="-1" class="file-input" type="file" accept="image/*" v-on:change="uploadIcon" ref="iconInput">
<span class="file-cta">
<span class="file-icon">
<FontAwesomeIcon :icon="['fas', 'upload']" />
</span>
<span class="file-label">{{ $t('twofaccounts.forms.choose_image') }}</span>
<div class="columns is-mobile mb-0">
<div class="column">
<!-- try my luck -->
<fieldset v-if="user.preferences.getOfficialIcons" :disabled="!form.service">
<div class="field is-grouped">
<div class="control">
<VueButton @click="fetchLogo" :color="mode == 'dark' ? 'is-dark' : ''" :nativeType="'button'" :is-loading="fetchingLogo" aria-describedby="lgdTryMyLuck">
<span class="icon is-small">
<FontAwesomeIcon :icon="['fas', 'globe']" />
</span>
<span>{{ $t('twofaccounts.forms.i_m_lucky') }}</span>
</VueButton>
</div>
<div class="control">
<div class="select">
<select name="icon-collection" v-model="iconCollection">
<option v-for="collection in iconCollections" :key="collection.text" :value="collection.value">
{{ collection.text }}
</option>
</select>
</div>
</div>
</div>
</fieldset>
<div class="field is-grouped">
<!-- upload icon button -->
<div class="control is-flex">
<div role="button" tabindex="0" class="file mr-3" :class="mode == 'dark' ? 'is-dark' : 'is-white'" @keyup.enter="iconInputLabel.click()">
<label for="filUploadIcon" class="file-label" ref="iconInputLabel">
<input id="filUploadIcon" tabindex="-1" class="file-input" type="file" accept="image/*" v-on:change="uploadIcon" ref="iconInput">
<span class="file-cta">
<span class="file-icon">
<FontAwesomeIcon :icon="['fas', 'upload']" />
</span>
<span class="file-label">{{ $t('twofaccounts.forms.choose_image') }}</span>
</span>
</label>
</div>
<span class="tag is-large" :class="mode =='dark' ? 'is-dark' : 'is-white'" v-if="tempIcon">
<img class="icon-preview" :src="$2fauth.config.subdirectory + '/storage/icons/' + tempIcon" :alt="$t('twofaccounts.icon_to_illustrate_the_account')">
<button type="button" class="clear-selection delete is-small" @click.prevent="deleteTempIcon" :aria-label="$t('twofaccounts.remove_icon')"></button>
</span>
</label>
</div>
</div>
<span class="tag is-large" :class="mode =='dark' ? 'is-dark' : 'is-white'" v-if="tempIcon">
<img class="icon-preview" :src="$2fauth.config.subdirectory + '/storage/icons/' + tempIcon" :alt="$t('twofaccounts.icon_to_illustrate_the_account')">
<button type="button" class="clear-selection delete is-small" @click.prevent="deleteTempIcon" :aria-label="$t('twofaccounts.remove_icon')"></button>
</span>
</div>
<div class="column is-narrow" style="width: 200px;">
</div>
</div>
<div class="field">

View File

@ -66,7 +66,7 @@ return [
],
'choose_image' => 'Upload',
'i_m_lucky' => 'Try my luck',
'i_m_lucky_legend' => 'The "Try my luck" button try to get the official icon of the given service. Enter actual service name without ".xyz" extension and try to avoid typo. (beta feature)',
'i_m_lucky_legend' => 'The "Try my luck" button tries to get a standard icon from the selected icon collection. The simpler the service value, the more likely you are to get the correct icon: Do not append any extension (like ".com"), use the exact name of the service, avoid special chars.',
'test' => 'Test',
'group' => [
'label' => 'Group',