Harmonize JSON API error messages

This commit is contained in:
2026-08-25 23:44:26 +02:00
parent 0d4b159ab3
commit f1b90a4d83
18 changed files with 254 additions and 175 deletions
+28 -25
View File
@@ -24,8 +24,8 @@ export default {
this.setProjects();
},
methods: {
l(id) {
return this.lang.get(id);
l(sLangId, asLangParams=[]) {
return this.lang.get(sLangId, asLangParams);
},
addFeedback(sType, sMsg, asContext = {}) {
delete asContext.a;
@@ -60,22 +60,7 @@ export default {
}
}
})
.catch((sMsg) => {this.addFeedback('error', sMsg, {'create':sType});});
},
deleteElem(oElem) {
const asInputs = {
type: oElem.type,
id: oElem.id
};
this.api.post('admin_delete', asInputs)
.then(() => {
delete this.elems[asInputs.type][asInputs.id];
this.addFeedback('success', this.l('admin.delete_success'), asInputs);
})
.catch((sError) => {
this.addFeedback('error', sError, asInputs);
});
.catch((oError) => {this.addFeedback('error', oError.desc_lang_text, {'create':sType});});
},
updateElem(oElem, oEvent) {
if(this.saveTimer) clearTimeout(this.saveTimer);
@@ -90,25 +75,43 @@ export default {
value: sNewVal
};
this.api.post('admin_set', asInputs)
.then(() => {
this.api.request('admin_set', asInputs, 'POST')
.then((oResponse) => {
this.elems[oElem.type][oElem.id][oEvent.target.name] = sNewVal;
this.addFeedback('success', this.l('admin.save_success'), asInputs);
const bSuccess = (oResponse.desc_lang_id == '');
const sType = bSuccess?'success':'warning';
const sText = this.l(bSuccess?'admin.save_success':oResponse.desc_lang_id, oResponse.desc_lang_params);
this.addFeedback(sType, sText, asInputs);
})
.catch((sError) => {
.catch((oError) => {
oEvent.target.value = sOldVal;
this.addFeedback('error', sError, asInputs);
this.addFeedback('error', oError.desc_lang_text, asInputs);
});
}
},
deleteElem(oElem) {
const asInputs = {
type: oElem.type,
id: oElem.id
};
this.api.post('admin_delete', asInputs)
.then(() => {
delete this.elems[asInputs.type][asInputs.id];
this.addFeedback('success', this.l('admin.delete_success'), asInputs);
})
.catch((oError) => {
this.addFeedback('error', oError.desc_lang_text, asInputs);
});
},
queue(oElem, oEvent) {
if(this.saveTimer) clearTimeout(this.saveTimer);
this.saveTimer = setTimeout(() => {this.updateElem(oElem, oEvent);}, 2000);
},
updateProject() {
this.api.request('update_project', {}, 'POST')
.then((oResponse) => {this.addFeedback('success', oResponse.desc, {'update':'project'});})
.catch((sMsg) => {this.addFeedback('error', sMsg, {'update':'project'});});
.then((oResponse) => {this.addFeedback('success', oResponse.desc_lang_text, {'update':'project'});})
.catch((oError) => {this.addFeedback('error', oError.desc_lang_text, {'update':'project'});});
}
}
}
+3 -3
View File
@@ -44,7 +44,7 @@ export default {
this.api.request(this.user.subscribed?'subscribe':'unsubscribe', {}, 'POST')
.then((asResponse) => {
this.user.setInfo(asResponse.data);
this.feedbacks.push({type:asResponse.result, msg:asResponse.desc});
this.feedbacks.push({type:asResponse.result, msg:asResponse.desc_lang_text});
})
.catch((sDesc) => {
this.user.subscribed = !this.user.subscribed;
@@ -64,7 +64,7 @@ export default {
this.api.request(sAction, {'email': this.user.email, 'password': this.password, 'name': this.user.name}, 'POST')
.then((asResponse) => {
this.feedbacks.push({type: asResponse.result, msg: asResponse.desc});
this.feedbacks.push({type: asResponse.result, msg: asResponse.desc_lang_text});
this.user.setInfo(asResponse.data);
this.passwordMode = false;
this.settingPassword = false;
@@ -72,7 +72,7 @@ export default {
this.passwordConfirmation = '';
})
.catch((oError) => {
switch(oError.descKey) {
switch(oError.desc_lang_id) {
case 'account.set_password':
this.passwordMode = true;
this.settingPassword = true;
+2 -2
View File
@@ -72,7 +72,7 @@ export default {
<span ref="postedon" class="lb-caption-line">
<projectRelTime
icon="upload"
titleWrapperName="media.posted_on"
titleWrapperLangId="media.posted_on"
:localTime="options.posted_on_formatted_time_local"
:siteTime="options.posted_on_formatted_time"
:offset="options.posted_on_day_offset"
@@ -81,7 +81,7 @@ export default {
<span ref="takenon" class="lb-caption-line">
<projectRelTime
:icon="options.subtype+'-shot'"
:titleWrapperName="'media.'+options.subtype+'_taken_on'"
:titleWrapperLangId="'media.'+options.subtype+'_taken_on'"
:localTime="options.taken_on_formatted_time_local"
:siteTime="options.taken_on_formatted_time"
:offset="options.taken_on_day_offset"
+3 -3
View File
@@ -11,7 +11,7 @@ export default {
offset: String,
classes: String,
icon: String,
titleWrapperName: String
titleWrapperLangId: String
},
inject: ['lang'],
computed: {
@@ -21,8 +21,8 @@ export default {
this.lang.get('time.user', this.siteTime.slice(-5))
+ ((this.offset != '0')?' ('+this.lang.get('unit.day_short')+this.offset+')':'');
return (this.titleWrapperName)?
this.lang.get(this.titleWrapperName, bDifferentTimeZone?sTime:this.siteTime)
return (this.titleWrapperLangId)?
this.lang.get(this.titleWrapperLangId, bDifferentTimeZone?sTime:this.siteTime)
:
(bDifferentTimeZone?sTime:null);
}
+21 -13
View File
@@ -22,7 +22,7 @@ export default {
},
mounted() {
if(!this.project.editable) {
this.logs = [this.lang.get('upload.mode_archived', [this.project.name])];
this.addLog('upload.mode_archived', [this.project.name]);
return;
}
@@ -35,6 +35,9 @@ export default {
}
},
methods: {
addLog(sLangId = 'upload.error', asLangParams = []) {
this.logs.push({lang_id: sLangId, lang_params: asLangParams});
},
initUploader() {
const endpoint = `${this.consts.process_page}?a=upload`;
@@ -66,14 +69,14 @@ export default {
const uploadedFiles = response?.body?.files || [];
uploadedFiles.forEach((uploadedFile) => {
const hasError = Object.prototype.hasOwnProperty.call(uploadedFile, 'error');
this.logs.push(hasError ? uploadedFile.error : this.lang.get('upload.success', [uploadedFile.original_name || uploadedFile.name]));
if(hasError) this.addLog(uploadedFile.desc_lang_id, uploadedFile.desc_lang_params);
else this.addLog('upload.success', [uploadedFile.original_name || uploadedFile.name]);
if(!hasError) this.files.push({...uploadedFile, content: ''});
});
});
this.uppy.on('upload-error', (file, error, response) => {
const message = response?.body?.error || error?.message || this.lang.get('upload.error');
this.logs.push(message);
this.addLog(response?.body?.desc_lang_id || 'upload.error', response?.body?.desc_lang_params || []);
});
this.uppy.on('complete', () => {
@@ -90,29 +93,34 @@ export default {
id: oFile.id,
content: oFile.content
})
.then((asData) => {this.logs.push(this.lang.get('media.comment_update', asData.filename));})
.catch((sMsgId) => {this.logs.push(this.lang.get(sMsgId));});
.then((asData) => {this.addLog('media.comment_update', [asData.filename]);})
.catch((oError) => {this.addLog(oError.desc_lang_id, oError.desc_lang_params);});
},
addPosition() {
if(navigator.geolocation) {
this.logs.push('Determining position...');
this.addLog('upload.position.determining');
navigator.geolocation.getCurrentPosition(
(position) => {
this.logs.push('Sending position...');
this.addLog('upload.position.sending');
this.api.post('add_position', {
'latitude': position.coords.latitude,
'longitude': position.coords.longitude,
'timestamp': Math.round(position.timestamp / 1000)
})
.then(() => {this.logs.push(this.lang.get('upload.success', [this.lang.get('upload.position.new')]));})
.catch((sMsgId) => {this.logs.push(this.lang.get(sMsgId));});
.then(() => {this.addLog('upload.position.success');})
.catch((oError) => {this.addLog(oError.desc_lang_id, oError.desc_lang_params);});
},
(error) => {
this.logs.push(error.message);
const asErrorLangIds = {
1: 'upload.position.permission_denied',
2: 'upload.position.unavailable',
3: 'upload.position.timeout'
};
this.addLog(asErrorLangIds[error.code] || 'upload.position.error');
}
);
}
else this.logs.push('This browser does not support geolocation');
else this.addLog('upload.position.unsupported');
}
}
}
@@ -144,7 +152,7 @@ export default {
<AppButton :icon="'marker'" :text="lang.get('upload.position.new')" @click="addPosition()" />
</div>
<div class="section logs" v-if="logs.length > 0">
<p class="log" v-for="log in logs">{{ log }}.</p>
<p class="log" v-for="(log, index) in logs" :key="index">{{ lang.get(log.lang_id, log.lang_params) }}</p>
</div>
</div>
</template>
+9 -8
View File
@@ -10,8 +10,8 @@ export default class Api {
}
async get(sAction, asParams = {}) {
const response = await this.request(sAction, asParams, 'GET');
return response.data;
const oResponse = await this.request(sAction, asParams, 'GET');
return oResponse.data;
}
async getAsset(sAssetPath) {
@@ -25,8 +25,8 @@ export default class Api {
}
async post(sAction, asParams = {}) {
const response = await this.request(sAction, asParams, 'POST');
return response.data;
const oResponse = await this.request(sAction, asParams, 'POST');
return oResponse.data;
}
async request(sAction, asParams = {}, method = 'GET') {
@@ -59,12 +59,13 @@ export default class Api {
}
const oResponse = await oRequest.json();
oResponse.descKey = this.lang.getLangKey(oResponse.desc);
oResponse.desc = this.lang.parse(oResponse.desc);
oResponse.desc_lang_text = this.lang.get(oResponse.desc_lang_id, oResponse.desc_lang_params);
if(oResponse.result == this.errorCode) {
const oError = new Error(oResponse.desc);
oError.descKey = oResponse.descKey;
const oError = new Error(oResponse.desc_lang_text);
oError.desc_lang_id = oResponse.desc_lang_id;
oError.desc_lang_params = oResponse.desc_lang_params;
oError.desc_lang_text = oResponse.desc_lang_text;
throw oError;
}
+6 -15
View File
@@ -5,29 +5,20 @@ export default class Lang {
this.prefix = prefix;
}
get(key = '', params = []) {
if(key === '') return '';
get(sLangId = '', params = []) {
if(sLangId === '') return '';
const normalizedParams = Array.isArray(params) ? params : [params];
if(Object.prototype.hasOwnProperty.call(this.translations, key)) {
let text = this.translations[key];
if(Object.prototype.hasOwnProperty.call(this.translations, sLangId)) {
let text = this.translations[sLangId];
normalizedParams.forEach((param, index) => {
text = text.replace('$' + index, param);
});
return text;
}
console.warn('Missing translation:', key);
return key;
}
parse(message = '') {
let sLangKey = this.getLangKey(message);
return (sLangKey != '')?this.get(sLangKey):message;
}
getLangKey(message = '') {
return (this.prefix && typeof message === 'string' && message.startsWith(this.prefix))?message.slice(this.prefix.length):'';
console.warn('Missing translation:', sLangId);
return sLangId;
}
}