Browse Source

show the image rate limits

kb/add-usage-guide
Trent Larson 8 months ago
parent
commit
252952e017
  1. 2
      CHANGELOG.md
  2. 8
      project.task.yaml
  3. 8
      src/libs/endorserServer.ts
  4. 71
      src/views/AccountViewView.vue

2
CHANGELOG.md

@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [Unreleased]
### Added
- Photo on gift records
### Fixed ### Fixed
- Environment variable for BVC meetings project - Environment variable for BVC meetings project
### Changed in DB or environment ### Changed in DB or environment

8
project.task.yaml

@ -2,6 +2,7 @@
tasks : tasks :
- alert & stop if give amount < 0 - alert & stop if give amount < 0
- onboarding video
- .1 on feed, don't show "to someone anonymous" if it's to a project - .1 on feed, don't show "to someone anonymous" if it's to a project
- .1 on ideas, put an "x" to close it - .1 on ideas, put an "x" to close it
@ -14,12 +15,11 @@ tasks :
- .2 list the "show more" contacts alphabetically - .2 list the "show more" contacts alphabetically
- 32 image on give : - 32 image on give :
- ping endpoint
- limits endpoint
- upload a photo from elsewhere - upload a photo from elsewhere
- go-live - create cert for new image domain, set up haproxy redirect - go-live - create cert for new image domain, set up haproxy redirect, test-image-api.timesafari.app
- make Time Safari a share_target for images
- 08 image on profile - 08 add image on profile
- ask to detect location & record it in settings - ask to detect location & record it in settings
- if personal location is set, show potential local affiliations - if personal location is set, show potential local affiliations

8
src/libs/endorserServer.ts

@ -187,7 +187,7 @@ export interface PlanData {
rowid?: string; rowid?: string;
} }
export interface RateLimits { export interface EndorserRateLimits {
doneClaimsThisWeek: string; doneClaimsThisWeek: string;
doneRegistrationsThisMonth: string; doneRegistrationsThisMonth: string;
maxClaimsPerWeek: string; maxClaimsPerWeek: string;
@ -196,6 +196,12 @@ export interface RateLimits {
nextWeekBeginDateTime: string; nextWeekBeginDateTime: string;
} }
export interface ImageRateLimits {
doneImagesThisWeek: string;
maxImagesPerWeek: string;
nextWeekBeginDateTime: string;
}
export interface VerifiableCredential { export interface VerifiableCredential {
"@context": string; "@context": string;
"@type": string; "@type": string;

71
src/views/AccountViewView.vue

@ -96,7 +96,7 @@
<!-- Registration notice --> <!-- Registration notice -->
<!-- We won't show any loading indicator because it usually doesn't change anything. We'll just pop the message in only if we discover that they need it. --> <!-- We won't show any loading indicator because it usually doesn't change anything. We'll just pop the message in only if we discover that they need it. -->
<div <div
v-if="!loadingLimits && !limits?.nextWeekBeginDateTime" v-if="!loadingLimits && !endorserLimits?.nextWeekBeginDateTime"
class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mb-4" class="bg-amber-200 text-amber-900 border-amber-500 border-dashed border text-center rounded-md overflow-hidden px-4 py-3 mb-4"
> >
<p class="mb-4"> <p class="mb-4">
@ -157,28 +157,39 @@
<div> <div>
{{ limitsMessage }} {{ limitsMessage }}
</div> </div>
<div v-if="!!limits?.nextWeekBeginDateTime"> <div v-if="!!endorserLimits?.nextWeekBeginDateTime">
<p class="mb-3 text-sm"> <p class="text-sm">
You have done <b>{{ limits.doneClaimsThisWeek }}</b> claims out of You have done
<b>{{ limits.maxClaimsPerWeek }}</b> for this week. Your claims <b>{{ endorserLimits.doneClaimsThisWeek }} claims</b> out of
counter resets at <b>{{ endorserLimits.maxClaimsPerWeek }}</b> for this week. Your
claims counter resets at
<b class="whitespace-nowrap">{{ <b class="whitespace-nowrap">{{
readableTime(limits.nextWeekBeginDateTime) readableDate(endorserLimits.nextWeekBeginDateTime)
}}</b> }}</b>
</p> </p>
<p class="text-sm"> <p class="mt-3 text-sm">
You have done You have done
<b>{{ limits.doneRegistrationsThisMonth }}</b> registrations out of <b>{{ endorserLimits.doneRegistrationsThisMonth }} registrations</b>
<b>{{ limits.maxRegistrationsPerMonth }}</b> for this month. out of <b>{{ endorserLimits.maxRegistrationsPerMonth }}</b> for this
month.
<i <i
>(You can register nobody on your first day, and after that only one >(You can register nobody on your first day, and after that only one
a day in your first month.)</i a day in your first month.)</i
> >
Your registration counter resets at Your registration counter resets at
<b class="whitespace-nowrap"> <b class="whitespace-nowrap">
{{ readableTime(limits.nextMonthBeginDateTime) }} {{ readableDate(endorserLimits.nextMonthBeginDateTime) }}
</b> </b>
</p> </p>
<p class="mt-3 text-sm" v-if="!!imageLimits">
You have uploaded
<b>{{ imageLimits?.doneImagesThisWeek }} images</b> out of
<b>{{ imageLimits?.maxImagesPerWeek }}</b> for this week. Your image
counter resets at
<b class="whitespace-nowrap">{{
readableDate(imageLimits?.nextWeekBeginDateTime)
}}</b>
</p>
</div> </div>
<button <button
class="block float-right w-fit text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mt-2" class="block float-right w-fit text-center text-md uppercase bg-slate-500 text-white px-1.5 py-2 rounded-md mt-2"
@ -509,6 +520,7 @@ import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue"; import TopMessage from "@/components/TopMessage.vue";
import { import {
AppString, AppString,
DEFAULT_IMAGE_API_SERVER,
DEFAULT_PUSH_SERVER, DEFAULT_PUSH_SERVER,
NotificationIface, NotificationIface,
} from "@/constants/app"; } from "@/constants/app";
@ -516,7 +528,11 @@ import { db, accountsDB } from "@/db/index";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
import { accessToken } from "@/libs/crypto"; import { accessToken } from "@/libs/crypto";
import { IIdentifier } from "@veramo/core"; import { IIdentifier } from "@veramo/core";
import { ErrorResponse, RateLimits } from "@/libs/endorserServer"; import {
ErrorResponse,
EndorserRateLimits,
ImageRateLimits,
} from "@/libs/endorserServer";
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const Buffer = require("buffer/").Buffer; const Buffer = require("buffer/").Buffer;
@ -542,7 +558,9 @@ export default class AccountViewView extends Vue {
apiServerInput = ""; apiServerInput = "";
derivationPath = ""; derivationPath = "";
downloadUrl = ""; // because DuckDuckGo doesn't download on automated call to "click" on the anchor downloadUrl = ""; // because DuckDuckGo doesn't download on automated call to "click" on the anchor
endorserLimits: EndorserRateLimits | null = null;
givenName = ""; givenName = "";
imageLimits: ImageRateLimits | null = null;
isRegistered = false; isRegistered = false;
isSubscribed = false; isSubscribed = false;
notificationMaybeChanged = false; notificationMaybeChanged = false;
@ -550,7 +568,6 @@ export default class AccountViewView extends Vue {
publicBase64 = ""; publicBase64 = "";
webPushServer = ""; webPushServer = "";
webPushServerInput = ""; webPushServerInput = "";
limits: RateLimits | null = null;
limitsMessage = ""; limitsMessage = "";
loadingLimits = false; loadingLimits = false;
showContactGives = false; showContactGives = false;
@ -697,7 +714,7 @@ export default class AccountViewView extends Vue {
this.updateShowShortcutBvc(this.showShortcutBvc); this.updateShowShortcutBvc(this.showShortcutBvc);
} }
readableTime(timeStr: string) { readableDate(timeStr: string) {
return timeStr.substring(0, timeStr.indexOf("T")); return timeStr.substring(0, timeStr.indexOf("T"));
} }
@ -1038,11 +1055,11 @@ export default class AccountViewView extends Vue {
this.limitsMessage = ""; this.limitsMessage = "";
try { try {
const resp = await this.fetchRateLimits(identity); const resp = await this.fetchEndorserRateLimits(identity);
if (resp.status === 200) { if (resp.status === 200) {
this.limits = resp.data; this.endorserLimits = resp.data;
if (!this.isRegistered) { if (!this.isRegistered) {
// the user is not known to be registered, but they are so let's record it // the user was not known to be registered, but now they are (because we got no error) so let's record it
try { try {
await db.open(); await db.open();
db.settings.update(MASTER_SETTINGS_KEY, { db.settings.update(MASTER_SETTINGS_KEY, {
@ -1062,6 +1079,10 @@ export default class AccountViewView extends Vue {
); );
} }
} }
const imageResp = await this.fetchImageRateLimits(identity);
if (imageResp.status === 200) {
this.imageLimits = imageResp.data;
}
} }
} catch (error) { } catch (error) {
this.handleRateLimitsError(error); this.handleRateLimitsError(error);
@ -1082,17 +1103,29 @@ export default class AccountViewView extends Vue {
} }
/** /**
* Fetches rate limits from the server. * Fetches rate limits from the Endorser server.
* *
* @param {IIdentifier} identity - The identity object to check rate limits for. * @param {IIdentifier} identity - The identity object to check rate limits for.
* @returns {Promise<AxiosResponse>} The Axios response object. * @returns {Promise<AxiosResponse>} The Axios response object.
*/ */
private async fetchRateLimits(identity: IIdentifier) { private async fetchEndorserRateLimits(identity: IIdentifier) {
const url = `${this.apiServer}/api/report/rateLimits`; const url = `${this.apiServer}/api/report/rateLimits`;
const headers = await this.getHeaders(identity); const headers = await this.getHeaders(identity);
return await this.axios.get(url, { headers } as AxiosRequestConfig); return await this.axios.get(url, { headers } as AxiosRequestConfig);
} }
/**
* Fetches rate limits from the image server.
*
* @param {IIdentifier} identity - The identity object to check rate limits for.
* @returns {Promise<AxiosResponse>} The Axios response object.
*/
private async fetchImageRateLimits(identity: IIdentifier) {
const url = DEFAULT_IMAGE_API_SERVER + "/image-limits";
const headers = await this.getHeaders(identity);
return await this.axios.get(url, { headers } as AxiosRequestConfig);
}
/** /**
* Handles errors that occur while fetching rate limits. * Handles errors that occur while fetching rate limits.
* *

Loading…
Cancel
Save