|  |  | @ -96,7 +96,7 @@ | 
			
		
	
		
			
				
					|  |  |  |     <!-- 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. --> | 
			
		
	
		
			
				
					|  |  |  |     <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" | 
			
		
	
		
			
				
					|  |  |  |     > | 
			
		
	
		
			
				
					|  |  |  |       <p class="mb-4"> | 
			
		
	
	
		
			
				
					|  |  | @ -157,28 +157,39 @@ | 
			
		
	
		
			
				
					|  |  |  |       <div> | 
			
		
	
		
			
				
					|  |  |  |         {{ limitsMessage }} | 
			
		
	
		
			
				
					|  |  |  |       </div> | 
			
		
	
		
			
				
					|  |  |  |       <div v-if="!!limits?.nextWeekBeginDateTime"> | 
			
		
	
		
			
				
					|  |  |  |         <p class="mb-3 text-sm"> | 
			
		
	
		
			
				
					|  |  |  |           You have done <b>{{ limits.doneClaimsThisWeek }}</b> claims out of | 
			
		
	
		
			
				
					|  |  |  |           <b>{{ limits.maxClaimsPerWeek }}</b> for this week. Your claims | 
			
		
	
		
			
				
					|  |  |  |           counter resets at | 
			
		
	
		
			
				
					|  |  |  |       <div v-if="!!endorserLimits?.nextWeekBeginDateTime"> | 
			
		
	
		
			
				
					|  |  |  |         <p class="text-sm"> | 
			
		
	
		
			
				
					|  |  |  |           You have done | 
			
		
	
		
			
				
					|  |  |  |           <b>{{ endorserLimits.doneClaimsThisWeek }} claims</b> out of | 
			
		
	
		
			
				
					|  |  |  |           <b>{{ endorserLimits.maxClaimsPerWeek }}</b> for this week. Your | 
			
		
	
		
			
				
					|  |  |  |           claims counter resets at | 
			
		
	
		
			
				
					|  |  |  |           <b class="whitespace-nowrap">{{ | 
			
		
	
		
			
				
					|  |  |  |             readableTime(limits.nextWeekBeginDateTime) | 
			
		
	
		
			
				
					|  |  |  |             readableDate(endorserLimits.nextWeekBeginDateTime) | 
			
		
	
		
			
				
					|  |  |  |           }}</b> | 
			
		
	
		
			
				
					|  |  |  |         </p> | 
			
		
	
		
			
				
					|  |  |  |         <p class="text-sm"> | 
			
		
	
		
			
				
					|  |  |  |         <p class="mt-3 text-sm"> | 
			
		
	
		
			
				
					|  |  |  |           You have done | 
			
		
	
		
			
				
					|  |  |  |           <b>{{ limits.doneRegistrationsThisMonth }}</b> registrations out of | 
			
		
	
		
			
				
					|  |  |  |           <b>{{ limits.maxRegistrationsPerMonth }}</b> for this month. | 
			
		
	
		
			
				
					|  |  |  |           <b>{{ endorserLimits.doneRegistrationsThisMonth }} registrations</b> | 
			
		
	
		
			
				
					|  |  |  |           out of <b>{{ endorserLimits.maxRegistrationsPerMonth }}</b> for this | 
			
		
	
		
			
				
					|  |  |  |           month. | 
			
		
	
		
			
				
					|  |  |  |           <i | 
			
		
	
		
			
				
					|  |  |  |             >(You can register nobody on your first day, and after that only one | 
			
		
	
		
			
				
					|  |  |  |             a day in your first month.)</i | 
			
		
	
		
			
				
					|  |  |  |           > | 
			
		
	
		
			
				
					|  |  |  |           Your registration counter resets at | 
			
		
	
		
			
				
					|  |  |  |           <b class="whitespace-nowrap"> | 
			
		
	
		
			
				
					|  |  |  |             {{ readableTime(limits.nextMonthBeginDateTime) }} | 
			
		
	
		
			
				
					|  |  |  |             {{ readableDate(endorserLimits.nextMonthBeginDateTime) }} | 
			
		
	
		
			
				
					|  |  |  |           </b> | 
			
		
	
		
			
				
					|  |  |  |         </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> | 
			
		
	
		
			
				
					|  |  |  |       <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" | 
			
		
	
	
		
			
				
					|  |  | @ -509,6 +520,7 @@ import QuickNav from "@/components/QuickNav.vue"; | 
			
		
	
		
			
				
					|  |  |  | import TopMessage from "@/components/TopMessage.vue"; | 
			
		
	
		
			
				
					|  |  |  | import { | 
			
		
	
		
			
				
					|  |  |  |   AppString, | 
			
		
	
		
			
				
					|  |  |  |   DEFAULT_IMAGE_API_SERVER, | 
			
		
	
		
			
				
					|  |  |  |   DEFAULT_PUSH_SERVER, | 
			
		
	
		
			
				
					|  |  |  |   NotificationIface, | 
			
		
	
		
			
				
					|  |  |  | } from "@/constants/app"; | 
			
		
	
	
		
			
				
					|  |  | @ -516,7 +528,11 @@ import { db, accountsDB } from "@/db/index"; | 
			
		
	
		
			
				
					|  |  |  | import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings"; | 
			
		
	
		
			
				
					|  |  |  | import { accessToken } from "@/libs/crypto"; | 
			
		
	
		
			
				
					|  |  |  | 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 | 
			
		
	
		
			
				
					|  |  |  | const Buffer = require("buffer/").Buffer; | 
			
		
	
	
		
			
				
					|  |  | @ -542,7 +558,9 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |   apiServerInput = ""; | 
			
		
	
		
			
				
					|  |  |  |   derivationPath = ""; | 
			
		
	
		
			
				
					|  |  |  |   downloadUrl = ""; // because DuckDuckGo doesn't download on automated call to "click" on the anchor | 
			
		
	
		
			
				
					|  |  |  |   endorserLimits: EndorserRateLimits | null = null; | 
			
		
	
		
			
				
					|  |  |  |   givenName = ""; | 
			
		
	
		
			
				
					|  |  |  |   imageLimits: ImageRateLimits | null = null; | 
			
		
	
		
			
				
					|  |  |  |   isRegistered = false; | 
			
		
	
		
			
				
					|  |  |  |   isSubscribed = false; | 
			
		
	
		
			
				
					|  |  |  |   notificationMaybeChanged = false; | 
			
		
	
	
		
			
				
					|  |  | @ -550,7 +568,6 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |   publicBase64 = ""; | 
			
		
	
		
			
				
					|  |  |  |   webPushServer = ""; | 
			
		
	
		
			
				
					|  |  |  |   webPushServerInput = ""; | 
			
		
	
		
			
				
					|  |  |  |   limits: RateLimits | null = null; | 
			
		
	
		
			
				
					|  |  |  |   limitsMessage = ""; | 
			
		
	
		
			
				
					|  |  |  |   loadingLimits = false; | 
			
		
	
		
			
				
					|  |  |  |   showContactGives = false; | 
			
		
	
	
		
			
				
					|  |  | @ -697,7 +714,7 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |     this.updateShowShortcutBvc(this.showShortcutBvc); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |   readableTime(timeStr: string) { | 
			
		
	
		
			
				
					|  |  |  |   readableDate(timeStr: string) { | 
			
		
	
		
			
				
					|  |  |  |     return timeStr.substring(0, timeStr.indexOf("T")); | 
			
		
	
		
			
				
					|  |  |  |   } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  | @ -1038,11 +1055,11 @@ export default class AccountViewView extends Vue { | 
			
		
	
		
			
				
					|  |  |  |     this.limitsMessage = ""; | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     try { | 
			
		
	
		
			
				
					|  |  |  |       const resp = await this.fetchRateLimits(identity); | 
			
		
	
		
			
				
					|  |  |  |       const resp = await this.fetchEndorserRateLimits(identity); | 
			
		
	
		
			
				
					|  |  |  |       if (resp.status === 200) { | 
			
		
	
		
			
				
					|  |  |  |         this.limits = resp.data; | 
			
		
	
		
			
				
					|  |  |  |         this.endorserLimits = resp.data; | 
			
		
	
		
			
				
					|  |  |  |         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 { | 
			
		
	
		
			
				
					|  |  |  |             await db.open(); | 
			
		
	
		
			
				
					|  |  |  |             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) { | 
			
		
	
		
			
				
					|  |  |  |       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. | 
			
		
	
		
			
				
					|  |  |  |    * @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 headers = await this.getHeaders(identity); | 
			
		
	
		
			
				
					|  |  |  |     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. | 
			
		
	
		
			
				
					|  |  |  |    * | 
			
		
	
	
		
			
				
					|  |  | 
 |