refactor: API class

cap
Varun Patil 2022-12-02 23:10:40 -08:00
parent e60d97ae5e
commit 13f73b3594
18 changed files with 132 additions and 94 deletions

View File

@ -44,21 +44,21 @@ return [
['name' => 'Days#day', 'url' => '/api/days/{id}', 'verb' => 'GET'],
['name' => 'Days#dayPost', 'url' => '/api/days', 'verb' => 'POST'],
['name' => 'Albums#albums', 'url' => '/api/albums', 'verb' => 'GET'],
['name' => 'Tags#tags', 'url' => '/api/tags', 'verb' => 'GET'],
['name' => 'Tags#previews', 'url' => '/api/tag-previews', 'verb' => 'GET'],
['name' => 'Albums#albums', 'url' => '/api/albums', 'verb' => 'GET'],
['name' => 'Faces#faces', 'url' => '/api/faces', 'verb' => 'GET'],
['name' => 'Faces#preview', 'url' => '/api/faces/preview/{id}', 'verb' => 'GET'],
['name' => 'Archive#archive', 'url' => '/api/archive/{id}', 'verb' => 'PATCH'],
['name' => 'Image#preview', 'url' => '/api/image/preview/{id}', 'verb' => 'GET'],
['name' => 'Image#info', 'url' => '/api/image/info/{id}', 'verb' => 'GET'],
['name' => 'Image#setExif', 'url' => '/api/image/set-exif/{id}', 'verb' => 'PATCH'],
['name' => 'Image#jpeg', 'url' => '/api/image/jpeg/{id}', 'verb' => 'GET'],
['name' => 'Archive#archive', 'url' => '/api/archive/{id}', 'verb' => 'PATCH'],
['name' => 'Video#transcode', 'url' => '/api/video/transcode/{client}/{fileid}/{profile}', 'verb' => 'GET'],
['name' => 'Video#livephoto', 'url' => '/api/video/livephoto/{fileid}', 'verb' => 'GET'],

View File

@ -54,7 +54,6 @@ import NcAppContent from "@nextcloud/vue/dist/Components/NcAppContent";
import NcButton from "@nextcloud/vue/dist/Components/NcButton";
import { getFilePickerBuilder } from "@nextcloud/dialogs";
import { generateUrl } from "@nextcloud/router";
import { getCurrentUser } from "@nextcloud/auth";
import axios from "@nextcloud/axios";
@ -63,6 +62,7 @@ import UserConfig from "../mixins/UserConfig";
import banner from "../assets/banner.svg";
import { IDay } from "../types";
import { API } from "../services/API";
@Component({
components: {
@ -99,7 +99,7 @@ export default class FirstStart extends Mixins(GlobalMixin, UserConfig) {
this.info = "";
const query = new URLSearchParams();
query.set("timelinePath", path);
let url = generateUrl("/apps/memories/api/days?" + query.toString());
let url = API.Q(API.DAYS(), query);
const res = await axios.get<IDay[]>(url);
// Check response

View File

@ -14,13 +14,14 @@ import GlobalMixin from "../mixins/GlobalMixin";
import { basename, dirname, extname, join } from "path";
import { emit } from "@nextcloud/event-bus";
import { showError, showSuccess } from "@nextcloud/dialogs";
import { generateUrl } from "@nextcloud/router";
import axios from "@nextcloud/axios";
import { FilerobotImageEditorConfig } from "react-filerobot-image-editor";
import translations from "./ImageEditorTranslations";
import { API } from "../services/API";
let TABS, TOOLS: any;
type FilerobotImageEditor = import("filerobot-image-editor").default;
let FilerobotImageEditor: typeof import("filerobot-image-editor").default;
@ -51,9 +52,7 @@ export default class ImageEditor extends Mixins(GlobalMixin) {
if (["image/png", "image/jpeg", "image/webp"].includes(this.mime)) {
src = this.src;
} else {
src = generateUrl("/apps/memories/api/image/jpeg/{fileid}", {
fileid: this.fileid,
});
src = API.IMAGE_JPEG(this.fileid);
}
return {
@ -157,9 +156,7 @@ export default class ImageEditor extends Mixins(GlobalMixin) {
// Get latest exif data
try {
const res = await axios.get(
generateUrl("/apps/memories/api/image/info/{id}?basic=1&current=1", {
id: this.fileid,
})
API.Q(API.IMAGE_INFO(this.fileid), "basic=1&current=1")
);
this.exif = res.data?.current;
@ -243,14 +240,9 @@ export default class ImageEditor extends Mixins(GlobalMixin) {
delete exif.MajorBrand;
// Update exif data
await axios.patch(
generateUrl("/apps/memories/api/image/set-exif/{id}", {
id: fileid,
}),
{
raw: exif,
}
);
await axios.patch(API.IMAGE_SETEXIF(fileid), {
raw: exif,
});
showSuccess(this.t("memories", "Image saved successfully"));
if (fileid !== this.fileid) {

View File

@ -51,7 +51,6 @@ import GlobalMixin from "../mixins/GlobalMixin";
import NcActions from "@nextcloud/vue/dist/Components/NcActions";
import NcActionButton from "@nextcloud/vue/dist/Components/NcActionButton";
import { generateUrl } from "@nextcloud/router";
import axios from "@nextcloud/axios";
import { subscribe, unsubscribe } from "@nextcloud/event-bus";
import { getCanonicalLocale } from "@nextcloud/l10n";
@ -66,6 +65,7 @@ import CalendarIcon from "vue-material-design-icons/Calendar.vue";
import CameraIrisIcon from "vue-material-design-icons/CameraIris.vue";
import ImageIcon from "vue-material-design-icons/Image.vue";
import LocationIcon from "vue-material-design-icons/MapMarker.vue";
import { API } from "../services/API";
@Component({
components: {
@ -88,9 +88,7 @@ export default class Metadata extends Mixins(GlobalMixin) {
this.nominatim = null;
let state = this.state;
let url = generateUrl("/apps/memories/api/image/info/{id}", {
id: fileInfo.id,
});
let url = API.IMAGE_INFO(fileInfo.id);
url = utils.addQueryTokensToUrl(url);
const res = await axios.get<any>(url);
if (state !== this.state) return;

View File

@ -1,11 +1,11 @@
import PhotoSwipe from "photoswipe";
import { generateUrl } from "@nextcloud/router";
import { loadState } from "@nextcloud/initial-state";
import axios from "@nextcloud/axios";
import { showError } from "@nextcloud/dialogs";
import { translate as t } from "@nextcloud/l10n";
import { getCurrentUser } from "@nextcloud/auth";
import { addQueryTokensToUrl } from "../services/Utils";
import { API } from "../services/API";
const config_noTranscode = loadState(
"memories",
@ -118,10 +118,7 @@ class VideoContentSetup {
getHLSsrc(content: any) {
// Get base URL
const fileid = content.data.photo.fileid;
let url = generateUrl(
`/apps/memories/api/video/transcode/${videoClientId}/${fileid}/index.m3u8`
);
let url = API.VIDEO_TRANSCODE(fileid);
url = addQueryTokensToUrl(url);
return {
@ -232,9 +229,7 @@ class VideoContentSetup {
});
// Get correct orientation
let url = generateUrl("/apps/memories/api/image/info/{id}", {
id: content.data.photo.fileid,
});
let url = API.IMAGE_INFO(content.data.photo.fileid);
url = addQueryTokensToUrl(url);
axios.get<any>(url).then((response) => {

View File

@ -147,7 +147,6 @@ import UserConfig from "../mixins/UserConfig";
import axios from "@nextcloud/axios";
import { showError } from "@nextcloud/dialogs";
import { subscribe, unsubscribe } from "@nextcloud/event-bus";
import { generateUrl } from "@nextcloud/router";
import NcEmptyContent from "@nextcloud/vue/dist/Components/NcEmptyContent";
import { getLayout } from "../services/Layout";
@ -168,6 +167,7 @@ import PeopleIcon from "vue-material-design-icons/AccountMultiple.vue";
import CheckCircle from "vue-material-design-icons/CheckCircle.vue";
import ImageMultipleIcon from "vue-material-design-icons/ImageMultiple.vue";
import ArchiveIcon from "vue-material-design-icons/PackageDown.vue";
import { API } from "../services/API";
const SCROLL_LOAD_DELAY = 100; // Delay in loading data when scrolling
const DESKTOP_ROW_HEIGHT = 200; // Height of row on desktop
@ -549,7 +549,7 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
}
/** Get query string for API calls */
appendQuery(url: string) {
getQuery() {
const query = new URLSearchParams();
// Favorites
@ -610,11 +610,7 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
// Create query string and append to URL
utils.addQueryTokens(query);
const queryStr = query.toString();
if (queryStr) {
url += "?" + queryStr;
}
return url;
return query;
}
/** Get view name for dynamic top matter */
@ -671,8 +667,7 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
/** Fetch timeline main call */
async fetchDays(noCache = false) {
let params: any = {};
let url = generateUrl(this.appendQuery("/apps/memories/api/days"), params);
const url = API.Q(API.DAYS(), this.getQuery());
const cacheUrl = this.$route.name + url;
// Try cache first
@ -838,9 +833,7 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) {
/** API url for Day call */
private getDayUrl(dayId: number | string) {
let baseUrl = "/apps/memories/api/days/{dayId}";
const params: any = { dayId };
return generateUrl(this.appendQuery(baseUrl), params);
return API.Q(API.DAY(dayId), this.getQuery());
}
/** Fetch image data for one dayId */

View File

@ -37,7 +37,6 @@
<script lang="ts">
import { Component, Prop, Watch, Mixins, Emit } from "vue-property-decorator";
import { IAlbum, IPhoto, ITag } from "../../types";
import { generateUrl } from "@nextcloud/router";
import { getPreviewUrl } from "../../services/FileUtils";
import { getCurrentUser } from "@nextcloud/auth";
@ -47,6 +46,7 @@ import * as utils from "../../services/Utils";
import GlobalMixin from "../../mixins/GlobalMixin";
import { constants } from "../../services/Utils";
import { API } from "../../services/API";
@Component({
components: {
@ -84,9 +84,7 @@ export default class Tag extends Mixins(GlobalMixin) {
getPreviewUrl(photo: IPhoto) {
if (this.isFace) {
return generateUrl(
"/apps/memories/api/faces/preview/" + this.data.fileid
);
return API.FACE_PREVIEWS(this.data.fileid);
}
return getPreviewUrl(photo, true, 256);
@ -127,9 +125,7 @@ export default class Tag extends Mixins(GlobalMixin) {
if (!this.data.previews) {
try {
const todayDayId = utils.dateToDayId(new Date());
const url = generateUrl(
`/apps/memories/api/tag-previews?tag=${this.data.name}`
);
const url = API.TAG_PREVIEWS(this.data.name);
const cacheUrl = `${url}&today=${todayDayId}`;
const cache = await utils.getCachedData(cacheUrl);
if (cache) {

View File

@ -69,10 +69,10 @@ import NcButton from "@nextcloud/vue/dist/Components/NcButton";
import NcLoadingIcon from "@nextcloud/vue/dist/Components/NcLoadingIcon";
const NcListItem = () => import("@nextcloud/vue/dist/Components/NcListItem");
import { generateUrl } from "@nextcloud/router";
import { getPreviewUrl } from "../../services/FileUtils";
import { IAlbum, IPhoto } from "../../types";
import axios from "@nextcloud/axios";
import { API } from "../../services/API";
@Component({
components: {
@ -118,9 +118,7 @@ export default class AlbumPicker extends Mixins(GlobalMixin) {
async loadAlbums() {
try {
const res = await axios.get<IAlbum[]>(
generateUrl("/apps/memories/api/albums?t=3")
);
const res = await axios.get<IAlbum[]>(API.ALBUM_LIST());
this.albums = res.data;
} catch (e) {
console.error(e);

View File

@ -138,15 +138,12 @@ import NcButton from "@nextcloud/vue/dist/Components/NcButton";
const NcTextField = () => import("@nextcloud/vue/dist/Components/NcTextField");
import { showError } from "@nextcloud/dialogs";
import { generateUrl } from "@nextcloud/router";
import { emit } from "@nextcloud/event-bus";
import Modal from "./Modal.vue";
import axios from "@nextcloud/axios";
import * as utils from "../../services/Utils";
import * as dav from "../../services/DavRequests";
const INFO_API_URL = "/apps/memories/api/image/info/{id}";
const EDIT_API_URL = "/apps/memories/api/image/set-exif/{id}";
import { API } from "../../services/API";
@Component({
components: {
@ -189,7 +186,7 @@ export default class EditDate extends Mixins(GlobalMixin) {
const calls = photos.map((p) => async () => {
try {
const res = await axios.get<any>(
generateUrl(INFO_API_URL, { id: p.fileid }) + "?basic=1"
API.Q(API.IMAGE_INFO(p.fileid), "basic=1")
);
if (typeof res.data.datetaken !== "number") {
console.error("Invalid date for", p.fileid);
@ -271,7 +268,7 @@ export default class EditDate extends Mixins(GlobalMixin) {
try {
this.processing = true;
const fileid = this.photos[0].fileid;
await axios.patch<any>(generateUrl(EDIT_API_URL, { id: fileid }), {
await axios.patch<any>(API.IMAGE_SETEXIF(fileid), {
raw: {
DateTimeOriginal: this.getExifFormat(this.getDate()),
},
@ -337,7 +334,7 @@ export default class EditDate extends Mixins(GlobalMixin) {
const offset = date.getTime() - pDate.getTime();
const scale = diff > 0 ? diffNew / diff : 0;
const pDateNew = new Date(dateNew.getTime() - offset * scale);
await axios.patch<any>(generateUrl(EDIT_API_URL, { id: p.fileid }), {
await axios.patch<any>(API.IMAGE_SETEXIF(p.fileid), {
raw: {
DateTimeOriginal: this.getExifFormat(pDateNew),
},

View File

@ -1,8 +1,8 @@
import { Component, Vue } from "vue-property-decorator";
import { emit, subscribe, unsubscribe } from "@nextcloud/event-bus";
import { generateUrl } from "@nextcloud/router";
import { loadState } from "@nextcloud/initial-state";
import axios from "@nextcloud/axios";
import { API } from "../services/API";
const eventName = "memories:user-config-changed";
const localSettings = ["squareThumbs", "showFaceRect"];
@ -57,7 +57,7 @@ export default class UserConfig extends Vue {
}
} else {
// Long time save setting
await axios.put(generateUrl("apps/memories/api/config/" + setting), {
await axios.put(API.CONFIG(setting), {
value: value.toString(),
});
}

View File

@ -0,0 +1,84 @@
import { generateUrl } from "@nextcloud/router";
const BASE = "/apps/memories/api";
export class API {
static Q(url: string, query: string | URLSearchParams | undefined | null) {
if (!query) return url;
let queryStr = typeof query === "string" ? query : query.toString();
if (!queryStr) return url;
if (url.indexOf("?") > -1) {
return `${url}&${queryStr}`;
} else {
return `${url}?${queryStr}`;
}
}
static DAYS() {
return generateUrl(`${BASE}/days`);
}
static DAY(id: number | string) {
return generateUrl(`${BASE}/days/{id}`, { id });
}
static ALBUM_LIST(t: "1" | "2" | "3" = "3") {
return generateUrl(`${BASE}/albums?t=${t}`);
}
static TAG_LIST() {
return generateUrl(`${BASE}/tags`);
}
static TAG_PREVIEWS(tag: string) {
return generateUrl(`${BASE}/tag-previews?tag=${tag}`);
}
static FACE_LIST() {
return generateUrl(`${BASE}/faces`);
}
static FACE_PREVIEWS(face: string | number) {
return generateUrl(`${BASE}/faces/preview/{face}`, { face });
}
static ARCHIVE(fileid: number) {
return generateUrl(`${BASE}/archive/{fileid}`, { fileid });
}
static IMAGE_PREVIEW(fileid: number) {
return generateUrl(`${BASE}/image/preview/{fileid}`, { fileid });
}
static IMAGE_INFO(id: number) {
return generateUrl(`${BASE}/image/info/{id}`, { id });
}
static IMAGE_SETEXIF(id: number) {
return generateUrl(`${BASE}/image/set-exif/{id}`, { id });
}
static IMAGE_JPEG(id: number) {
return generateUrl(`${BASE}/image/jpeg/{id}`, { id });
}
static VIDEO_TRANSCODE(fileid: number) {
return generateUrl(
`${BASE}/video/transcode/{videoClientId}/{fileid}/index.m3u8`,
{
videoClientId,
fileid,
}
);
}
static VIDEO_LIVEPHOTO(fileid: number) {
return generateUrl(`${BASE}/video/livephoto/{fileid}`, { fileid });
}
static CONFIG(setting: string) {
return generateUrl(`${BASE}/config/{setting}`, { setting });
}
}

View File

@ -19,9 +19,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
import { generateUrl } from "@nextcloud/router";
import camelcase from "camelcase";
import { IFileInfo, IPhoto } from "../types";
import { API } from "./API";
import { isNumber } from "./NumberUtils";
import { addQueryTokens } from "./Utils";
@ -143,9 +143,6 @@ const getPreviewUrl = function (
) {
const [x, y] = typeof size === "number" ? [size, size] : size;
// Get base URL
const url = generateUrl(`/apps/memories/api/image/preview/${photo.fileid}`);
// Build query
const query = new URLSearchParams();
query.set("c", photo.etag);
@ -156,7 +153,7 @@ const getPreviewUrl = function (
// Public preview
addQueryTokens(query);
return url + "?" + query.toString();
return API.Q(API.IMAGE_PREVIEW(photo.fileid), query);
};
export {

View File

@ -1,9 +1,9 @@
import { getCanonicalLocale } from "@nextcloud/l10n";
import { getCurrentUser } from "@nextcloud/auth";
import { generateUrl } from "@nextcloud/router";
import { loadState } from "@nextcloud/initial-state";
import { IPhoto } from "../types";
import moment from "moment";
import { API } from "./API";
// Memoize the result of short date conversions
// These operations are surprisingly expensive
@ -269,9 +269,6 @@ export function addQueryTokensToUrl(url: string) {
* Get URL to live photo video part
*/
export function getLivePhotoVideoUrl(p: IPhoto, transcode: boolean) {
// Get base url
const url = generateUrl(`/apps/memories/api/video/livephoto/${p.fileid}`);
// Build query string
const query = new URLSearchParams();
query.set("etag", p.etag);
@ -283,7 +280,7 @@ export function getLivePhotoVideoUrl(p: IPhoto, transcode: boolean) {
}
addQueryTokens(query);
return url + "?" + query.toString();
return API.Q(API.VIDEO_LIVEPHOTO(p.fileid), query);
}
/**

View File

@ -1,12 +1,12 @@
import * as base from "./base";
import { getCurrentUser } from "@nextcloud/auth";
import { generateUrl } from "@nextcloud/router";
import { showError } from "@nextcloud/dialogs";
import { translate as t, translatePlural as n } from "@nextcloud/l10n";
import { IAlbum, IDay, IFileInfo, IPhoto, ITag } from "../../types";
import { constants } from "../Utils";
import axios from "@nextcloud/axios";
import client from "../DavClient";
import { API } from "../API";
/**
* Get DAV path for album
@ -28,9 +28,7 @@ export function getAlbumPath(user: string, name: string) {
export async function getAlbumsData(type: "1" | "2" | "3"): Promise<IDay[]> {
let data: IAlbum[] = [];
try {
const res = await axios.get<typeof data>(
generateUrl(`/apps/memories/api/albums?t=${type}`)
);
const res = await axios.get<typeof data>(API.ALBUM_LIST(type));
data = res.data;
} catch (e) {
throw e;

View File

@ -1,8 +1,8 @@
import * as base from "./base";
import { generateUrl } from "@nextcloud/router";
import { showError } from "@nextcloud/dialogs";
import { translate as t, translatePlural as n } from "@nextcloud/l10n";
import axios from "@nextcloud/axios";
import { API } from "../API";
/**
* Archive or unarchive a single file
@ -11,10 +11,7 @@ import axios from "@nextcloud/axios";
* @param archive Archive or unarchive
*/
export async function archiveFile(fileid: number, archive: boolean) {
return await axios.patch(
generateUrl("/apps/memories/api/archive/{fileid}", { fileid }),
{ archive }
);
return await axios.patch(API.ARCHIVE(fileid), { archive });
}
/**

View File

@ -1,8 +1,8 @@
import axios from "@nextcloud/axios";
import { showError } from "@nextcloud/dialogs";
import { translate as t } from "@nextcloud/l10n";
import { generateUrl } from "@nextcloud/router";
import { IDay, IPhoto } from "../../types";
import { API } from "../API";
import client from "../DavClient";
import { constants } from "../Utils";
import * as base from "./base";
@ -19,9 +19,7 @@ export async function getPeopleData(): Promise<IDay[]> {
previews: IPhoto[];
}[] = [];
try {
const res = await axios.get<typeof data>(
generateUrl("/apps/memories/api/faces")
);
const res = await axios.get<typeof data>(API.FACE_LIST());
data = res.data;
} catch (e) {
throw e;

View File

@ -1,6 +1,6 @@
import { generateUrl } from "@nextcloud/router";
import { IDay, IPhoto } from "../../types";
import axios from "@nextcloud/axios";
import { API } from "../API";
/**
* Get original onThisDay response.
@ -23,7 +23,7 @@ export async function getOnThisDayRaw() {
}
return (
await axios.post<IPhoto[]>(generateUrl("/apps/memories/api/days"), {
await axios.post<IPhoto[]>(API.DAYS(), {
body_ids: dayIds.join(","),
})
).data;

View File

@ -1,7 +1,7 @@
import { generateUrl } from "@nextcloud/router";
import { IDay, IPhoto, ITag } from "../../types";
import { constants, hashCode } from "../Utils";
import axios from "@nextcloud/axios";
import { API } from "../API";
/**
* Get list of tags and convert to Days response
@ -15,9 +15,7 @@ export async function getTagsData(): Promise<IDay[]> {
previews: IPhoto[];
}[] = [];
try {
const res = await axios.get<typeof data>(
generateUrl("/apps/memories/api/tags")
);
const res = await axios.get<typeof data>(API.TAG_LIST());
data = res.data;
} catch (e) {
throw e;