Commit cf2e5931 authored by Viacheslav Pavlov's avatar Viacheslav Pavlov Committed by Matija Obreza
Browse files

fixed client side axios auth, fixed UserBrowsePage, added validators

parent c6bf6f36
......@@ -3,5 +3,10 @@
"welcome": {
"title": "Grin global application"
}
},
"validate": {
"error": {
"required": "Required"
}
}
}
{
"action": {
"back": "Back",
"logout": "Logout",
"submit": "Submit"
},
"label": {
"loadingData": null
}
......
export const UPDATE_HISTORY = 'UPDATE_HISTORY';
import { Page, SortDirection } from '@gringlobal/client/model/page';
/*
* Defined in OpenAPI as '#/definitions/Page<T>'
*/
class FilteredPage<T> extends Page<T> {
public filterCode?: string;
public filter?: any;
public static reSort(paged: FilteredPage<any>, property?: string, direction?: SortDirection): FilteredPage<any> {
const resorted: FilteredPage<any> = {
filterCode: paged ? paged.filterCode : undefined,
// number: undefined, // because loadMore defaults to 0
size: paged ? paged.size : undefined,
sort: [ {
property: property ? property : undefined,
direction: direction ? direction : undefined,
} ],
};
console.log(`reSort for prop=${property} dir=${direction}`, resorted);
return resorted;
}
public static merge(oldPaged: FilteredPage<any>, newPaged: FilteredPage<any>): FilteredPage<any> {
if (!oldPaged) {
return newPaged;
}
if (! newPaged) {
return oldPaged;
}
const { filterCode, filter, ...other } = newPaged; // other helps with properties of subclasses
return {
...other,
...Page.merge(oldPaged, newPaged),
filterCode: filterCode === '' ? '' : filterCode || oldPaged.filterCode,
filter: filter || oldPaged.filter,
};
}
}
export default FilteredPage;
import { SortDirection } from '@gringlobal/client/model/page';
export default interface IPageRequest {
page?: number; // page number
size?: number; // page size
direction?: SortDirection; // direction
properties?: string[]; // sort by properties
}
import { SortDirection } from '@gringlobal/client/model/page';
export default interface ISort {
ascending?: boolean;
descending?: boolean;
direction: SortDirection;
property: string;
}
/*
* Defined in OpenAPI as '#/definitions/Page<T>'
*/
import { IPageRequest, ISort, SortDirection } from '@gringlobal/client/model/page';
class Page<T> {
public content?: T[];
public last?: boolean;
public number?: number;
public totalElements?: number;
public totalPages?: number;
public size?: number;
public sort?: ISort[];
public static nextPage(paged?: Page<any>): IPageRequest {
const nextPage: IPageRequest = {
page: paged && (paged.number || paged.number === 0) ? paged.number + 1 : 0,
size: paged && paged.size || 50,
direction: paged && paged.sort && paged.sort[0].direction || undefined,
properties: paged && paged.sort && paged.sort[0].property ? [ paged.sort[0].property ] : undefined,
};
// console.log('Current/Next', paged, nextPage);
return nextPage;
}
public static fromQueryString(qs: any): IPageRequest {
return {
page: 0,
size: undefined,
properties: qs ? [ qs.s ] : undefined,
direction: qs ? qs.d : undefined,
};
}
public static reSort(paged: Page<any>, property?: string, direction?: SortDirection): Page<any> {
const resorted: Page<any> = {
number: undefined, // because loadMore defaults to 0
size: undefined,
sort: [ {
property: property ? property : undefined,
direction: direction ? direction : undefined,
} ],
};
console.log(`Resort for prop=${property} dir={direction}`, resorted);
return resorted;
}
public static merge(oldPaged: Page<any>, newPaged: Page<any>): Page<any> {
if (!oldPaged) {
return newPaged;
}
return newPaged ? {
content: newPaged.content && newPaged.number === 0 ? newPaged.content : (newPaged.content ? [...oldPaged.content, ...newPaged.content] : oldPaged.content),
last: newPaged.last === false ? newPaged.last : newPaged.last || oldPaged.last,
number: newPaged.number === 0 ? newPaged.number : newPaged.number || oldPaged.number,
totalElements: newPaged.totalElements === 0 ? newPaged.totalElements : newPaged.totalElements || oldPaged.totalElements,
totalPages: newPaged.totalPages === 0 ? newPaged.totalPages : newPaged.totalPages || oldPaged.totalPages,
size: newPaged.size === 0 ? newPaged.size : newPaged.size || oldPaged.size,
sort: newPaged.sort || oldPaged.sort,
} : oldPaged;
}
}
export default Page;
// TODO Remove, we're using infinite loaders
export default class Pagination<T> {
public page: number;
public size: number;
// TODO Should we be using DataOrder (below)?
public sort: string[] | string;
public dir: string[] | string;
public filter: T;
public filterCode: string;
public constructor(obj?) {
if (obj !== null && obj !== undefined) {
const props = Object.keys(obj);
for (const prop of props) { this[prop] = obj[prop] }
}
}
public equals(other: Pagination<T>): boolean {
if (other === null) {
return false;
}
if (this.page !== other.page) {
return false;
}
if (this.size !== other.size) {
return false;
}
if (this.filterCode !== other.filterCode) {
return false;
}
if (JSON.stringify(this.sort) !== JSON.stringify(other.sort)) {
return false;
}
return JSON.stringify(this.dir) === JSON.stringify(other.dir);
}
}
enum SortDirection {
ASC = 'ASC',
DESC = 'DESC',
}
export default SortDirection;
import { FilteredPage } from '@gringlobal/client/model/page';
export default class SuggestionsPage<T> extends FilteredPage<T> {
public suggestions: any;
}
export { default as FilteredPage } from '@gringlobal/client/model/page/FilteredPage';
export { default as IPageRequest } from '@gringlobal/client/model/page/IPageRequest';
export { default as ISort } from '@gringlobal/client/model/page/ISort';
export { default as Page } from '@gringlobal/client/model/page/Page';
export { default as Pagination } from '@gringlobal/client/model/page/Pagination';
export { default as SortDirection } from '@gringlobal/client/model/page/SortDirection';
import update from 'immutability-helper';
import { UPDATE_HISTORY } from '@gringlobal/client/constants/history';
const INITIAL_STATE: {
hasHistory: boolean,
lastLocation: string,
} = {
hasHistory: false,
lastLocation: '/',
};
export default (state = INITIAL_STATE, action: { type?: string, payload?: any } = { type: '', payload: {} }) => {
switch (action.type) {
case UPDATE_HISTORY: {
return update(state, {
hasHistory: { $set: true },
lastLocation: { $set: action.payload },
});
}
default:
return state;
}
}
......@@ -3,6 +3,7 @@ import { connectRouter } from 'connected-react-router';
// common reduces
import applicationConfig from '@gringlobal/client/reducer/applicationConfig';
import historyReducer from '@gringlobal/client/reducer/history';
import login from '@gringlobal/client/reducer/login';
import pageTitle from '@gringlobal/client/reducer/pageTitle';
......@@ -13,6 +14,7 @@ const coreReducers = (history?) => ({
// common reducers
applicationConfig,
history: historyReducer,
login,
pageTitle,
......
......@@ -27,6 +27,9 @@ export class LoginService {
}
public static login(username: string, password: string, xhrConfig?) {
console.error('====================', axiosBackend.defaults.headers);
const form = new FormData();
form.append('username', username);
form.append('password', password);
......@@ -50,6 +53,8 @@ export class LoginService {
*/
public static logout(authToken: string, xhrConfig?): Promise<any> {
console.error('====================', axiosBackend.defaults.headers);
const apiUrl = URL_LOGOUT;
// console.log(`Fetching from ${apiUrl}`);
const content = { /* No content in request body */};
......
import { AxiosRequestConfig } from 'axios';
import * as UrlTemplate from 'url-template';
import * as QueryString from 'query-string';
// Model
import User from '@gringlobal/client/model/user/User';
import { FilteredPage, IPageRequest } from '@gringlobal/client/model/page';
// utilities
import { axiosBackend } from '@gringlobal/client/utilities/requestUtils';
const LIST_USERS_URL = '/api/user/list';
const GET_USER_URL = UrlTemplate.parse('/api/user/{uuid}');
const LIST_USERS_URL = '/api/v1/user/list';
const GET_USER_URL = UrlTemplate.parse('/api/v1/user/{uuid}');
export default class UserService {
public static listUsers(xhrConfig?: AxiosRequestConfig) {
const apiUrl = LIST_USERS_URL;
/**
* listUsers at /api/v1/user/list
*
* @param filter the user filter
* @param page the page
*/
public static listUsers(filter: string, page: IPageRequest, xhrConfig?): Promise<FilteredPage<User>> {
const qs = QueryString.stringify({
f: typeof filter === 'string' ? filter : undefined,
p: page.page || undefined,
l: page.size || 100,
d: page.direction ? page.direction : undefined,
s: page.properties && page.properties.length && page.properties || undefined,
}, {});
const apiUrl = LIST_USERS_URL + (qs ? `?${qs}` : '');
// console.log(`Fetching from ${apiUrl}`);
const content = { };
return axiosBackend.get(apiUrl, {
return axiosBackend({
...xhrConfig,
},
).then(({ data }) => data as User[])
.catch(({ error }) => error as any);
url: apiUrl,
method: 'POST',
...content,
}).then(({ data }) => data as FilteredPage<User>);
}
public static getUser(uuid: string, xhrConfig?: AxiosRequestConfig): Promise<User> {
......
......@@ -56,7 +56,7 @@ export const configureBackendApi = ({ apiUrl, accessToken, origin, timeout }: {
console.log('axiosBackend.defaults.headers', axiosBackend.defaults.headers);
}
if (accessToken) {
console.log('Using backend API accessToken ..snip..');
console.log('Using backend API accessToken ..snip..', `Bearer ${accessToken}`);
axiosBackend.defaults.headers.common.Authorization = `Bearer ${accessToken}`;
}
if (origin) {
......
export const required = (value, allValues, meta) => !value ? 'client:validate.error.required' : undefined;
......@@ -64,6 +64,7 @@ if (__PRELOADED_STATE__ === undefined) {
checkAccessTokens(store.dispatch, store.getState)
.then(() => store.dispatch(receiveLang(detectedLang)))
.then(() => configureBackendApi({ accessToken: store.getState().login.access_token }))
.then(() => {
// no SSR
ReactDOM.render(
......@@ -85,6 +86,7 @@ if (__PRELOADED_STATE__ === undefined) {
} else {
// SSR
Loadable.preloadReady().then(() => {
configureBackendApi({ accessToken: store.getState().login.access_token });
ReactDOM.hydrate(
<Provider store={store}>
<ConnectedRouter history={history}>
......
{
"user": {
"p": {
"login": {
"youLoggedIn": "You logged in as {{username}}"
"public": {
"p": {
"login": {
"youLoggedIn": "You logged in as {{username}}"
}
}
},
"admin": {
"p": {
"browse": {
"title": "List of users"
}
}
}
}
......
......@@ -6,7 +6,7 @@ import user from 'user/reducer';
const rootReducer = (history?) => (combineReducers({
// model reducers
...user,
user,
...coreReducers(history),
}));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment