chore: configure base url (#179)

* chore: set base api url

* chore: change config varibales names

* chore: rename env var

* chore: set base url to match wakatime cli usage
This commit is contained in:
Juan Sebastian velez Posada
2023-03-28 17:50:32 -05:00
committed by GitHub
parent 1e9e233066
commit c2ead5149d
9 changed files with 87 additions and 37 deletions

View File

@@ -9,6 +9,7 @@ interface State {
alertText: string; alertText: string;
alertType: SuccessOrFailType; alertType: SuccessOrFailType;
apiKey: string; apiKey: string;
apiUrl: string;
blacklist: string; blacklist: string;
displayAlert: boolean; displayAlert: boolean;
hostname: string; hostname: string;
@@ -25,6 +26,7 @@ export default function Options(): JSX.Element {
alertText: config.alert.success.text, alertText: config.alert.success.text,
alertType: config.alert.success.type, alertType: config.alert.success.type,
apiKey: '', apiKey: '',
apiUrl: config.apiUrl,
blacklist: '', blacklist: '',
displayAlert: false, displayAlert: false,
hostname: '', hostname: '',
@@ -42,6 +44,7 @@ export default function Options(): JSX.Element {
const restoreSettings = async (): Promise<void> => { const restoreSettings = async (): Promise<void> => {
const items = await browser.storage.sync.get({ const items = await browser.storage.sync.get({
apiKey: config.apiKey, apiKey: config.apiKey,
apiUrl: config.apiUrl,
blacklist: '', blacklist: '',
hostname: config.hostname, hostname: config.hostname,
loggingStyle: config.loggingStyle, loggingStyle: config.loggingStyle,
@@ -54,6 +57,7 @@ export default function Options(): JSX.Element {
setState({ setState({
...state, ...state,
apiKey: items.apiKey as string, apiKey: items.apiKey as string,
apiUrl: items.apiUrl as string,
blacklist: items.blacklist as string, blacklist: items.blacklist as string,
hostname: items.hostname as string, hostname: items.hostname as string,
loggingStyle: items.loggingStyle as string, loggingStyle: items.loggingStyle as string,
@@ -82,6 +86,7 @@ export default function Options(): JSX.Element {
setState({ ...state, loading: true }); setState({ ...state, loading: true });
const apiKey = state.apiKey; const apiKey = state.apiKey;
const apiUrl = state.apiUrl;
const theme = state.theme; const theme = state.theme;
const hostname = state.hostname; const hostname = state.hostname;
const loggingType = state.loggingType; const loggingType = state.loggingType;
@@ -95,6 +100,7 @@ export default function Options(): JSX.Element {
// Sync options with google storage. // Sync options with google storage.
await browser.storage.sync.set({ await browser.storage.sync.set({
apiKey, apiKey,
apiUrl,
blacklist, blacklist,
hostname, hostname,
loggingStyle, loggingStyle,
@@ -109,6 +115,7 @@ export default function Options(): JSX.Element {
setState({ setState({
...state, ...state,
apiKey, apiKey,
apiUrl,
blacklist, blacklist,
displayAlert: true, displayAlert: true,
hostname, hostname,
@@ -273,6 +280,23 @@ export default function Options(): JSX.Element {
</div> </div>
</div> </div>
<div className="form-group">
<label htmlFor="theme" className="col-lg-2 control-label">
API Url
</label>
<div className="col-lg-10">
<input
type="text"
className="form-control"
value={state.apiUrl}
onChange={(e) => setState({ ...state, apiUrl: e.target.value })}
placeholder="https://wakatime.com/api/v1"
/>
<span className="help-block">https://wakatime.com/api/v1</span>
</div>
</div>
<div className="form-group row"> <div className="form-group row">
<div className="col-lg-10 col-lg-offset-2 space-between align-items-center"> <div className="col-lg-10 col-lg-offset-2 space-between align-items-center">
<div <div

View File

@@ -1,12 +1,12 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { ApiKeyReducer, ReduxSelector } from '../types/store';
import { fetchUserData } from '../utils/user';
import apiKeyInvalid from '../utils/apiKey';
import config from '../config/config'; import config from '../config/config';
import { ApiKeyReducer, ReduxSelector } from '../types/store';
import apiKeyInvalid from '../utils/apiKey';
import { fetchUserData } from '../utils/user';
import Alert from './Alert'; import Alert from './Alert';
import NavBar from './NavBar';
import MainList from './MainList'; import MainList from './MainList';
import NavBar from './NavBar';
export default function WakaTime(): JSX.Element { export default function WakaTime(): JSX.Element {
const dispatch = useDispatch(); const dispatch = useDispatch();
@@ -35,7 +35,7 @@ export default function WakaTime(): JSX.Element {
{isApiKeyValid && extensionState === 'notSignedIn' && ( {isApiKeyValid && extensionState === 'notSignedIn' && (
<Alert <Alert
type={config.alert.failure.type} type={config.alert.failure.type}
text={'Invalid api key'} text={'Invalid API key or API url'}
onClick={() => browser.runtime.openOptionsPage()} onClick={() => browser.runtime.openOptionsPage()}
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
/> />

View File

@@ -25,13 +25,14 @@ describe('wakatime config', () => {
}, },
}, },
"apiKey": "", "apiKey": "",
"apiUrl": "https://wakatime.com/api/v1",
"colors": { "colors": {
"allGood": "", "allGood": "",
"lightTheme": "white", "lightTheme": "white",
"notLogging": "gray", "notLogging": "gray",
"notSignedIn": "red", "notSignedIn": "red",
}, },
"currentUserApiUrl": "https://wakatime.com/api/v1/users/current", "currentUserApiEndPoint": "/users/current",
"detectionIntervalInSeconds": 60, "detectionIntervalInSeconds": 60,
"devSites": "https://codepen.io/ "devSites": "https://codepen.io/
https://www.codewars.com/ https://www.codewars.com/
@@ -43,7 +44,7 @@ describe('wakatime config', () => {
https://stackoverflow.com/ https://stackoverflow.com/
https://www.udemy.com/ https://www.udemy.com/
https://www.w3schools.com/", https://www.w3schools.com/",
"heartbeatApiUrl": "https://wakatime.com/api/v1/users/current/heartbeats", "heartbeatApiEndPoint": "/users/current/heartbeats",
"hostname": "", "hostname": "",
"loggingEnabled": true, "loggingEnabled": true,
"loggingStyle": "blacklist", "loggingStyle": "blacklist",
@@ -67,7 +68,7 @@ describe('wakatime config', () => {
"blacklisted", "blacklisted",
"whitelisted", "whitelisted",
], ],
"summariesApiUrl": "https://wakatime.com/api/v1/users/current/summaries", "summariesApiEndPoint": "/users/current/summaries",
"theme": "light", "theme": "light",
"tooltips": { "tooltips": {
"allGood": "", "allGood": "",

View File

@@ -53,11 +53,12 @@ export interface Config {
* API key use to query wakatime api * API key use to query wakatime api
*/ */
apiKey: ''; apiKey: '';
apiUrl: string;
colors: Colors; colors: Colors;
/** /**
* Url from which to detect if the user is logged in * Url from which to detect if the user is logged in
*/ */
currentUserApiUrl: string; currentUserApiEndPoint: string;
/** /**
* Time for idle state of the browser * Time for idle state of the browser
* The user is considered idle if there was * The user is considered idle if there was
@@ -69,7 +70,7 @@ export interface Config {
/** /**
* Url to which to send the heartbeat * Url to which to send the heartbeat
*/ */
heartbeatApiUrl: string; heartbeatApiEndPoint: string;
hostname: string; hostname: string;
/** /**
@@ -91,7 +92,7 @@ export interface Config {
/** /**
* Get stats from the wakatime api * Get stats from the wakatime api
*/ */
summariesApiUrl: string; summariesApiEndPoint: string;
/** /**
* Options for theme * Options for theme
*/ */
@@ -118,6 +119,8 @@ const config: Config = {
apiKey: '', apiKey: '',
apiUrl: process.env.API_URL ?? 'https://wakatime.com/api/v1',
colors: { colors: {
allGood: '', allGood: '',
lightTheme: 'white', lightTheme: 'white',
@@ -125,16 +128,14 @@ const config: Config = {
notSignedIn: 'red', notSignedIn: 'red',
}, },
currentUserApiUrl: currentUserApiEndPoint: process.env.CURRENT_USER_API_URL ?? '/users/current',
process.env.CURRENT_USER_API_URL ?? 'https://wakatime.com/api/v1/users/current',
detectionIntervalInSeconds: 60, detectionIntervalInSeconds: 60,
devSites: devSites:
'https://codepen.io/\nhttps://www.codewars.com/\nhttps://dev.to/\nhttps://github.com/\nhttps://www.hackerrank.com/\nhttps://leetcode.com/\nhttps://developer.mozilla.org/en-US/\nhttps://stackoverflow.com/\nhttps://www.udemy.com/\nhttps://www.w3schools.com/', 'https://codepen.io/\nhttps://www.codewars.com/\nhttps://dev.to/\nhttps://github.com/\nhttps://www.hackerrank.com/\nhttps://leetcode.com/\nhttps://developer.mozilla.org/en-US/\nhttps://stackoverflow.com/\nhttps://www.udemy.com/\nhttps://www.w3schools.com/',
heartbeatApiUrl: heartbeatApiEndPoint: process.env.HEARTBEAT_API_URL ?? '/users/current/heartbeats',
process.env.HEART_BEAT_API_URL ?? 'https://wakatime.com/api/v1/users/current/heartbeats',
hostname: '', hostname: '',
@@ -152,8 +153,7 @@ const config: Config = {
states: ['allGood', 'notLogging', 'notSignedIn', 'blacklisted', 'whitelisted'], states: ['allGood', 'notLogging', 'notSignedIn', 'blacklisted', 'whitelisted'],
summariesApiUrl: summariesApiEndPoint: process.env.SUMMARIES_API_URL ?? '/users/current/summaries',
process.env.SUMMARIES_API_URL ?? 'https://wakatime.com/api/v1/users/current/summaries',
theme: 'light', theme: 'light',

View File

@@ -49,9 +49,14 @@ class WakaTimeCore {
} }
async getTotalTimeLoggedToday(api_key = ''): Promise<GrandTotal> { async getTotalTimeLoggedToday(api_key = ''): Promise<GrandTotal> {
const items = await browser.storage.sync.get({
apiUrl: config.apiUrl,
summariesApiEndPoint: config.summariesApiEndPoint,
});
const today = moment().format('YYYY-MM-DD'); const today = moment().format('YYYY-MM-DD');
const summariesAxiosPayload: AxiosResponse<SummariesPayload> = await axios.get( const summariesAxiosPayload: AxiosResponse<SummariesPayload> = await axios.get(
config.summariesApiUrl, `${items.apiUrl}${items.summariesApiEndPoint}`,
{ {
params: { params: {
api_key, api_key,
@@ -70,8 +75,13 @@ class WakaTimeCore {
*/ */
async fetchApiKey(): Promise<string> { async fetchApiKey(): Promise<string> {
try { try {
const items = await browser.storage.sync.get({
apiUrl: config.apiUrl,
currentUserApiEndPoint: config.currentUserApiEndPoint,
});
const apiKeyResponse: AxiosResponse<ApiKeyPayload> = await axios.post( const apiKeyResponse: AxiosResponse<ApiKeyPayload> = await axios.post(
`${config.currentUserApiUrl}/get_api_key`, `${items.apiUrl}${items.currentUserApiEndPoint}/get_api_key`,
); );
return apiKeyResponse.data.data.api_key; return apiKeyResponse.data.data.api_key;
} catch (err: unknown) { } catch (err: unknown) {
@@ -85,8 +95,12 @@ class WakaTimeCore {
* @returns {*} * @returns {*}
*/ */
async checkAuth(api_key = ''): Promise<User> { async checkAuth(api_key = ''): Promise<User> {
const items = await browser.storage.sync.get({
apiUrl: config.apiUrl,
currentUserApiEndPoint: config.currentUserApiEndPoint,
});
const userPayload: AxiosResponse<AxiosUserResponse> = await axios.get( const userPayload: AxiosResponse<AxiosUserResponse> = await axios.get(
config.currentUserApiUrl, `${items.apiUrl}${items.currentUserApiEndPoint}`,
{ params: { api_key } }, { params: { api_key } },
); );
return userPayload.data.data; return userPayload.data.data;
@@ -345,6 +359,11 @@ class WakaTimeCore {
hostname = '', hostname = '',
): Promise<void> { ): Promise<void> {
try { try {
const items = await browser.storage.sync.get({
apiUrl: config.apiUrl,
heartbeatApiEndPoint: config.heartbeatApiEndPoint,
});
const request: RequestInit = { const request: RequestInit = {
body: JSON.stringify(payload), body: JSON.stringify(payload),
credentials: 'omit', credentials: 'omit',
@@ -355,7 +374,10 @@ class WakaTimeCore {
'X-Machine-Name': hostname, 'X-Machine-Name': hostname,
}; };
} }
const response = await fetch(`${config.heartbeatApiUrl}?api_key=${apiKey}`, request); const response = await fetch(
`${items.apiUrl}${items.heartbeatApiEndPoint}?api_key=${apiKey}`,
request,
);
await response.json(); await response.json();
} catch (err: unknown) { } catch (err: unknown) {
if (this.db) { if (this.db) {

View File

@@ -26,5 +26,5 @@
"page": "options.html" "page": "options.html"
}, },
"permissions": ["alarms", "tabs", "storage", "idle"], "permissions": ["alarms", "tabs", "storage", "idle"],
"version": "3.0.7" "version": "3.0.8"
} }

View File

@@ -39,5 +39,5 @@
"storage", "storage",
"idle" "idle"
], ],
"version": "3.0.7" "version": "3.0.8"
} }

View File

@@ -1,7 +1,8 @@
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
import axios, { AxiosResponse } from 'axios'; import axios, { AxiosResponse } from 'axios';
import { CurrentUser, User, UserPayload } from '../types/user'; import browser from 'webextension-polyfill';
import config from '../config/config'; import config from '../config/config';
import { CurrentUser, User, UserPayload } from '../types/user';
interface setUserAction { interface setUserAction {
payload: User | undefined; payload: User | undefined;
@@ -14,9 +15,16 @@ export const name: NameType = 'currentUser';
export const fetchCurrentUser = createAsyncThunk<User, string>( export const fetchCurrentUser = createAsyncThunk<User, string>(
`[${name}]`, `[${name}]`,
async (api_key = '') => { async (api_key = '') => {
const userPayload: AxiosResponse<UserPayload> = await axios.get(config.currentUserApiUrl, { const items = await browser.storage.sync.get({
params: { api_key }, apiUrl: config.apiUrl,
currentUserApiEndPoint: config.currentUserApiEndPoint,
}); });
const userPayload: AxiosResponse<UserPayload> = await axios.get(
`${items.apiUrl}${items.currentUserApiEndPoint}`,
{
params: { api_key },
},
);
return userPayload.data.data; return userPayload.data.data;
}, },
); );

View File

@@ -55,17 +55,12 @@ const getConfigByBrowser = (isProd: boolean, browser: BrowserTypes): webpack.Con
], ],
}), }),
new webpack.DefinePlugin({ new webpack.DefinePlugin({
['process.env.CURRENT_USER_API_URL']: JSON.stringify( ['process.env.API_URL']: JSON.stringify('https://wakatime.com/api/v1'),
'https://wakatime.com/api/v1/users/current', ['process.env.CURRENT_USER_API_URL']: JSON.stringify('/users/current'),
), ['process.env.HEARTBEAT_API_URL']: JSON.stringify('/users/current/heartbeats'),
['process.env.HEART_BEAT_API_URL']: JSON.stringify(
'https://wakatime.com/api/v1/users/current/heartbeats',
),
['process.env.LOGOUT_USER_URL']: JSON.stringify('https://wakatime.com/logout'), ['process.env.LOGOUT_USER_URL']: JSON.stringify('https://wakatime.com/logout'),
['process.env.NODE_ENV']: JSON.stringify(isProd ? 'production' : 'development'), ['process.env.NODE_ENV']: JSON.stringify(isProd ? 'production' : 'development'),
['process.env.SUMMARIES_API_URL']: JSON.stringify( ['process.env.SUMMARIES_API_URL']: JSON.stringify('/users/current/summaries'),
'https://wakatime.com/api/v1/users/current/summaries',
),
}), }),
], ],
resolve: { resolve: {