add response interceptors for refreshTokens method
This commit is contained in:
committed by
Daniel Hutzel
parent
76cbf7f9ca
commit
938abb6387
13
media-store/app/.vscode/launch.json
vendored
Normal file
13
media-store/app/.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Chrome",
|
||||||
|
"type": "chrome",
|
||||||
|
"request": "launch",
|
||||||
|
"url": "http://localhost:3000",
|
||||||
|
"webRoot": "${workspaceRoot}/src"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
"@umijs/hooks": "^1.9.3",
|
"@umijs/hooks": "^1.9.3",
|
||||||
"antd": "^4.8.2",
|
"antd": "^4.8.2",
|
||||||
"axios": "^0.20.0",
|
"axios": "^0.20.0",
|
||||||
|
"events": "^3.2.0",
|
||||||
"lodash": "^4.17.20",
|
"lodash": "^4.17.20",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"react": "^16.14.0",
|
"react": "^16.14.0",
|
||||||
@@ -18,9 +19,9 @@
|
|||||||
"react-scripts": "^4.0.0"
|
"react-scripts": "^4.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start --no-cache",
|
||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test --no-cache",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
|
|||||||
@@ -1,3 +1,22 @@
|
|||||||
|
@import "~antd/dist/antd.css";
|
||||||
|
|
||||||
|
html {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#root {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
section.ant-layout {
|
||||||
|
height: 100vh;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Layout
|
||||||
|
*/
|
||||||
|
.site-layout .site-layout-background {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
.App {
|
.App {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@@ -36,7 +55,3 @@
|
|||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-menu.ant-menu-sub.ant-menu-vertical {
|
|
||||||
border-radius: 6px !important;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,15 +2,15 @@ import React from "react";
|
|||||||
import "antd/dist/antd.css";
|
import "antd/dist/antd.css";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
import { Layout } from "antd";
|
import { Layout } from "antd";
|
||||||
import { MyRouter } from "./Router";
|
import { MyRouter } from "./components/Router";
|
||||||
import { GlobalContextProvider } from "./GlobalContext";
|
import { AppStateContextProvider } from "./contexts/AppStateContext";
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
return (
|
return (
|
||||||
<Layout style={{ height: "100%" }}>
|
<Layout style={{ height: "100%" }}>
|
||||||
<GlobalContextProvider>
|
<AppStateContextProvider>
|
||||||
<MyRouter />
|
<MyRouter />
|
||||||
</GlobalContextProvider>
|
</AppStateContextProvider>
|
||||||
</Layout>
|
</Layout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
import React, { useMemo, createContext, useContext, useState } from "react";
|
|
||||||
import axios from "axios";
|
|
||||||
import { isEmpty, isArray } from "lodash";
|
|
||||||
|
|
||||||
const globalContext = {
|
|
||||||
error: {},
|
|
||||||
loading: true,
|
|
||||||
user: {
|
|
||||||
ID: undefined,
|
|
||||||
roles: [],
|
|
||||||
email: undefined,
|
|
||||||
token: undefined,
|
|
||||||
},
|
|
||||||
locale: undefined,
|
|
||||||
invoicedItems: [],
|
|
||||||
notifications: [],
|
|
||||||
};
|
|
||||||
const GlobalContext = createContext(globalContext);
|
|
||||||
const useGlobals = () => useContext(GlobalContext);
|
|
||||||
const AVAILABLE_LOCALES = ["en", "fr", "de"];
|
|
||||||
|
|
||||||
const isValidUser = (user) => {
|
|
||||||
return (
|
|
||||||
!isEmpty(user) &&
|
|
||||||
user.ID &&
|
|
||||||
user.roles &&
|
|
||||||
user.email &&
|
|
||||||
user.token &&
|
|
||||||
isArray(user.roles)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const resetAxiosParams = () => {
|
|
||||||
delete axios.defaults.headers.common["Authorization"];
|
|
||||||
delete axios.defaults.userEntity;
|
|
||||||
axios.defaults.tracksEntity = "Tracks";
|
|
||||||
};
|
|
||||||
|
|
||||||
const setAxiosParams = (user) => {
|
|
||||||
axios.defaults.headers.common["Authorization"] = `Basic ${user.token}`;
|
|
||||||
axios.defaults.userID = user.ID;
|
|
||||||
if (user.roles.includes("customer")) {
|
|
||||||
axios.defaults.userEntity = `Customers/${user.ID}`;
|
|
||||||
axios.defaults.tracksEntity = "MarkedTracks";
|
|
||||||
} else {
|
|
||||||
axios.defaults.userEntity = `Employees/${user.ID}`;
|
|
||||||
axios.defaults.tracksEntity = "Tracks";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const useUserData = () => {
|
|
||||||
const getUserDataFromLS = () => {
|
|
||||||
let userFromLS;
|
|
||||||
try {
|
|
||||||
userFromLS = JSON.parse(localStorage.getItem("user"));
|
|
||||||
} catch (e) {}
|
|
||||||
if (isValidUser(userFromLS)) {
|
|
||||||
setAxiosParams(userFromLS);
|
|
||||||
return userFromLS;
|
|
||||||
} else {
|
|
||||||
localStorage.removeItem("user");
|
|
||||||
resetAxiosParams();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const setUserDataToLS = (value) => {
|
|
||||||
if (isValidUser(value)) {
|
|
||||||
localStorage.setItem("user", JSON.stringify(value));
|
|
||||||
setAxiosParams(value);
|
|
||||||
} else {
|
|
||||||
localStorage.removeItem("user");
|
|
||||||
resetAxiosParams();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const setLocaleToLS = (value) => {
|
|
||||||
localStorage.setItem("locale", value);
|
|
||||||
axios.defaults.headers.common["Accept-language"] = value;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getLocaleFromLS = () => {
|
|
||||||
const localeFromLS = localStorage.getItem("locale");
|
|
||||||
const selectedLocale =
|
|
||||||
localeFromLS &&
|
|
||||||
localeFromLS !== "undefined" &&
|
|
||||||
AVAILABLE_LOCALES.includes(localeFromLS)
|
|
||||||
? localeFromLS
|
|
||||||
: "en";
|
|
||||||
axios.defaults.headers.common["Accept-language"] = selectedLocale;
|
|
||||||
|
|
||||||
return selectedLocale;
|
|
||||||
};
|
|
||||||
|
|
||||||
return { getUserDataFromLS, setUserDataToLS, setLocaleToLS, getLocaleFromLS };
|
|
||||||
};
|
|
||||||
|
|
||||||
const GlobalContextProvider = ({ children }) => {
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [error, setError] = useState({});
|
|
||||||
const [invoicedItems, setInvoicedItems] = useState([]);
|
|
||||||
const [user, setUser] = useState(null);
|
|
||||||
const [locale, setLocale] = useState(undefined);
|
|
||||||
const {
|
|
||||||
getUserDataFromLS,
|
|
||||||
setUserDataToLS,
|
|
||||||
getLocaleFromLS,
|
|
||||||
setLocaleToLS,
|
|
||||||
} = useUserData();
|
|
||||||
|
|
||||||
const value = useMemo(
|
|
||||||
() => ({
|
|
||||||
error: error,
|
|
||||||
loading: loading,
|
|
||||||
invoicedItems: invoicedItems,
|
|
||||||
user: user ? user : getUserDataFromLS(),
|
|
||||||
locale: locale ? locale : getLocaleFromLS(),
|
|
||||||
setLoading,
|
|
||||||
setError,
|
|
||||||
setInvoicedItems,
|
|
||||||
setUser: (userParam) => {
|
|
||||||
setUserDataToLS(userParam);
|
|
||||||
setUser(userParam);
|
|
||||||
},
|
|
||||||
setLocale: (localeParam) => {
|
|
||||||
setLocaleToLS(localeParam);
|
|
||||||
setLocale(localeParam);
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[locale, user, loading, error, invoicedItems]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<GlobalContext.Provider value={value}>{children}</GlobalContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export { GlobalContextProvider, useGlobals };
|
|
||||||
21
media-store/app/src/api/axiosInstance.js
Normal file
21
media-store/app/src/api/axiosInstance.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import { getUserFromLS, getLocaleFromLS } from "../util/localStorageService";
|
||||||
|
import {
|
||||||
|
changeUserDefaults,
|
||||||
|
changeLocaleDefaults,
|
||||||
|
} from "./changeAxiosDefaults";
|
||||||
|
import { API } from "../util/constants";
|
||||||
|
import { responseErrorInterceptor } from "./responseErrorInterceptor";
|
||||||
|
|
||||||
|
const axiosInstance = axios.create({
|
||||||
|
baseURL: API,
|
||||||
|
timeout: 1000,
|
||||||
|
});
|
||||||
|
const user = getUserFromLS();
|
||||||
|
const locale = getLocaleFromLS();
|
||||||
|
changeUserDefaults(user);
|
||||||
|
changeLocaleDefaults(locale);
|
||||||
|
|
||||||
|
axiosInstance.interceptors.response.use(null, responseErrorInterceptor);
|
||||||
|
|
||||||
|
export { axiosInstance, changeLocaleDefaults, changeUserDefaults };
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
import { isEmpty } from "lodash";
|
import { isEmpty } from "lodash";
|
||||||
import axios from "axios";
|
import { axiosInstance } from "./axiosInstance";
|
||||||
|
|
||||||
// in dev mode using provided api
|
const BROWSE_TRACKS_SERVICE = "browse-tracks";
|
||||||
// in prod mode using proxy
|
const INVOICES_SERVICE = "browse-invoices";
|
||||||
const API =
|
const USER_SERVICE = "users";
|
||||||
process.env.NODE_ENV === "development" ? "http://localhost:4004/" : "api/";
|
const MANAGE_STORE = "manage-store";
|
||||||
|
|
||||||
const BROWSE_TRACKS_SERVICE = `${API}browse-tracks`;
|
|
||||||
const INVOICES_SERVICE = `${API}browse-invoices`;
|
|
||||||
const USER_SERVICE = `${API}users`;
|
|
||||||
const MANAGE_STORE = `${API}manage-store`;
|
|
||||||
|
|
||||||
const constructGenresQuery = (genreIds) => {
|
const constructGenresQuery = (genreIds) => {
|
||||||
return !isEmpty(genreIds)
|
return !isEmpty(genreIds)
|
||||||
@@ -29,26 +24,31 @@ const fetchTacks = ({
|
|||||||
}`;
|
}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
return axios.get(`${BROWSE_TRACKS_SERVICE}/${axios.defaults.tracksEntity}`, {
|
return axiosInstance.get(
|
||||||
params: {},
|
`${BROWSE_TRACKS_SERVICE}/${axiosInstance.defaults.tracksEntity}`,
|
||||||
paramsSerializer: () => serializeTracksUrl(),
|
{
|
||||||
});
|
params: {},
|
||||||
|
paramsSerializer: () => serializeTracksUrl(),
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const countTracks = ({ genreIds = [], substr = "" } = {}) => {
|
const countTracks = ({ genreIds = [], substr = "" } = {}) => {
|
||||||
return axios.get(
|
const tracksEntity = axiosInstance.defaults.tracksEntity;
|
||||||
`${BROWSE_TRACKS_SERVICE}/${axios.defaults.tracksEntity}/$count?$filter=${
|
|
||||||
|
return axiosInstance.get(
|
||||||
|
`${BROWSE_TRACKS_SERVICE}/${tracksEntity}/$count?$filter=${
|
||||||
`contains(name,'${substr}')` + constructGenresQuery(genreIds)
|
`contains(name,'${substr}')` + constructGenresQuery(genreIds)
|
||||||
}`
|
}`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchGenres = () => {
|
const fetchGenres = () => {
|
||||||
return axios.get(`${BROWSE_TRACKS_SERVICE}/Genres`);
|
return axiosInstance.get(`${BROWSE_TRACKS_SERVICE}/Genres`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const invoice = (tracks) => {
|
const invoice = (tracks) => {
|
||||||
return axios.post(
|
return axiosInstance.post(
|
||||||
`${INVOICES_SERVICE}/invoice`,
|
`${INVOICES_SERVICE}/invoice`,
|
||||||
{
|
{
|
||||||
tracks: tracks.map(({ unitPrice, ID }) => ({
|
tracks: tracks.map(({ unitPrice, ID }) => ({
|
||||||
@@ -63,12 +63,14 @@ const invoice = (tracks) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchPerson = () => {
|
const fetchPerson = () => {
|
||||||
return axios.get(`${USER_SERVICE}/${axios.defaults.userEntity}`);
|
return axiosInstance.get(
|
||||||
|
`${USER_SERVICE}/${axiosInstance.defaults.userEntity}`
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const confirmPerson = (person) => {
|
const confirmPerson = (person) => {
|
||||||
return axios.put(
|
return axiosInstance.put(
|
||||||
`${USER_SERVICE}/${axios.defaults.userEntity}`,
|
`${USER_SERVICE}/${axiosInstance.defaults.userEntity}`,
|
||||||
{
|
{
|
||||||
...person,
|
...person,
|
||||||
},
|
},
|
||||||
@@ -79,13 +81,13 @@ const confirmPerson = (person) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchInvoices = () => {
|
const fetchInvoices = () => {
|
||||||
return axios.get(
|
return axiosInstance.get(
|
||||||
`${INVOICES_SERVICE}/Invoices?$expand=invoiceItems($expand=track($expand=album($expand=artist)))`
|
`${INVOICES_SERVICE}/Invoices?$expand=invoiceItems($expand=track($expand=album($expand=artist)))`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancelInvoice = (ID) => {
|
const cancelInvoice = (ID) => {
|
||||||
return axios.post(
|
return axiosInstance.post(
|
||||||
`${INVOICES_SERVICE}/cancelInvoice`,
|
`${INVOICES_SERVICE}/cancelInvoice`,
|
||||||
{
|
{
|
||||||
ID,
|
ID,
|
||||||
@@ -97,61 +99,71 @@ const cancelInvoice = (ID) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchAlbumsByName = (substr = "", top) => {
|
const fetchAlbumsByName = (substr = "", top) => {
|
||||||
return axios.get(
|
return axiosInstance.get(
|
||||||
`${BROWSE_TRACKS_SERVICE}/Albums?$filter=${`contains(title,'${substr}')&$top=${top}`}`
|
`${BROWSE_TRACKS_SERVICE}/Albums?$filter=${`contains(title,'${substr}')&$top=${top}`}`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const addTrack = (data) => {
|
const addTrack = (data) => {
|
||||||
return axios.post(`${MANAGE_STORE}/Tracks`, data, {
|
return axiosInstance.post(`${MANAGE_STORE}/Tracks`, data, {
|
||||||
headers: { "content-type": "application/json" },
|
headers: { "content-type": "application/json;IEEE754Compatible=true" },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const addArtist = (data) => {
|
const addArtist = (data) => {
|
||||||
return axios.post(`${MANAGE_STORE}/Artists`, data, {
|
return axiosInstance.post(`${MANAGE_STORE}/Artists`, data, {
|
||||||
headers: { "content-type": "application/json" },
|
headers: { "content-type": "application/json" },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const addAlbum = (data) => {
|
const addAlbum = (data) => {
|
||||||
return axios.post(`${MANAGE_STORE}/Albums`, data, {
|
return axiosInstance.post(`${MANAGE_STORE}/Albums`, data, {
|
||||||
headers: { "content-type": "application/json" },
|
headers: { "content-type": "application/json" },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchArtistsByName = (substr = "", top) => {
|
const fetchArtistsByName = (substr = "", top) => {
|
||||||
return axios.get(
|
return axiosInstance.get(
|
||||||
`${MANAGE_STORE}/Artists?$filter=${`contains(name,'${substr}')&$top=${top}`}`
|
`${MANAGE_STORE}/Artists?$filter=${`contains(name,'${substr}')&$top=${top}`}`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const login = (data) => {
|
const login = (data) => {
|
||||||
return axios.post(`${USER_SERVICE}/login`, data, {
|
return axiosInstance.post(`${USER_SERVICE}/login`, data, {
|
||||||
headers: { "content-type": "application/json" },
|
headers: { "content-type": "application/json" },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateTrack = (track) => {
|
const updateTrack = (track) => {
|
||||||
return axios.put(
|
return axiosInstance.put(
|
||||||
`${MANAGE_STORE}/Tracks/${track.ID}`,
|
`${MANAGE_STORE}/Tracks/${track.ID}`,
|
||||||
{
|
{
|
||||||
...track,
|
...track,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: { "content-type": "application/json" },
|
headers: { "content-type": "application/json;IEEE754Compatible=true" },
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTrack = (ID) => {
|
const getTrack = (ID) => {
|
||||||
return axios.get(
|
return axiosInstance.get(
|
||||||
`${BROWSE_TRACKS_SERVICE}/${axios.defaults.tracksEntity}/${ID}?$expand=genre,album($expand=artist)`
|
`${BROWSE_TRACKS_SERVICE}/${axiosInstance.defaults.tracksEntity}/${ID}?$expand=genre,album($expand=artist)`
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const deleteTrack = (ID) => {
|
const deleteTrack = (ID) => {
|
||||||
return axios.delete(`${MANAGE_STORE}/Tracks(${ID})`);
|
return axiosInstance.delete(`${MANAGE_STORE}/Tracks(${ID})`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const refreshTokens = (refreshToken) => {
|
||||||
|
return axiosInstance.post(
|
||||||
|
`${USER_SERVICE}/refreshTokens`,
|
||||||
|
{ refreshToken },
|
||||||
|
{
|
||||||
|
headers: { "content-type": "application/json" },
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
@@ -172,4 +184,5 @@ export {
|
|||||||
updateTrack,
|
updateTrack,
|
||||||
getTrack,
|
getTrack,
|
||||||
deleteTrack,
|
deleteTrack,
|
||||||
|
refreshTokens,
|
||||||
};
|
};
|
||||||
27
media-store/app/src/api/changeAxiosDefaults.js
Normal file
27
media-store/app/src/api/changeAxiosDefaults.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { axiosInstance } from "./axiosInstance";
|
||||||
|
|
||||||
|
function changeUserDefaults(currentUser) {
|
||||||
|
if (currentUser) {
|
||||||
|
axiosInstance.defaults.headers.common[
|
||||||
|
"Authorization"
|
||||||
|
] = `Basic ${currentUser.accessToken}`;
|
||||||
|
axiosInstance.defaults.userID = currentUser.ID;
|
||||||
|
if (currentUser.roles.includes("customer")) {
|
||||||
|
axiosInstance.defaults.userEntity = `Customers/${currentUser.ID}`;
|
||||||
|
axiosInstance.defaults.tracksEntity = "MarkedTracks";
|
||||||
|
} else {
|
||||||
|
axiosInstance.defaults.userEntity = `Employees/${currentUser.ID}`;
|
||||||
|
axiosInstance.defaults.tracksEntity = "Tracks";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
axiosInstance.defaults.tracksEntity = "Tracks";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeLocaleDefaults(locale) {
|
||||||
|
if (locale) {
|
||||||
|
axiosInstance.defaults.headers.common["Accept-language"] = locale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { changeLocaleDefaults, changeUserDefaults };
|
||||||
64
media-store/app/src/api/responseErrorInterceptor.js
Normal file
64
media-store/app/src/api/responseErrorInterceptor.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { emitter } from "../util/EventEmitter";
|
||||||
|
import { axiosInstance } from "./axiosInstance";
|
||||||
|
import { refreshTokens } from "./calls";
|
||||||
|
import { getUserFromLS } from "../util/localStorageService";
|
||||||
|
|
||||||
|
let isRefreshing = false;
|
||||||
|
let subscribers = [];
|
||||||
|
|
||||||
|
function responseErrorInterceptor(error) {
|
||||||
|
const originalRequest = error.config;
|
||||||
|
|
||||||
|
if (error.response && error.response.status === 401) {
|
||||||
|
if (originalRequest.url === "users/login") {
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if users/refreshTokens request failed
|
||||||
|
if (isRefreshing && originalRequest.url === "users/refreshTokens") {
|
||||||
|
subscribers.forEach((request) => request.reject(error));
|
||||||
|
subscribers = [];
|
||||||
|
isRefreshing = false;
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if got a 401 error we sending users/refreshTokens request
|
||||||
|
if (!isRefreshing) {
|
||||||
|
isRefreshing = true;
|
||||||
|
|
||||||
|
refreshTokens(getUserFromLS().refreshToken)
|
||||||
|
.then((response) => {
|
||||||
|
emitter.emit("UPDATE_USER", response.data);
|
||||||
|
subscribers.forEach((request) =>
|
||||||
|
request.resolve(response.data.accessToken)
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
subscribers.forEach((request) => request.reject(error));
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
subscribers = [];
|
||||||
|
isRefreshing = false;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// holding requests which should be sended after users/refreshTokens complete
|
||||||
|
// otherwise if users/refreshTokens failed an error will be thrown
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
subscribers.push({
|
||||||
|
resolve: (newAccessToken) => {
|
||||||
|
originalRequest.headers.Authorization = "Basic " + newAccessToken;
|
||||||
|
resolve(axiosInstance(originalRequest));
|
||||||
|
},
|
||||||
|
reject: (err) => {
|
||||||
|
reject(err);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { responseErrorInterceptor };
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Breadcrumb, Spin } from "antd";
|
import { Breadcrumb, Spin } from "antd";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import { useGlobals } from "./GlobalContext";
|
import { useAppState } from "../hooks/useAppState";
|
||||||
|
|
||||||
const names = {
|
const names = {
|
||||||
"/": "Browse / Tracks",
|
"/": "Browse / Tracks",
|
||||||
@@ -13,7 +13,7 @@ const names = {
|
|||||||
|
|
||||||
const CurrentPageHeader = () => {
|
const CurrentPageHeader = () => {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { loading } = useGlobals();
|
const { loading } = useAppState();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Breadcrumb
|
<Breadcrumb
|
||||||
@@ -39,7 +39,6 @@ const Editable = ({ value, onChange, type }) => {
|
|||||||
fontWeight: 600,
|
fontWeight: 600,
|
||||||
outline: "none",
|
outline: "none",
|
||||||
border: "none",
|
border: "none",
|
||||||
borderRadius: 6,
|
|
||||||
backgroundColor: "white",
|
backgroundColor: "white",
|
||||||
padding: "0 2px",
|
padding: "0 2px",
|
||||||
}}
|
}}
|
||||||
@@ -7,7 +7,10 @@ import {
|
|||||||
LoginOutlined,
|
LoginOutlined,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import { useHistory, useLocation } from "react-router-dom";
|
import { useHistory, useLocation } from "react-router-dom";
|
||||||
import { useGlobals } from "./GlobalContext";
|
import { useAppState } from "../hooks/useAppState";
|
||||||
|
import { setLocaleToLS } from "../util/localStorageService";
|
||||||
|
import { changeLocaleDefaults } from "../api/axiosInstance";
|
||||||
|
import { emitter } from "../util/EventEmitter";
|
||||||
import "./Header.css";
|
import "./Header.css";
|
||||||
|
|
||||||
const { SubMenu } = Menu;
|
const { SubMenu } = Menu;
|
||||||
@@ -19,12 +22,14 @@ const RELOAD_LOCATION_NUMBER = 0;
|
|||||||
const Header = () => {
|
const Header = () => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const { user, invoicedItems, setUser, locale, setLocale } = useGlobals();
|
const { user, invoicedItems, locale, setLocale } = useAppState();
|
||||||
const currentKey = [keys.find((key) => key === location.pathname)];
|
const currentKey = [keys.find((key) => key === location.pathname)];
|
||||||
const haveInvoicedItems = !isEmpty(invoicedItems);
|
const haveInvoicedItems = !isEmpty(invoicedItems);
|
||||||
const invoicedItemsLength = invoicedItems.length;
|
const invoicedItemsLength = invoicedItems.length;
|
||||||
|
|
||||||
const onChangeLocale = (value) => {
|
const onChangeLocale = (value) => {
|
||||||
|
setLocaleToLS(value);
|
||||||
|
changeLocaleDefaults(value);
|
||||||
setLocale(value);
|
setLocale(value);
|
||||||
history.go(RELOAD_LOCATION_NUMBER);
|
history.go(RELOAD_LOCATION_NUMBER);
|
||||||
};
|
};
|
||||||
@@ -39,6 +44,12 @@ const Header = () => {
|
|||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
));
|
));
|
||||||
|
|
||||||
|
const onUserLogout = () => {
|
||||||
|
emitter.emit("UPDATE_USER", undefined);
|
||||||
|
|
||||||
|
history.push("/");
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -107,10 +118,7 @@ const Header = () => {
|
|||||||
|
|
||||||
{!!user ? (
|
{!!user ? (
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
onClick={() => {
|
onClick={onUserLogout}
|
||||||
setUser(undefined);
|
|
||||||
history.push("/");
|
|
||||||
}}
|
|
||||||
danger
|
danger
|
||||||
icon={<LogoutOutlined style={{ fontSize: 16 }} />}
|
icon={<LogoutOutlined style={{ fontSize: 16 }} />}
|
||||||
></Menu.Item>
|
></Menu.Item>
|
||||||
@@ -6,16 +6,19 @@ import {
|
|||||||
Redirect,
|
Redirect,
|
||||||
} from "react-router-dom";
|
} from "react-router-dom";
|
||||||
import { isEmpty } from "lodash";
|
import { isEmpty } from "lodash";
|
||||||
import { TracksContainer } from "./pages/tracks/TracksPage";
|
import { TracksContainer } from "../pages/tracks/TracksPage";
|
||||||
import { CurrentPageHeader } from "./CurrentPageHeader";
|
import { CurrentPageHeader } from "./CurrentPageHeader";
|
||||||
import { Header } from "./Header";
|
import { Header } from "../components/Header";
|
||||||
import { PersonPage } from "./pages/person/PersonPage";
|
import { PersonPage } from "../pages/person/PersonPage";
|
||||||
import { ErrorPage } from "./pages/ErrorPage";
|
import { ErrorPage } from "../pages/ErrorPage";
|
||||||
import { Login } from "./pages/login/Login";
|
import { Login } from "../pages/login/Login";
|
||||||
import { withRestrictions, withRestrictedSection } from "./withRestrictions";
|
import {
|
||||||
import { InvoicePage } from "./pages/invoice/InvoicePage";
|
withRestrictions,
|
||||||
import { ManageStore } from "./pages/manage-store/ManageStore";
|
withRestrictedSection,
|
||||||
import { MyInvoices } from "./pages/person/MyInvoices";
|
} from "../hocs/withRestrictions";
|
||||||
|
import { InvoicePage } from "../pages/invoice/InvoicePage";
|
||||||
|
import { ManageStore } from "../pages/manage-store/ManageStore";
|
||||||
|
import { MyInvoices } from "../pages/person/MyInvoices";
|
||||||
|
|
||||||
const needCustomer = ({ user }) => !!user && user.roles.includes("customer");
|
const needCustomer = ({ user }) => !!user && user.roles.includes("customer");
|
||||||
|
|
||||||
72
media-store/app/src/contexts/AppStateContext.js
Normal file
72
media-store/app/src/contexts/AppStateContext.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import React, { useMemo, createContext, useState, useEffect } from "react";
|
||||||
|
import {
|
||||||
|
getUserFromLS,
|
||||||
|
getLocaleFromLS,
|
||||||
|
setUserToLS,
|
||||||
|
} from "../util/localStorageService";
|
||||||
|
import { changeUserDefaults } from "../api/axiosInstance";
|
||||||
|
import { emitter } from "../util/EventEmitter";
|
||||||
|
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
|
const globalContext = {
|
||||||
|
error: {},
|
||||||
|
loading: true,
|
||||||
|
user: {
|
||||||
|
ID: undefined,
|
||||||
|
roles: [],
|
||||||
|
email: undefined,
|
||||||
|
accessToken: undefined,
|
||||||
|
refreshToken: undefined,
|
||||||
|
},
|
||||||
|
locale: undefined,
|
||||||
|
invoicedItems: [],
|
||||||
|
notifications: [],
|
||||||
|
};
|
||||||
|
const AppStateContext = createContext(globalContext);
|
||||||
|
|
||||||
|
const AppStateContextProvider = ({ children }) => {
|
||||||
|
const [invoicedItems, setInvoicedItems] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState({});
|
||||||
|
const [user, setUser] = useState(getUserFromLS());
|
||||||
|
const [locale, setLocale] = useState(getLocaleFromLS());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const updateUser = (newUser) => {
|
||||||
|
console.log("USER_UPDATE WAS TRIGGERED", counter++);
|
||||||
|
changeUserDefaults(newUser);
|
||||||
|
setUserToLS(newUser);
|
||||||
|
setUser(newUser);
|
||||||
|
};
|
||||||
|
emitter.on("UPDATE_USER", updateUser);
|
||||||
|
console.log("listener was registered");
|
||||||
|
return () => {
|
||||||
|
emitter.removeListener("UPDATE_USER", updateUser);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const value = useMemo(
|
||||||
|
() => ({
|
||||||
|
error: error,
|
||||||
|
loading: loading,
|
||||||
|
invoicedItems: invoicedItems,
|
||||||
|
user: user,
|
||||||
|
locale: locale,
|
||||||
|
setLoading,
|
||||||
|
setError,
|
||||||
|
setInvoicedItems,
|
||||||
|
setUser: setUser,
|
||||||
|
setLocale: setLocale,
|
||||||
|
}),
|
||||||
|
[locale, user, loading, error, invoicedItems]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AppStateContext.Provider value={value}>
|
||||||
|
{children}
|
||||||
|
</AppStateContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { AppStateContextProvider, AppStateContext };
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Redirect } from "react-router-dom";
|
import { Redirect } from "react-router-dom";
|
||||||
import { useGlobals } from "./GlobalContext";
|
import { useAppState } from "../hooks/useAppState";
|
||||||
|
|
||||||
const withRestrictions = (Component, isUserMeetRestrictions) => {
|
const withRestrictions = (Component, isUserMeetRestrictions) => {
|
||||||
return (props) => {
|
return (props) => {
|
||||||
const { user, invoicedItems } = useGlobals();
|
const { user, invoicedItems } = useAppState();
|
||||||
return isUserMeetRestrictions({ user, invoicedItems }) ? (
|
return isUserMeetRestrictions({ user, invoicedItems }) ? (
|
||||||
<Component {...props} />
|
<Component {...props} />
|
||||||
) : (
|
) : (
|
||||||
@@ -15,7 +15,7 @@ const withRestrictions = (Component, isUserMeetRestrictions) => {
|
|||||||
|
|
||||||
const withRestrictedSection = (Component, isUserMeetRestrictions) => {
|
const withRestrictedSection = (Component, isUserMeetRestrictions) => {
|
||||||
return (props) => {
|
return (props) => {
|
||||||
const { user, invoicedItems } = useGlobals();
|
const { user, invoicedItems } = useAppState();
|
||||||
return (
|
return (
|
||||||
isUserMeetRestrictions({ user, invoicedItems }) && (
|
isUserMeetRestrictions({ user, invoicedItems }) && (
|
||||||
<Component {...props} />
|
<Component {...props} />
|
||||||
22
media-store/app/src/hooks/useAbortableEffect.js
Normal file
22
media-store/app/src/hooks/useAbortableEffect.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
function useAbortableEffect(effect, dependencies) {
|
||||||
|
const status = {}; // mutable status object
|
||||||
|
useEffect(() => {
|
||||||
|
status.aborted = false;
|
||||||
|
// pass the mutable object to the effect callback
|
||||||
|
// store the returned value for cleanup
|
||||||
|
const cleanUpFn = effect(status);
|
||||||
|
return () => {
|
||||||
|
// mutate the object to signal the consumer
|
||||||
|
// this effect is cleaning up
|
||||||
|
status.aborted = true;
|
||||||
|
if (typeof cleanUpFn === "function") {
|
||||||
|
// run the cleanup function
|
||||||
|
cleanUpFn();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [...dependencies]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { useAbortableEffect };
|
||||||
6
media-store/app/src/hooks/useAppState.js
Normal file
6
media-store/app/src/hooks/useAppState.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { useContext } from "react";
|
||||||
|
import { AppStateContext } from "../contexts/AppStateContext";
|
||||||
|
|
||||||
|
const useAppState = () => useContext(AppStateContext);
|
||||||
|
|
||||||
|
export { useAppState };
|
||||||
42
media-store/app/src/hooks/useErrors.js
Normal file
42
media-store/app/src/hooks/useErrors.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { useHistory } from "react-router-dom";
|
||||||
|
import { useAppState } from "./useAppState";
|
||||||
|
import { emitter } from "../util/EventEmitter";
|
||||||
|
import { message } from "antd";
|
||||||
|
import { MESSAGE_TIMEOUT } from "../util/constants";
|
||||||
|
|
||||||
|
const useErrors = () => {
|
||||||
|
const history = useHistory();
|
||||||
|
const { setError } = useAppState();
|
||||||
|
|
||||||
|
const handleError = (error) => {
|
||||||
|
console.error("Error", error);
|
||||||
|
|
||||||
|
if (error.response) {
|
||||||
|
if (error.response.status === 401) {
|
||||||
|
emitter.emit("UPDATE_USER", undefined);
|
||||||
|
message.error("You are unauthorized, try login again", MESSAGE_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { status, statusText, data } = error.response;
|
||||||
|
setError({
|
||||||
|
status,
|
||||||
|
statusText,
|
||||||
|
message: data.error ? data.error.message : data,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setError({
|
||||||
|
status: "",
|
||||||
|
statusText: "Error",
|
||||||
|
message: "Something went wrong",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
history.push("/error");
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
handleError,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export { useErrors };
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
@import "~antd/dist/antd.css";
|
|
||||||
|
|
||||||
html {
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
#root {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
section.ant-layout {
|
|
||||||
height: 100vh;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Layout
|
|
||||||
*/
|
|
||||||
.site-layout .site-layout-background {
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import "./index.css";
|
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
import * as serviceWorker from "./serviceWorker";
|
import * as serviceWorker from "./serviceWorker";
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
import { isEmpty } from "lodash";
|
import { isEmpty } from "lodash";
|
||||||
import { Result, Button } from "antd";
|
import { Result, Button } from "antd";
|
||||||
import { useGlobals } from "../GlobalContext";
|
import { useAppState } from "../hooks/useAppState";
|
||||||
|
|
||||||
const ErrorPage = () => {
|
const ErrorPage = () => {
|
||||||
const { error, setError } = useGlobals();
|
const { error, setError } = useAppState();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
const onGoHome = () => {
|
useEffect(() => {
|
||||||
setError({});
|
setError({});
|
||||||
|
history.replace("/");
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onGoHome = () => {
|
||||||
history.push("/");
|
history.push("/");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Table, Button, message } from "antd";
|
import { Table, Button, message } from "antd";
|
||||||
import { useGlobals } from "../../GlobalContext";
|
import { useAppState } from "../../hooks/useAppState";
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
import { invoice } from "../../api-service";
|
import { invoice } from "../../api/calls";
|
||||||
import { useErrors } from "../../useErrors";
|
import { useErrors } from "../../hooks/useErrors";
|
||||||
|
import { MESSAGE_TIMEOUT } from "../../util/constants";
|
||||||
|
|
||||||
import "./InvoicePage.css";
|
import "./InvoicePage.css";
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
@@ -24,12 +26,11 @@ const columns = [
|
|||||||
dataIndex: "unitPrice",
|
dataIndex: "unitPrice",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const MESSAGE_TIMEOUT = 2;
|
|
||||||
|
|
||||||
const InvoicePage = () => {
|
const InvoicePage = () => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { handleError } = useErrors();
|
const { handleError } = useErrors();
|
||||||
const { invoicedItems, setInvoicedItems, setLoading } = useGlobals();
|
const { invoicedItems, setInvoicedItems, setLoading } = useAppState();
|
||||||
|
|
||||||
const data = invoicedItems.map(({ ID: key, ...otherProps }) => ({
|
const data = invoicedItems.map(({ ID: key, ...otherProps }) => ({
|
||||||
key,
|
key,
|
||||||
@@ -45,12 +46,12 @@ const InvoicePage = () => {
|
|||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setLoading(false);
|
|
||||||
setInvoicedItems([]);
|
setInvoicedItems([]);
|
||||||
message.success("Invoice successfully completed", MESSAGE_TIMEOUT);
|
message.success("Invoice successfully completed", MESSAGE_TIMEOUT);
|
||||||
history.push("/person");
|
history.push("/person");
|
||||||
})
|
})
|
||||||
.catch(handleError);
|
.catch(handleError)
|
||||||
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
const onCancel = () => {
|
const onCancel = () => {
|
||||||
setInvoicedItems([]);
|
setInvoicedItems([]);
|
||||||
@@ -58,7 +59,7 @@ const InvoicePage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ borderRadius: 6, backgroundColor: "white", padding: 10 }}>
|
<div style={{ backgroundColor: "white", padding: 10 }}>
|
||||||
<Table
|
<Table
|
||||||
bordered={false}
|
bordered={false}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
@@ -73,17 +74,12 @@ const InvoicePage = () => {
|
|||||||
padding: 5,
|
padding: 5,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
<Button type="primary" size="large" onClick={onBuy}>
|
||||||
type="primary"
|
|
||||||
size="large"
|
|
||||||
style={{ borderRadius: 6 }}
|
|
||||||
onClick={onBuy}
|
|
||||||
>
|
|
||||||
Buy
|
Buy
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
size="large"
|
size="large"
|
||||||
style={{ borderRadius: 6, marginLeft: 5 }}
|
style={{ marginLeft: 5 }}
|
||||||
onClick={onCancel}
|
onClick={onCancel}
|
||||||
danger
|
danger
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Form, Input, Button, Checkbox, message } from "antd";
|
import { Form, Input, Button, Checkbox, message } from "antd";
|
||||||
import { login } from "../../api-service";
|
import { login } from "../../api/calls";
|
||||||
import { useHistory } from "react-router-dom";
|
import { useHistory } from "react-router-dom";
|
||||||
import { useGlobals } from "../../GlobalContext";
|
import { useAppState } from "../../hooks/useAppState";
|
||||||
import { useErrors } from "../../useErrors";
|
import { useErrors } from "../../hooks/useErrors";
|
||||||
|
import { MESSAGE_TIMEOUT } from "../../util/constants";
|
||||||
|
import { emitter } from "../../util/EventEmitter";
|
||||||
|
|
||||||
const layout = {
|
const layout = {
|
||||||
labelCol: {
|
labelCol: {
|
||||||
@@ -19,12 +21,11 @@ const tailLayout = {
|
|||||||
span: 8,
|
span: 8,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const MESSAGE_TIMEOUT = 2;
|
|
||||||
|
|
||||||
const Login = () => {
|
const Login = () => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const { setLoading, setUser } = useGlobals();
|
const { setLoading } = useAppState();
|
||||||
const { handleError } = useErrors();
|
const { handleError } = useErrors();
|
||||||
|
|
||||||
const onFinish = (values) => {
|
const onFinish = (values) => {
|
||||||
@@ -32,25 +33,19 @@ const Login = () => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
login({ email: values.email, password: values.password })
|
login({ email: values.email, password: values.password })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const { ID, email, level, token, roles } = response.data;
|
emitter.emit("UPDATE_USER", response.data);
|
||||||
setUser({
|
|
||||||
ID,
|
|
||||||
roles,
|
|
||||||
email,
|
|
||||||
level,
|
|
||||||
token,
|
|
||||||
});
|
|
||||||
history.push("/");
|
history.push("/");
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error.response.status === 401) {
|
console.log(error);
|
||||||
|
if (error.response && error.response.status === 401) {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
message.error("Invalid credentials!", MESSAGE_TIMEOUT);
|
message.error("Invalid credentials!", MESSAGE_TIMEOUT);
|
||||||
} else {
|
} else {
|
||||||
handleError(error);
|
handleError(error);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(() => setLoading(false));
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFinishFailed = (errorInfo) => {
|
const onFinishFailed = (errorInfo) => {
|
||||||
@@ -78,7 +73,7 @@ const Login = () => {
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Input style={{ borderRadius: 6 }} />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@@ -91,7 +86,7 @@ const Login = () => {
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Input.Password style={{ borderRadius: 6 }} />
|
<Input.Password style={{}} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item {...tailLayout} name="remember" valuePropName="checked">
|
<Form.Item {...tailLayout} name="remember" valuePropName="checked">
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { Form, Input, Select } from "antd";
|
import { Form, Input, Select } from "antd";
|
||||||
import { useSearch } from "@umijs/hooks";
|
import { useSearch } from "@umijs/hooks";
|
||||||
import { useErrors } from "../../useErrors";
|
import { useErrors } from "../../hooks/useErrors";
|
||||||
import { fetchArtistsByName } from "../../api-service";
|
import { fetchArtistsByName } from "../../api/calls";
|
||||||
|
|
||||||
const REQUIRED = [
|
const REQUIRED = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
.ant-select.ant-select-single.ant-select-show-arrow.ant-select-show-search
|
|
||||||
> div,
|
|
||||||
.ant-form-item-control-input-content > input {
|
|
||||||
border-radius: 6px !important;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ import { Form, Radio, Button, message } from "antd";
|
|||||||
import { TrackForm } from "./TrackForm";
|
import { TrackForm } from "./TrackForm";
|
||||||
import { AddArtistForm } from "./AddArtistForm";
|
import { AddArtistForm } from "./AddArtistForm";
|
||||||
import { AddAlbumForm } from "./AddAlbumForm";
|
import { AddAlbumForm } from "./AddAlbumForm";
|
||||||
import { useErrors } from "../../useErrors";
|
import { useErrors } from "../../hooks/useErrors";
|
||||||
import { useGlobals } from "../../GlobalContext";
|
import { useAppState } from "../../hooks/useAppState";
|
||||||
import { addTrack, addArtist, addAlbum } from "../../api-service";
|
import { addTrack, addArtist, addAlbum } from "../../api/calls";
|
||||||
|
import { MESSAGE_TIMEOUT } from "../../util/constants";
|
||||||
import "./ManageStore.css";
|
import "./ManageStore.css";
|
||||||
|
|
||||||
const FORM_TYPES = {
|
const FORM_TYPES = {
|
||||||
@@ -14,8 +15,6 @@ const FORM_TYPES = {
|
|||||||
album: "album",
|
album: "album",
|
||||||
playlist: "",
|
playlist: "",
|
||||||
};
|
};
|
||||||
const DEFAULT_MEDIA_TYPE_ID = 1;
|
|
||||||
const MESSAGE_TIMEOUT = 2;
|
|
||||||
|
|
||||||
const chooseForm = (type) => {
|
const chooseForm = (type) => {
|
||||||
return (
|
return (
|
||||||
@@ -28,7 +27,7 @@ const chooseForm = (type) => {
|
|||||||
const ManageStore = () => {
|
const ManageStore = () => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const { handleError } = useErrors();
|
const { handleError } = useErrors();
|
||||||
const { setLoading } = useGlobals();
|
const { setLoading } = useAppState();
|
||||||
const [formType, setFormType] = useState("track");
|
const [formType, setFormType] = useState("track");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -53,8 +52,8 @@ const ManageStore = () => {
|
|||||||
name: data.name,
|
name: data.name,
|
||||||
composer: data.composer,
|
composer: data.composer,
|
||||||
album: { ID: data.albumID },
|
album: { ID: data.albumID },
|
||||||
mediaType: { ID: DEFAULT_MEDIA_TYPE_ID },
|
|
||||||
genre: { ID: data.genreID },
|
genre: { ID: data.genreID },
|
||||||
|
unitPrice: data.unitPrice.toString(),
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case FORM_TYPES.artist:
|
case FORM_TYPES.artist:
|
||||||
@@ -68,11 +67,11 @@ const ManageStore = () => {
|
|||||||
|
|
||||||
promise
|
promise
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setLoading(false);
|
|
||||||
message.success("Entity successfully created", MESSAGE_TIMEOUT);
|
message.success("Entity successfully created", MESSAGE_TIMEOUT);
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
})
|
})
|
||||||
.catch(handleError);
|
.catch(handleError)
|
||||||
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -95,13 +94,9 @@ const ManageStore = () => {
|
|||||||
>
|
>
|
||||||
<Form.Item label="Entity" name="type">
|
<Form.Item label="Entity" name="type">
|
||||||
<Radio.Group onChange={onChangeForm}>
|
<Radio.Group onChange={onChangeForm}>
|
||||||
<Radio.Button value="track" style={{ borderRadius: "6px 0 0 6px" }}>
|
<Radio.Button value="track">Track</Radio.Button>
|
||||||
Track
|
|
||||||
</Radio.Button>
|
|
||||||
<Radio.Button value="album">Album</Radio.Button>
|
<Radio.Button value="album">Album</Radio.Button>
|
||||||
<Radio.Button value="artist" style={{ borderRadius: "0 6px 6px 0" }}>
|
<Radio.Button value="artist">Artist</Radio.Button>
|
||||||
Artist
|
|
||||||
</Radio.Button>
|
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{formElement}
|
{formElement}
|
||||||
@@ -111,7 +106,6 @@ const ManageStore = () => {
|
|||||||
span: 14,
|
span: 14,
|
||||||
offset: 4,
|
offset: 4,
|
||||||
}}
|
}}
|
||||||
style={{ borderRadius: 6 }}
|
|
||||||
>
|
>
|
||||||
<Button onClick={() => form.submit()}>Create</Button>
|
<Button onClick={() => form.submit()}>Create</Button>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Form, Input, Select } from "antd";
|
import { Form, Input, Select, InputNumber } from "antd";
|
||||||
import { head } from "lodash";
|
import { head } from "lodash";
|
||||||
import { useSearch } from "@umijs/hooks";
|
import { useSearch } from "@umijs/hooks";
|
||||||
import { useGlobals } from "../../GlobalContext";
|
import { useAppState } from "../../hooks/useAppState";
|
||||||
import { fetchAlbumsByName, fetchGenres } from "../../api-service";
|
import { fetchAlbumsByName, fetchGenres } from "../../api/calls";
|
||||||
import { useErrors } from "../../useErrors";
|
import { useErrors } from "../../hooks/useErrors";
|
||||||
|
|
||||||
const ALBUMS_LIMIT = 10;
|
const ALBUMS_LIMIT = 10;
|
||||||
const REQUIRED = [
|
const REQUIRED = [
|
||||||
@@ -13,6 +13,10 @@ const REQUIRED = [
|
|||||||
message: "This filed is required!",
|
message: "This filed is required!",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
const PRICE_INPUT_RULE = {
|
||||||
|
pattern: /^(?:\d*\.\d\d)$/,
|
||||||
|
message: "Price should have precision 2 and dot separator!",
|
||||||
|
};
|
||||||
|
|
||||||
const getAlbums = function (value) {
|
const getAlbums = function (value) {
|
||||||
return fetchAlbumsByName(value, ALBUMS_LIMIT)
|
return fetchAlbumsByName(value, ALBUMS_LIMIT)
|
||||||
@@ -28,17 +32,15 @@ const TrackForm = ({ initialAlbumTitle }) => {
|
|||||||
onChange: onChangeAlbumInput,
|
onChange: onChangeAlbumInput,
|
||||||
cancel: onAlbumCancel,
|
cancel: onAlbumCancel,
|
||||||
} = useSearch(getAlbums.bind({ handleError }));
|
} = useSearch(getAlbums.bind({ handleError }));
|
||||||
const { setLoading } = useGlobals();
|
const { setLoading } = useAppState();
|
||||||
const [genres, setGenres] = useState([]);
|
const [genres, setGenres] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
Promise.all([fetchGenres(), onChangeAlbumInput(initialAlbumTitle)])
|
Promise.all([fetchGenres(), onChangeAlbumInput(initialAlbumTitle)])
|
||||||
.then((responses) => {
|
.then((responses) => setGenres(head(responses).data.value))
|
||||||
setGenres(head(responses).data.value);
|
.catch(handleError)
|
||||||
setLoading(false);
|
.finally(() => setLoading(false));
|
||||||
})
|
|
||||||
.catch(handleError);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -76,6 +78,18 @@ const TrackForm = ({ initialAlbumTitle }) => {
|
|||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label="Unit price"
|
||||||
|
name="unitPrice"
|
||||||
|
precision={2}
|
||||||
|
rules={REQUIRED}
|
||||||
|
>
|
||||||
|
<InputNumber
|
||||||
|
precision={2}
|
||||||
|
decimalSeparator="."
|
||||||
|
parser={(value) => value.replace(/\$\s?|(,*)/g, "")}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import React, { useState, useEffect, useMemo, useCallback } from "react";
|
import React, { useState, useEffect, useMemo, useCallback } from "react";
|
||||||
import { Button, message, Divider, Tag, Collapse, Table, Spin } from "antd";
|
import { Button, message, Divider, Tag, Collapse, Table, Spin } from "antd";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { useErrors } from "../../useErrors";
|
import { useErrors } from "../../hooks/useErrors";
|
||||||
import { useGlobals } from "../../GlobalContext";
|
import { useAppState } from "../../hooks/useAppState";
|
||||||
import { cancelInvoice, fetchInvoices } from "../../api-service";
|
import { cancelInvoice, fetchInvoices } from "../../api/calls";
|
||||||
|
import { MESSAGE_TIMEOUT } from "../../util/constants";
|
||||||
|
|
||||||
const { Panel } = Collapse;
|
const { Panel } = Collapse;
|
||||||
const MESSAGE_TIMEOUT = 2;
|
|
||||||
const INVOICE_STATUS = {
|
const INVOICE_STATUS = {
|
||||||
2: {
|
2: {
|
||||||
tagTitle: "Shipped",
|
tagTitle: "Shipped",
|
||||||
@@ -64,7 +64,7 @@ const chooseStatus = (utcNowTimestamp, invoiceDate, statusFromDb) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ExtraHeader = ({ ID, invoiceDate, status: initialStatus }) => {
|
const ExtraHeader = ({ ID, invoiceDate, status: initialStatus }) => {
|
||||||
const { loading, setLoading } = useGlobals();
|
const { loading, setLoading } = useAppState();
|
||||||
const { handleError } = useErrors();
|
const { handleError } = useErrors();
|
||||||
const [loadingHeaderId, setLoadingHeaderId] = useState();
|
const [loadingHeaderId, setLoadingHeaderId] = useState();
|
||||||
const [status, setStatus] = useState(initialStatus);
|
const [status, setStatus] = useState(initialStatus);
|
||||||
@@ -83,11 +83,11 @@ const ExtraHeader = ({ ID, invoiceDate, status: initialStatus }) => {
|
|||||||
cancelInvoice(ID)
|
cancelInvoice(ID)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
message.success("Invoice successfully cancelled", MESSAGE_TIMEOUT);
|
message.success("Invoice successfully cancelled", MESSAGE_TIMEOUT);
|
||||||
setLoading(false);
|
|
||||||
setLoadingHeaderId(undefined);
|
setLoadingHeaderId(undefined);
|
||||||
setStatus(CANCELLED_STATUS);
|
setStatus(CANCELLED_STATUS);
|
||||||
})
|
})
|
||||||
.catch(handleError);
|
.catch(handleError)
|
||||||
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -108,20 +108,15 @@ const ExtraHeader = ({ ID, invoiceDate, status: initialStatus }) => {
|
|||||||
|
|
||||||
const MyInvoices = () => {
|
const MyInvoices = () => {
|
||||||
const { handleError } = useErrors();
|
const { handleError } = useErrors();
|
||||||
const { setLoading } = useGlobals();
|
const { setLoading } = useAppState();
|
||||||
const [invoices, setInvoices] = useState([]);
|
const [invoices, setInvoices] = useState([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
fetchInvoices()
|
fetchInvoices()
|
||||||
.then((response) => {
|
.then(({ data: { value } }) => setInvoices(value))
|
||||||
const {
|
.catch(handleError)
|
||||||
data: { value },
|
.finally(() => setLoading(false));
|
||||||
} = response;
|
|
||||||
setInvoices(value);
|
|
||||||
setLoading(false);
|
|
||||||
})
|
|
||||||
.catch(handleError);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const genExtra = useCallback(
|
const genExtra = useCallback(
|
||||||
@@ -183,9 +178,7 @@ const MyInvoices = () => {
|
|||||||
{invoiceElements && (
|
{invoiceElements && (
|
||||||
<>
|
<>
|
||||||
<Divider orientation="left">My invoices</Divider>
|
<Divider orientation="left">My invoices</Divider>
|
||||||
<Collapse style={{ borderRadius: 6 }} expandIconPosition="left">
|
<Collapse expandIconPosition="left">{invoiceElements}</Collapse>
|
||||||
{invoiceElements}
|
|
||||||
</Collapse>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import React, { useState, useEffect, useMemo } from "react";
|
import React, { useState, useMemo } from "react";
|
||||||
import { Card, Button, message } from "antd";
|
import { Card, Button, message } from "antd";
|
||||||
import { omit } from "lodash";
|
import { omit } from "lodash";
|
||||||
import { fetchPerson, confirmPerson } from "../../api-service";
|
import { fetchPerson, confirmPerson } from "../../api/calls";
|
||||||
import { useErrors } from "../../useErrors";
|
import { useErrors } from "../../hooks/useErrors";
|
||||||
import { useGlobals } from "../../GlobalContext";
|
import { useAppState } from "../../hooks/useAppState";
|
||||||
import { Editable } from "../../Editable";
|
import { Editable } from "../../components/Editable";
|
||||||
|
import { MESSAGE_TIMEOUT } from "../../util/constants";
|
||||||
|
import { useAbortableEffect } from "../../hooks/useAbortableEffect";
|
||||||
|
|
||||||
const MESSAGE_TIMEOUT = 2;
|
|
||||||
const PERSON_PROP = {
|
const PERSON_PROP = {
|
||||||
address: "Address ",
|
address: "Address ",
|
||||||
city: "City ",
|
city: "City ",
|
||||||
@@ -22,7 +23,7 @@ const PERSON_PROP = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const PersonPage = ({ myInvoicesSection }) => {
|
const PersonPage = ({ myInvoicesSection }) => {
|
||||||
const { setLoading } = useGlobals();
|
const { setLoading } = useAppState();
|
||||||
const { handleError } = useErrors();
|
const { handleError } = useErrors();
|
||||||
const [initialPerson, setInitialPerson] = useState({});
|
const [initialPerson, setInitialPerson] = useState({});
|
||||||
const [person, setPerson] = useState({
|
const [person, setPerson] = useState({
|
||||||
@@ -39,30 +40,31 @@ const PersonPage = ({ myInvoicesSection }) => {
|
|||||||
company: "",
|
company: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useAbortableEffect((status) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
fetchPerson()
|
fetchPerson()
|
||||||
.then((response) => {
|
.then(({ data: personData }) => {
|
||||||
let { data: personData } = response;
|
|
||||||
personData = omit(personData, "@odata.context", "ID");
|
personData = omit(personData, "@odata.context", "ID");
|
||||||
console.log("personData", personData);
|
console.log("personData", personData);
|
||||||
setInitialPerson(personData);
|
if (!status.aborted) {
|
||||||
setPerson(personData);
|
setInitialPerson(personData);
|
||||||
setLoading(false);
|
setPerson(personData);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch(handleError);
|
.catch(handleError)
|
||||||
|
.finally(() => setLoading(false));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onConfirmChanges = () => {
|
const onConfirmChanges = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
confirmPerson(person)
|
confirmPerson(person)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setLoading(false);
|
|
||||||
setInitialPerson(person);
|
setInitialPerson(person);
|
||||||
message.success("Person successfully updated", MESSAGE_TIMEOUT);
|
message.success("Person successfully updated", MESSAGE_TIMEOUT);
|
||||||
})
|
})
|
||||||
.catch(handleError);
|
.catch(handleError)
|
||||||
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
const isPersonChanged = useMemo(() => {
|
const isPersonChanged = useMemo(() => {
|
||||||
const keysOne = Object.keys(initialPerson);
|
const keysOne = Object.keys(initialPerson);
|
||||||
@@ -100,10 +102,7 @@ const PersonPage = ({ myInvoicesSection }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card
|
<Card title={`${person.lastName} ${person.firstName}`}>
|
||||||
style={{ borderRadius: 6 }}
|
|
||||||
title={`${person.lastName} ${person.firstName}`}
|
|
||||||
>
|
|
||||||
{personProperties}
|
{personProperties}
|
||||||
<div>
|
<div>
|
||||||
Email: <span style={{ fontWeight: 600 }}>{person.email}</span>
|
Email: <span style={{ fontWeight: 600 }}>{person.email}</span>
|
||||||
@@ -111,7 +110,7 @@ const PersonPage = ({ myInvoicesSection }) => {
|
|||||||
{isPersonChanged && (
|
{isPersonChanged && (
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
style={{ margin: 10, borderRadius: 6 }}
|
style={{ margin: 10 }}
|
||||||
onClick={onConfirmChanges}
|
onClick={onConfirmChanges}
|
||||||
>
|
>
|
||||||
Confirm changes
|
Confirm changes
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Modal, message } from "antd";
|
import { Modal, message } from "antd";
|
||||||
import { DeleteOutlined } from "@ant-design/icons";
|
import { DeleteOutlined } from "@ant-design/icons";
|
||||||
import { deleteTrack } from "../../api-service";
|
import { deleteTrack } from "../../api/calls";
|
||||||
import { useErrors } from "../../useErrors";
|
import { useErrors } from "../../hooks/useErrors";
|
||||||
|
import { MESSAGE_TIMEOUT } from "../../util/constants";
|
||||||
const MESSAGE_TIMEOUT = 2;
|
|
||||||
|
|
||||||
const DeleteAction = ({ ID, onDeleteTrack }) => {
|
const DeleteAction = ({ ID, onDeleteTrack }) => {
|
||||||
const [modalVisible, setModalVisible] = useState(false);
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Button, Modal, Form, message } from "antd";
|
import { Button, Modal, Form, message } from "antd";
|
||||||
import { EditOutlined, LoadingOutlined } from "@ant-design/icons";
|
import { EditOutlined, LoadingOutlined } from "@ant-design/icons";
|
||||||
import { useErrors } from "../../useErrors";
|
import { useErrors } from "../../hooks/useErrors";
|
||||||
import { TrackForm } from "../manage-store/TrackForm";
|
import { TrackForm } from "../manage-store/TrackForm";
|
||||||
import { updateTrack, getTrack } from "../../api-service";
|
import { updateTrack, getTrack } from "../../api/calls";
|
||||||
|
import { MESSAGE_TIMEOUT } from "../../util/constants";
|
||||||
|
|
||||||
const MESSAGE_TIMEOUT = 2;
|
const EditAction = ({
|
||||||
|
ID,
|
||||||
const EditAction = ({ ID, name, composer, genre, album, afterTrackUpdate }) => {
|
name,
|
||||||
|
composer,
|
||||||
|
genre,
|
||||||
|
unitPrice,
|
||||||
|
album,
|
||||||
|
afterTrackUpdate,
|
||||||
|
}) => {
|
||||||
const [visible, setVisible] = React.useState(false);
|
const [visible, setVisible] = React.useState(false);
|
||||||
const [confirmLoading, setConfirmLoading] = React.useState(false);
|
const [confirmLoading, setConfirmLoading] = React.useState(false);
|
||||||
const [updateLoading, setUpdateLoading] = React.useState(false);
|
const [updateLoading, setUpdateLoading] = React.useState(false);
|
||||||
@@ -26,6 +33,7 @@ const EditAction = ({ ID, name, composer, genre, album, afterTrackUpdate }) => {
|
|||||||
composer: value.composer,
|
composer: value.composer,
|
||||||
album: { ID: value.albumID },
|
album: { ID: value.albumID },
|
||||||
genre: { ID: value.genreID },
|
genre: { ID: value.genreID },
|
||||||
|
unitPrice: value.unitPrice.toString(),
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
message.success("Track successfully updated!", MESSAGE_TIMEOUT);
|
message.success("Track successfully updated!", MESSAGE_TIMEOUT);
|
||||||
@@ -99,6 +107,7 @@ const EditAction = ({ ID, name, composer, genre, album, afterTrackUpdate }) => {
|
|||||||
composer: composer,
|
composer: composer,
|
||||||
genreID: genre.ID,
|
genreID: genre.ID,
|
||||||
albumID: album.ID,
|
albumID: album.ID,
|
||||||
|
unitPrice: unitPrice,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<TrackForm initialAlbumTitle={album.title} />
|
<TrackForm initialAlbumTitle={album.title} />
|
||||||
|
|||||||
@@ -1,16 +1,15 @@
|
|||||||
import React, { useState, useRef } from "react";
|
import React, { useState, useRef } from "react";
|
||||||
import { Card, Button } from "antd";
|
import { Card, Button } from "antd";
|
||||||
import { PlusOutlined, MinusOutlined } from "@ant-design/icons";
|
import { PlusOutlined, MinusOutlined } from "@ant-design/icons";
|
||||||
import { useGlobals } from "../../GlobalContext";
|
import { useAppState } from "../../hooks/useAppState";
|
||||||
import { withRestrictedSection } from "../../withRestrictions";
|
import { withRestrictedSection } from "../../hocs/withRestrictions";
|
||||||
import { EditAction } from "./EditAction";
|
import { EditAction } from "./EditAction";
|
||||||
import { DeleteAction } from "./DeleteAction";
|
import { DeleteAction } from "./DeleteAction";
|
||||||
import "./Track.css";
|
import "./Track.css";
|
||||||
|
|
||||||
const RestrictedButton = withRestrictedSection(
|
const RestrictedButton = withRestrictedSection(Button, ({ user }) => {
|
||||||
Button,
|
return !!user && user.roles.includes("customer");
|
||||||
({ user }) => !!user && user.roles.includes("customer")
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const RestrictedEditAction = withRestrictedSection(
|
const RestrictedEditAction = withRestrictedSection(
|
||||||
EditAction,
|
EditAction,
|
||||||
@@ -28,7 +27,7 @@ const Track = ({
|
|||||||
onDeleteTrack,
|
onDeleteTrack,
|
||||||
}) => {
|
}) => {
|
||||||
const trackElement = useRef();
|
const trackElement = useRef();
|
||||||
const { setInvoicedItems, invoicedItems } = useGlobals();
|
const { setInvoicedItems, invoicedItems } = useAppState();
|
||||||
const [isInvoiced, setIsInvoiced] = useState(isInvoicedProp);
|
const [isInvoiced, setIsInvoiced] = useState(isInvoicedProp);
|
||||||
const [track, setTrack] = useState(initialTrack);
|
const [track, setTrack] = useState(initialTrack);
|
||||||
|
|
||||||
@@ -70,10 +69,10 @@ const Track = ({
|
|||||||
composer={track.composer}
|
composer={track.composer}
|
||||||
album={track.album}
|
album={track.album}
|
||||||
genre={track.genre}
|
genre={track.genre}
|
||||||
|
unitPrice={track.unitPrice}
|
||||||
afterTrackUpdate={(value) => setTrack(value)}
|
afterTrackUpdate={(value) => setTrack(value)}
|
||||||
/>,
|
/>,
|
||||||
]}
|
]}
|
||||||
style={{ borderRadius: 6 }}
|
|
||||||
title={track.name}
|
title={track.name}
|
||||||
bordered={false}
|
bordered={false}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,15 +1,4 @@
|
|||||||
div.ant-select.ant-select-multiple.ant-select-show-search > div,
|
|
||||||
div.ant-select-dropdown.ant-select-dropdown-placement-bottomLeft {
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ant-select > div.ant-select-selector {
|
.ant-select > div.ant-select-selector {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
min-width: 300px;
|
min-width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ant-pagination-prev > .ant-pagination-item-link,
|
|
||||||
.ant-pagination-next > .ant-pagination-item-link,
|
|
||||||
.ant-pagination-item {
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { debounce } from "lodash";
|
import { debounce } from "lodash";
|
||||||
import { Input, Col, Row, Select, Pagination } from "antd";
|
import { Input, Col, Row, Select, Pagination } from "antd";
|
||||||
import { Track } from "./Track";
|
import { Track } from "./Track";
|
||||||
import "./TracksPage.css";
|
import "./TracksPage.css";
|
||||||
import { useGlobals } from "../../GlobalContext";
|
import { useAppState } from "../../hooks/useAppState";
|
||||||
import { useErrors } from "../../useErrors";
|
import { useErrors } from "../../hooks/useErrors";
|
||||||
import { fetchTacks, countTracks, fetchGenres } from "../../api-service";
|
import { fetchTacks, countTracks, fetchGenres } from "../../api/calls";
|
||||||
|
import { useAbortableEffect } from "../../hooks/useAbortableEffect";
|
||||||
|
|
||||||
|
let counter = 0;
|
||||||
|
|
||||||
const { Search } = Input;
|
const { Search } = Input;
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
@@ -24,7 +27,7 @@ const renderGenres = (genres) =>
|
|||||||
));
|
));
|
||||||
|
|
||||||
const TracksContainer = () => {
|
const TracksContainer = () => {
|
||||||
const { setLoading, invoicedItems } = useGlobals();
|
const { setLoading, invoicedItems } = useAppState();
|
||||||
const { handleError } = useErrors();
|
const { handleError } = useErrors();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
tracks: [],
|
tracks: [],
|
||||||
@@ -40,16 +43,17 @@ const TracksContainer = () => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useAbortableEffect((status) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
const countTracksReq = countTracks();
|
const countTracksReq = countTracks();
|
||||||
const getTracksRequest = fetchTacks();
|
const getTracksRequest = fetchTacks();
|
||||||
const getGenresReq = fetchGenres();
|
const getGenresReq = fetchGenres();
|
||||||
|
|
||||||
|
console.log("calling requests", counter++);
|
||||||
Promise.all([countTracksReq, getTracksRequest, getGenresReq])
|
Promise.all([countTracksReq, getTracksRequest, getGenresReq])
|
||||||
.then((responses) => {
|
.then(
|
||||||
const [
|
([
|
||||||
{ data: totalItems },
|
{ data: totalItems },
|
||||||
{
|
{
|
||||||
data: { value: tracks },
|
data: { value: tracks },
|
||||||
@@ -57,16 +61,19 @@ const TracksContainer = () => {
|
|||||||
{
|
{
|
||||||
data: { value: genres },
|
data: { value: genres },
|
||||||
},
|
},
|
||||||
] = responses;
|
]) => {
|
||||||
setState({
|
if (!status.aborted) {
|
||||||
...state,
|
setState({
|
||||||
tracks,
|
...state,
|
||||||
genres,
|
tracks,
|
||||||
pagination: { ...state.pagination, totalItems },
|
genres,
|
||||||
});
|
pagination: { ...state.pagination, totalItems },
|
||||||
setLoading(false);
|
});
|
||||||
})
|
}
|
||||||
.catch(handleError);
|
}
|
||||||
|
)
|
||||||
|
.catch(handleError)
|
||||||
|
.finally(() => setLoading(false));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onSearch = debounce(
|
const onSearch = debounce(
|
||||||
@@ -85,21 +92,15 @@ const TracksContainer = () => {
|
|||||||
genreIds: options.genreIds,
|
genreIds: options.genreIds,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
.then((responses) => {
|
.then(([{ data: { value: tracks } }, { data: totalItems }]) =>
|
||||||
const [
|
|
||||||
{
|
|
||||||
data: { value: tracks },
|
|
||||||
},
|
|
||||||
{ data: totalItems },
|
|
||||||
] = responses;
|
|
||||||
setState({
|
setState({
|
||||||
...state,
|
...state,
|
||||||
tracks,
|
tracks,
|
||||||
pagination: { ...state.pagination, totalItems },
|
pagination: { ...state.pagination, totalItems },
|
||||||
});
|
})
|
||||||
setLoading(false);
|
)
|
||||||
})
|
.catch(handleError)
|
||||||
.catch(handleError);
|
.finally(() => setLoading(false));
|
||||||
},
|
},
|
||||||
DEBOUNCE_TIMER,
|
DEBOUNCE_TIMER,
|
||||||
DEBOUNCE_OPTIONS
|
DEBOUNCE_OPTIONS
|
||||||
@@ -132,15 +133,15 @@ const TracksContainer = () => {
|
|||||||
$skip: (pageNumber - 1) * state.pagination.pageSize,
|
$skip: (pageNumber - 1) * state.pagination.pageSize,
|
||||||
};
|
};
|
||||||
fetchTacks(options)
|
fetchTacks(options)
|
||||||
.then((response) => {
|
.then((response) =>
|
||||||
setState({
|
setState({
|
||||||
...state,
|
...state,
|
||||||
tracks: response.data.value,
|
tracks: response.data.value,
|
||||||
pagination: { ...state.pagination, currentPage: pageNumber },
|
pagination: { ...state.pagination, currentPage: pageNumber },
|
||||||
});
|
})
|
||||||
setLoading(false);
|
)
|
||||||
})
|
.catch(handleError)
|
||||||
.catch(handleError);
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
const deleteTrack = (ID) => {
|
const deleteTrack = (ID) => {
|
||||||
setState({
|
setState({
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
const reducersFactory = (initialState, handlers) => {
|
|
||||||
return (state = initialState, action) => {
|
|
||||||
const handler = handlers[action.type];
|
|
||||||
|
|
||||||
if (handler) {
|
|
||||||
return handler(state, action);
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export { reducersFactory };
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import { useHistory } from "react-router-dom";
|
|
||||||
import { useGlobals } from "./GlobalContext";
|
|
||||||
import { message } from "antd";
|
|
||||||
|
|
||||||
const MESSAGE_TIMEOUT = 2;
|
|
||||||
|
|
||||||
const useErrors = () => {
|
|
||||||
const history = useHistory();
|
|
||||||
const { setError, setUser, setLoading } = useGlobals();
|
|
||||||
|
|
||||||
const handleError = (error) => {
|
|
||||||
console.error("Error", error);
|
|
||||||
|
|
||||||
console.log("error", error);
|
|
||||||
if (error.response) {
|
|
||||||
if (error.response.status === 401 || error.response.status === 403) {
|
|
||||||
setUser(undefined);
|
|
||||||
setLoading(false);
|
|
||||||
// message.error("You are unauthorized, try login again", MESSAGE_TIMEOUT);
|
|
||||||
// history.push("/login");
|
|
||||||
// return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setError({
|
|
||||||
status: error.response.status,
|
|
||||||
statusText: error.response.statusText,
|
|
||||||
message: error.response.data.error
|
|
||||||
? error.response.data.error.message
|
|
||||||
: error.response.data,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setError({
|
|
||||||
status: "",
|
|
||||||
statusText: "Network error",
|
|
||||||
message: "Please, check your connection",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
history.push("/error");
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
handleError,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export { useErrors };
|
|
||||||
5
media-store/app/src/util/EventEmitter.js
Normal file
5
media-store/app/src/util/EventEmitter.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import EventEmitter from "events";
|
||||||
|
|
||||||
|
const emitter = new EventEmitter();
|
||||||
|
|
||||||
|
export { emitter };
|
||||||
8
media-store/app/src/util/constants.js
Normal file
8
media-store/app/src/util/constants.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
export const AVAILABLE_LOCALES = ["en", "fr", "de"];
|
||||||
|
|
||||||
|
export const MESSAGE_TIMEOUT = 2;
|
||||||
|
|
||||||
|
// in dev mode using provided api
|
||||||
|
// in prod mode using proxy
|
||||||
|
export const API =
|
||||||
|
process.env.NODE_ENV === "development" ? "http://localhost:4004/" : "api/";
|
||||||
35
media-store/app/src/util/localStorageService.js
Normal file
35
media-store/app/src/util/localStorageService.js
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { isValidUser } from "./validateUser";
|
||||||
|
import { AVAILABLE_LOCALES } from "./constants";
|
||||||
|
|
||||||
|
const setUserToLS = (user) => {
|
||||||
|
if (user) {
|
||||||
|
localStorage.setItem("user", JSON.stringify(user));
|
||||||
|
} else {
|
||||||
|
localStorage.removeItem("user");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getUserFromLS = () => {
|
||||||
|
let userFromLS;
|
||||||
|
try {
|
||||||
|
userFromLS = JSON.parse(localStorage.getItem("user"));
|
||||||
|
if (isValidUser(userFromLS)) {
|
||||||
|
return userFromLS;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getLocaleFromLS = () => {
|
||||||
|
const localeFromLS = localStorage.getItem("locale");
|
||||||
|
return localeFromLS &&
|
||||||
|
localeFromLS !== "undefined" &&
|
||||||
|
AVAILABLE_LOCALES.includes(localeFromLS)
|
||||||
|
? localeFromLS
|
||||||
|
: "en";
|
||||||
|
};
|
||||||
|
|
||||||
|
const setLocaleToLS = (locale) => {
|
||||||
|
localStorage.setItem("locale", locale);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { setLocaleToLS, getLocaleFromLS, getUserFromLS, setUserToLS };
|
||||||
20
media-store/app/src/util/validateUser.js
Normal file
20
media-store/app/src/util/validateUser.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import { isArray, isEmpty, isString, isNumber } from "lodash";
|
||||||
|
|
||||||
|
const CUSTOMER_ROLE = "customer";
|
||||||
|
const EMPLOYEE_ROLE = "employee";
|
||||||
|
|
||||||
|
const isValidUser = (user) => {
|
||||||
|
return (
|
||||||
|
!isEmpty(user) &&
|
||||||
|
isNumber(user.ID) &&
|
||||||
|
isArray(user.roles) &&
|
||||||
|
!!user.roles.some(
|
||||||
|
(role) => role === CUSTOMER_ROLE || role === EMPLOYEE_ROLE
|
||||||
|
) &&
|
||||||
|
isString(user.email) &&
|
||||||
|
isString(user.accessToken) &&
|
||||||
|
isString(user.refreshToken)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { isValidUser };
|
||||||
@@ -1,60 +1,60 @@
|
|||||||
ID,lastName,firstName,city,state,address,country,postalCode,phone,fax,email,password,company,supportRep_ID
|
ID,lastName,firstName,city,address,country,phone,email,password,supportRep_ID
|
||||||
1,Gonçalves,Luís,São José dos Campos,SP,"Av. Brigadeiro Faria Lima, 2170",Brazil,12227-000,+55 (12) 3923-5555,+55 (12) 3923-5566,luisg@embraer.com.br,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Embraer - Empresa Brasileira de Aeronáutica S.A.,3
|
1,Gonçalves,Luís,São José dos Campos,"Av. Brigadeiro Faria Lima, 2170",Brazil,+55 (12) 3923-5555,luisg@embraer.com.br,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
2,Köhler,Leonie,Stuttgart,,Theodor-Heuss-Straße 34,Germany,70174,+49 0711 2842222,,leonekohler@surfeu.de,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
2,Köhler,Leonie,Stuttgart,Theodor-Heuss-Straße 34,Germany,+49 0711 2842222,leonekohler@surfeu.de,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
3,Tremblay,François,Montréal,QC,1498 rue Bélanger,Canada,H2G 1A7,+1 (514) 721-4711,,ftremblay@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
3,Tremblay,François,Montréal,1498 rue Bélanger,Canada,+1 (514) 721-4711,ftremblay@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
4,Hansen,Bjørn,Oslo,,Ullevålsveien 14,Norway,0171,+47 22 44 22 22,,bjorn.hansen@yahoo.no,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
4,Hansen,Bjørn,Oslo,Ullevålsveien 14,Norway,+47 22 44 22 22,bjorn.hansen@yahoo.no,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
5,Wichterlová,František,Prague,,Klanova 9/506,Czech Republic,14700,+420 2 4172 5555,+420 2 4172 5555,frantisekw@jetbrains.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,JetBrains s.r.o.,4
|
5,Wichterlová,František,Prague,Klanova 9/506,Czech Republic,+420 2 4172 5555,frantisekw@jetbrains.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
6,Holý,Helena,Prague,,Rilská 3174/6,Czech Republic,14300,+420 2 4177 0449,,hholy@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
6,Holý,Helena,Prague,Rilská 3174/6,Czech Republic,+420 2 4177 0449,hholy@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
7,Gruber,Astrid,Vienne,,"Rotenturmstraße 4, 1010 Innere Stadt",Austria,1010,+43 01 5134505,,astrid.gruber@apple.at,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
7,Gruber,Astrid,Vienne,"Rotenturmstraße 4, 1010 Innere Stadt",Austria,+43 01 5134505,astrid.gruber@apple.at,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
8,Peeters,Daan,Brussels,,Grétrystraat 63,Belgium,1000,+32 02 219 03 03,,daan_peeters@apple.be,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
8,Peeters,Daan,Brussels,Grétrystraat 63,Belgium,+32 02 219 03 03,daan_peeters@apple.be,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
9,Nielsen,Kara,Copenhagen,,Sønder Boulevard 51,Denmark,1720,+453 3331 9991,,kara.nielsen@jubii.dk,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
9,Nielsen,Kara,Copenhagen,Sønder Boulevard 51,Denmark,+453 3331 9991,kara.nielsen@jubii.dk,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
10,Martins,Eduardo,São Paulo,SP,"Rua Dr. Falcão Filho, 155",Brazil,01007-010,+55 (11) 3033-5446,+55 (11) 3033-4564,eduardo@woodstock.com.br,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Woodstock Discos,4
|
10,Martins,Eduardo,São Paulo,"Rua Dr. Falcão Filho, 155",Brazil,+55 (11) 3033-5446,eduardo@woodstock.com.br,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
11,Rocha,Alexandre,São Paulo,SP,"Av. Paulista, 2022",Brazil,01310-200,+55 (11) 3055-3278,+55 (11) 3055-8131,alero@uol.com.br,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Banco do Brasil S.A.,5
|
11,Rocha,Alexandre,São Paulo,"Av. Paulista, 2022",Brazil,+55 (11) 3055-3278,alero@uol.com.br,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
12,Almeida,Roberto,Rio de Janeiro,RJ,"Praça Pio X, 119",Brazil,20040-020,+55 (21) 2271-7000,+55 (21) 2271-7070,roberto.almeida@riotur.gov.br,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Riotur,3
|
12,Almeida,Roberto,Rio de Janeiro,"Praça Pio X, 119",Brazil,+55 (21) 2271-7000,roberto.almeida@riotur.gov.br,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
13,Ramos,Fernanda,Brasília,DF,Qe 7 Bloco G,Brazil,71020-677,+55 (61) 3363-5547,+55 (61) 3363-7855,fernadaramos4@uol.com.br,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
13,Ramos,Fernanda,Brasília,Qe 7 Bloco G,Brazil,+55 (61) 3363-5547,fernadaramos4@uol.com.br,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
14,Philips,Mark,Edmonton,AB,8210 111 ST NW,Canada,T6G 2C7,+1 (780) 434-4554,+1 (780) 434-5565,mphilips12@shaw.ca,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Telus,5
|
14,Philips,Mark,Edmonton,8210 111 ST NW,Canada,+1 (780) 434-4554,mphilips12@shaw.ca,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
15,Peterson,Jennifer,Vancouver,BC,700 W Pender Street,Canada,V6C 1G8,+1 (604) 688-2255,+1 (604) 688-8756,jenniferp@rogers.ca,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Rogers Canada,3
|
15,Peterson,Jennifer,Vancouver,700 W Pender Street,Canada,+1 (604) 688-2255,jenniferp@rogers.ca,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
16,Harris,Frank,Mountain View,CA,1600 Amphitheatre Parkway,USA,94043-1351,+1 (650) 253-0000,+1 (650) 253-0000,fharris@google.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Google Inc.,4
|
16,Harris,Frank,Mountain View,1600 Amphitheatre Parkway,USA,+1 (650) 253-0000,fharris@google.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
17,Smith,Jack,Redmond,WA,1 Microsoft Way,USA,98052-8300,+1 (425) 882-8080,+1 (425) 882-8081,jacksmith@microsoft.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Microsoft Corporation,5
|
17,Smith,Jack,Redmond,1 Microsoft Way,USA,+1 (425) 882-8080,jacksmith@microsoft.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
18,Brooks,Michelle,New York,NY,627 Broadway,USA,10012-2612,+1 (212) 221-3546,+1 (212) 221-4679,michelleb@aol.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
18,Brooks,Michelle,New York,627 Broadway,USA,+1 (212) 221-3546,michelleb@aol.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
19,Goyer,Tim,Cupertino,CA,1 Infinite Loop,USA,95014,+1 (408) 996-1010,+1 (408) 996-1011,tgoyer@apple.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Apple Inc.,3
|
19,Goyer,Tim,Cupertino,1 Infinite Loop,USA,+1 (408) 996-1010,tgoyer@apple.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
20,Miller,Dan,Mountain View,CA,541 Del Medio Avenue,USA,94040-111,+1 (650) 644-3358,,dmiller@comcast.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
20,Miller,Dan,Mountain View,541 Del Medio Avenue,USA,+1 (650) 644-3358,dmiller@comcast.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
21,Chase,Kathy,Reno,NV,801 W 4th Street,USA,89503,+1 (775) 223-7665,,kachase@hotmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
21,Chase,Kathy,Reno,801 W 4th Street,USA,+1 (775) 223-7665,kachase@hotmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
22,Leacock,Heather,Orlando,FL,120 S Orange Ave,USA,32801,+1 (407) 999-7788,,hleacock@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
22,Leacock,Heather,Orlando,120 S Orange Ave,USA,+1 (407) 999-7788,hleacock@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
23,Gordon,John,Boston,MA,69 Salem Street,USA,2113,+1 (617) 522-1333,,johngordon22@yahoo.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
23,Gordon,John,Boston,69 Salem Street,USA,+1 (617) 522-1333,johngordon22@yahoo.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
24,Ralston,Frank,Chicago,IL,162 E Superior Street,USA,60611,+1 (312) 332-3232,,fralston@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
24,Ralston,Frank,Chicago,162 E Superior Street,USA,+1 (312) 332-3232,fralston@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
25,Stevens,Victor,Madison,WI,319 N. Frances Street,USA,53703,+1 (608) 257-0597,,vstevens@yahoo.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
25,Stevens,Victor,Madison,319 N. Frances Street,USA,+1 (608) 257-0597,vstevens@yahoo.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
26,Cunningham,Richard,Fort Worth,TX,2211 W Berry Street,USA,76110,+1 (817) 924-7272,,ricunningham@hotmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
26,Cunningham,Richard,Fort Worth,2211 W Berry Street,USA,+1 (817) 924-7272,ricunningham@hotmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
27,Gray,Patrick,Tucson,AZ,1033 N Park Ave,USA,85719,+1 (520) 622-4200,,patrick.gray@aol.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
27,Gray,Patrick,Tucson,1033 N Park Ave,USA,+1 (520) 622-4200,patrick.gray@aol.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
28,Barnett,Julia,Salt Lake City,UT,302 S 700 E,USA,84102,+1 (801) 531-7272,,jubarnett@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
28,Barnett,Julia,Salt Lake City,302 S 700 E,USA,+1 (801) 531-7272,jubarnett@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
29,Brown,Robert,Toronto,ON,796 Dundas Street West,Canada,M6J 1V1,+1 (416) 363-8888,,robbrown@shaw.ca,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
29,Brown,Robert,Toronto,796 Dundas Street West,Canada,+1 (416) 363-8888,robbrown@shaw.ca,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
30,Francis,Edward,Ottawa,ON,230 Elgin Street,Canada,K2P 1L7,+1 (613) 234-3322,,edfrancis@yachoo.ca,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
30,Francis,Edward,Ottawa,230 Elgin Street,Canada,+1 (613) 234-3322,edfrancis@yachoo.ca,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
31,Silk,Martha,Halifax,NS,194A Chain Lake Drive,Canada,B3S 1C5,+1 (902) 450-0450,,marthasilk@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
31,Silk,Martha,Halifax,194A Chain Lake Drive,Canada,+1 (902) 450-0450,marthasilk@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
32,Mitchell,Aaron,Winnipeg,MB,696 Osborne Street,Canada,R3L 2B9,+1 (204) 452-6452,,aaronmitchell@yahoo.ca,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
32,Mitchell,Aaron,Winnipeg,696 Osborne Street,Canada,+1 (204) 452-6452,aaronmitchell@yahoo.ca,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
33,Sullivan,Ellie,Yellowknife,NT,5112 48 Street,Canada,X1A 1N6,+1 (867) 920-2233,,ellie.sullivan@shaw.ca,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
33,Sullivan,Ellie,Yellowknife,5112 48 Street,Canada,+1 (867) 920-2233,ellie.sullivan@shaw.ca,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
34,Fernandes,João,Lisbon,,Rua da Assunção 53,Portugal,,+351 (213) 466-111,,jfernandes@yahoo.pt,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
34,Fernandes,João,Lisbon,Rua da Assunção 53,Portugal,+351 (213) 466-111,jfernandes@yahoo.pt,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
35,Sampaio,Madalena,Porto,,"Rua dos Campeões Europeus de Viena, 4350",Portugal,,+351 (225) 022-448,,masampaio@sapo.pt,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
35,Sampaio,Madalena,Porto,"Rua dos Campeões Europeus de Viena, 4350",Portugal,+351 (225) 022-448,masampaio@sapo.pt,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
36,Schneider,Hannah,Berlin,,Tauentzienstraße 8,Germany,10789,+49 030 26550280,,hannah.schneider@yahoo.de,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
36,Schneider,Hannah,Berlin,Tauentzienstraße 8,Germany,+49 030 26550280,hannah.schneider@yahoo.de,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
37,Zimmermann,Fynn,Frankfurt,,Berger Straße 10,Germany,60316,+49 069 40598889,,fzimmermann@yahoo.de,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
37,Zimmermann,Fynn,Frankfurt,Berger Straße 10,Germany,+49 069 40598889,fzimmermann@yahoo.de,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
38,Schröder,Niklas,Berlin,,Barbarossastraße 19,Germany,10779,+49 030 2141444,,nschroder@surfeu.de,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
38,Schröder,Niklas,Berlin,Barbarossastraße 19,Germany,+49 030 2141444,nschroder@surfeu.de,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
39,Bernard,Camille,Paris,,"4, Rue Milton",France,75009,+33 01 49 70 65 65,,camille.bernard@yahoo.fr,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
39,Bernard,Camille,Paris,"4, Rue Milton",France,+33 01 49 70 65 65,camille.bernard@yahoo.fr,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
40,Lefebvre,Dominique,Paris,,"8, Rue Hanovre",France,75002,+33 01 47 42 71 71,,dominiquelefebvre@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
40,Lefebvre,Dominique,Paris,"8, Rue Hanovre",France,+33 01 47 42 71 71,dominiquelefebvre@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
41,Dubois,Marc,Lyon,,"11, Place Bellecour",France,69002,+33 04 78 30 30 30,,marc.dubois@hotmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
41,Dubois,Marc,Lyon,"11, Place Bellecour",France,+33 04 78 30 30 30,marc.dubois@hotmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
42,Girard,Wyatt,Bordeaux,,"9, Place Louis Barthou",France,33000,+33 05 56 96 96 96,,wyatt.girard@yahoo.fr,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
42,Girard,Wyatt,Bordeaux,"9, Place Louis Barthou",France,+33 05 56 96 96 96,wyatt.girard@yahoo.fr,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
43,Mercier,Isabelle,Dijon,,"68, Rue Jouvence",France,21000,+33 03 80 73 66 99,,isabelle_mercier@apple.fr,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
43,Mercier,Isabelle,Dijon,"68, Rue Jouvence",France,+33 03 80 73 66 99,isabelle_mercier@apple.fr,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
44,Hämäläinen,Terhi,Helsinki,,Porthaninkatu 9,Finland,00530,+358 09 870 2000,,terhi.hamalainen@apple.fi,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
44,Hämäläinen,Terhi,Helsinki,Porthaninkatu 9,Finland,+358 09 870 2000,terhi.hamalainen@apple.fi,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
45,Kovács,Ladislav,Budapest,,Erzsébet krt. 58.,Hungary,H-1073,,,ladislav_kovacs@apple.hu,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
45,Kovács,Ladislav,Budapest,Erzsébet krt. 58.,Hungary,,ladislav_kovacs@apple.hu,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
46,O'Reilly,Hugh,Dublin,Dublin,3 Chatham Street,Ireland,,+353 01 6792424,,hughoreilly@apple.ie,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
46,O'Reilly,Hugh,Dublin,3 Chatham Street,Ireland,+353 01 6792424,hughoreilly@apple.ie,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
47,Mancini,Lucas,Rome,RM,"Via Degli Scipioni, 43",Italy,00192,+39 06 39733434,,lucas.mancini@yahoo.it,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
47,Mancini,Lucas,Rome,"Via Degli Scipioni, 43",Italy,+39 06 39733434,lucas.mancini@yahoo.it,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
48,Van der Berg,Johannes,Amsterdam,VV,Lijnbaansgracht 120bg,Netherlands,1016,+31 020 6223130,,johavanderberg@yahoo.nl,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
48,Van der Berg,Johannes,Amsterdam,Lijnbaansgracht 120bg,Netherlands,+31 020 6223130,johavanderberg@yahoo.nl,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
49,Wójcik,Stanisław,Warsaw,,Ordynacka 10,Poland,00-358,+48 22 828 37 39,,stanisław.wójcik@wp.pl,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
49,Wójcik,Stanisław,Warsaw,Ordynacka 10,Poland,+48 22 828 37 39,stanisław.wójcik@wp.pl,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
50,Muñoz,Enrique,Madrid,,C/ San Bernardo 85,Spain,28015,+34 914 454 454,,enrique_munoz@yahoo.es,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
50,Muñoz,Enrique,Madrid,C/ San Bernardo 85,Spain,+34 914 454 454,enrique_munoz@yahoo.es,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
51,Johansson,Joakim,Stockholm,,Celsiusg. 9,Sweden,11230,+46 08-651 52 52,,joakim.johansson@yahoo.se,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
51,Johansson,Joakim,Stockholm,Celsiusg. 9,Sweden,+46 08-651 52 52,joakim.johansson@yahoo.se,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
52,Jones,Emma,London,,202 Hoxton Street,United Kingdom,N1 5LH,+44 020 7707 0707,,emma_jones@hotmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
52,Jones,Emma,London,202 Hoxton Street,United Kingdom,+44 020 7707 0707,emma_jones@hotmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
53,Hughes,Phil,London,,113 Lupus St,United Kingdom,SW1V 3EN,+44 020 7976 5722,,phil.hughes@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
53,Hughes,Phil,London,113 Lupus St,United Kingdom,+44 020 7976 5722,phil.hughes@gmail.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
54,Murray,Steve,Edinburgh ,,110 Raeburn Pl,United Kingdom,EH4 1HH,+44 0131 315 3300,,steve.murray@yahoo.uk,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
54,Murray,Steve,Edinburgh,110 Raeburn Pl,United Kingdom,+44 0131 315 3300,steve.murray@yahoo.uk,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
55,Taylor,Mark,Sidney,NSW,421 Bourke Street,Australia,2010,+61 (02) 9332 3633,,mark.taylor@yahoo.au,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
55,Taylor,Mark,Sidney,421 Bourke Street,Australia,+61 (02) 9332 3633,mark.taylor@yahoo.au,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
56,Gutiérrez,Diego,Buenos Aires,,307 Macacha Güemes,Argentina,1106,+54 (0)11 4311 4333,,diego.gutierrez@yahoo.ar,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,4
|
56,Gutiérrez,Diego,Buenos Aires,307 Macacha Güemes,Argentina,+54 (0)11 4311 4333,diego.gutierrez@yahoo.ar,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,4
|
||||||
57,Rojas,Luis,Santiago,,"Calle Lira, 198",Chile,,+56 (0)2 635 4444,,luisrojas@yahoo.cl,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,5
|
57,Rojas,Luis,Santiago,"Calle Lira, 198",Chile,+56 (0)2 635 4444,luisrojas@yahoo.cl,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,5
|
||||||
58,Pareek,Manoj,Delhi,,"12,Community Centre",India,110017,+91 0124 39883988,,manoj.pareek@rediff.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
58,Pareek,Manoj,Delhi,"12,Community Centre",India,+91 0124 39883988,manoj.pareek@rediff.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
59,Srivastava,Puja,Bangalore,,"3,Raj Bhavan Road",India,560001,+91 080 22289999,,puja_srivastava@yahoo.in,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,,3
|
59,Srivastava,Puja,Bangalore,"3,Raj Bhavan Road",India,+91 080 22289999,puja_srivastava@yahoo.in,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,3
|
||||||
|
|||||||
|
@@ -1,9 +1,9 @@
|
|||||||
ID,lastName,firstName,city,state,address,country,postalCode,phone,fax,email,password,title,birthDate,hireDate,reportsTo_ID
|
ID,lastName,firstName,city,address,country,phone,email,password,title,birthDate,hireDate,reportsTo_ID
|
||||||
1,Adams,Andrew,Edmonton,AB,11120 Jasper Ave NW,Canada,T5K 2N1,+1 (780) 428-9482,+1 (780) 428-3457,andrew@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,General Manager,1962-02-18 00:00:00,2002-08-14 00:00:00,
|
1,Adams,Andrew,Edmonton,11120 Jasper Ave NW,Canada,+1 (780) 428-9482,andrew@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,General Manager,1962-02-18 00:00:00,2002-08-14 00:00:00,
|
||||||
2,Edwards,Nancy,Calgary,AB,825 8 Ave SW,Canada,T2P 2T3,+1 (403) 262-3443,+1 (403) 262-3322,nancy@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Sales Manager,1958-12-08 00:00:00,2002-05-01 00:00:00,1
|
2,Edwards,Nancy,Calgary,825 8 Ave SW,Canada,+1 (403) 262-3443,nancy@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Sales Manager,1958-12-08 00:00:00,2002-05-01 00:00:00,1
|
||||||
3,Peacock,Jane,Calgary,AB,1111 6 Ave SW,Canada,T2P 5M5,+1 (403) 262-3443,+1 (403) 262-6712,jane@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Sales Support Agent,1973-08-29 00:00:00,2002-04-01 00:00:00,2
|
3,Peacock,Jane,Calgary,1111 6 Ave SW,Canada,+1 (403) 262-3443,jane@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Sales Support Agent,1973-08-29 00:00:00,2002-04-01 00:00:00,2
|
||||||
4,Park,Margaret,Calgary,AB,683 10 Street SW,Canada,T2P 5G3,+1 (403) 263-4423,+1 (403) 263-4289,margaret@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Sales Support Agent,1947-09-19 00:00:00,2003-05-03 00:00:00,2
|
4,Park,Margaret,Calgary,683 10 Street SW,Canada,+1 (403) 263-4423,margaret@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Sales Support Agent,1947-09-19 00:00:00,2003-05-03 00:00:00,2
|
||||||
5,Johnson,Steve,Calgary,AB,7727B 41 Ave,Canada,T3B 1Y7,1 (780) 836-9987,1 (780) 836-9543,steve@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Sales Support Agent,1965-03-03 00:00:00,2003-10-17 00:00:00,2
|
5,Johnson,Steve,Calgary,7727B 41 Ave,Canada,1 (780) 836-9987,steve@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,Sales Support Agent,1965-03-03 00:00:00,2003-10-17 00:00:00,2
|
||||||
6,Mitchell,Michael,Calgary,AB,5827 Bowness Road NW,Canada,T3B 0C5,+1 (403) 246-9887,+1 (403) 246-9899,michael@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,IT Manager,1973-07-01 00:00:00,2003-10-17 00:00:00,1
|
6,Mitchell,Michael,Calgary,5827 Bowness Road NW,Canada,+1 (403) 246-9887,michael@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,IT Manager,1973-07-01 00:00:00,2003-10-17 00:00:00,1
|
||||||
7,King,Robert,Lethbridge,AB,590 Columbia Boulevard West,Canada,T1K 5N8,+1 (403) 456-9986,+1 (403) 456-8485,robert@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,IT Staff,1970-05-29 00:00:00,2004-01-02 00:00:00,6
|
7,King,Robert,Lethbridge,590 Columbia Boulevard West,Canada,+1 (403) 456-9986,robert@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,IT Staff,1970-05-29 00:00:00,2004-01-02 00:00:00,6
|
||||||
8,Callahan,Laura,Lethbridge,AB,923 7 ST NW,Canada,T1H 1Y8,+1 (403) 467-3351,+1 (403) 467-8772,laura@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,IT Staff,1968-01-09 00:00:00,2004-03-04 00:00:00,6
|
8,Callahan,Laura,Lethbridge,923 7 ST NW,Canada,+1 (403) 467-3351,laura@chinookcorp.com,$2b$10$8f5ztDxjf/oz225jNdNB0uCtJSMeVwkchFayUrTS6xEcRVpoyIooC,IT Staff,1968-01-09 00:00:00,2004-03-04 00:00:00,6
|
||||||
|
|||||||
|
@@ -1,413 +1,413 @@
|
|||||||
ID,invoiceDate,billingAddress,billingCity,billingState,billingCountry,billingPostalCode,total,status,customer_ID
|
ID,invoiceDate,total,status,customer_ID
|
||||||
1,2009-01-01 00:00:00,Theodor-Heuss-Straße 34,Stuttgart,,Germany,70174,1.98,1,2
|
1,2009-01-01 00:00:00,1.98,1,2
|
||||||
2,2009-01-02 00:00:00,Ullevålsveien 14,Oslo,,Norway,0171,3.96,1,4
|
2,2009-01-02 00:00:00,3.96,1,4
|
||||||
3,2009-01-03 00:00:00,Grétrystraat 63,Brussels,,Belgium,1000,5.94,1,8
|
3,2009-01-03 00:00:00,5.94,1,8
|
||||||
4,2009-01-06 00:00:00,8210 111 ST NW,Edmonton,AB,Canada,T6G 2C7,8.91,1,14
|
4,2009-01-06 00:00:00,8.91,1,14
|
||||||
5,2009-01-11 00:00:00,69 Salem Street,Boston,MA,USA,2113,13.86,1,23
|
5,2009-01-11 00:00:00,13.86,1,23
|
||||||
6,2009-01-19 00:00:00,Berger Straße 10,Frankfurt,,Germany,60316,0.99,1,37
|
6,2009-01-19 00:00:00,0.99,1,37
|
||||||
7,2009-02-01 00:00:00,Barbarossastraße 19,Berlin,,Germany,10779,1.98,1,38
|
7,2009-02-01 00:00:00,1.98,1,38
|
||||||
8,2009-02-01 00:00:00,"8, Rue Hanovre",Paris,,France,75002,1.98,1,40
|
8,2009-02-01 00:00:00,1.98,1,40
|
||||||
9,2009-02-02 00:00:00,"9, Place Louis Barthou",Bordeaux,,France,33000,3.96,1,42
|
9,2009-02-02 00:00:00,3.96,1,42
|
||||||
10,2009-02-03 00:00:00,3 Chatham Street,Dublin,Dublin,Ireland,,5.94,1,46
|
10,2009-02-03 00:00:00,5.94,1,46
|
||||||
11,2009-02-06 00:00:00,202 Hoxton Street,London,,United Kingdom,N1 5LH,8.91,1,52
|
11,2009-02-06 00:00:00,8.91,1,52
|
||||||
12,2009-02-11 00:00:00,Theodor-Heuss-Straße 34,Stuttgart,,Germany,70174,13.86,1,2
|
12,2009-02-11 00:00:00,13.86,1,2
|
||||||
13,2009-02-19 00:00:00,1600 Amphitheatre Parkway,Mountain View,CA,USA,94043-1351,0.99,1,16
|
13,2009-02-19 00:00:00,0.99,1,16
|
||||||
14,2009-03-04 00:00:00,1 Microsoft Way,Redmond,WA,USA,98052-8300,1.98,1,17
|
14,2009-03-04 00:00:00,1.98,1,17
|
||||||
15,2009-03-04 00:00:00,1 Infinite Loop,Cupertino,CA,USA,95014,1.98,1,19
|
15,2009-03-04 00:00:00,1.98,1,19
|
||||||
16,2009-03-05 00:00:00,801 W 4th Street,Reno,NV,USA,89503,3.96,1,21
|
16,2009-03-05 00:00:00,3.96,1,21
|
||||||
17,2009-03-06 00:00:00,319 N. Frances Street,Madison,WI,USA,53703,5.94,1,25
|
17,2009-03-06 00:00:00,5.94,1,25
|
||||||
18,2009-03-09 00:00:00,194A Chain Lake Drive,Halifax,NS,Canada,B3S 1C5,8.91,1,31
|
18,2009-03-09 00:00:00,8.91,1,31
|
||||||
19,2009-03-14 00:00:00,"8, Rue Hanovre",Paris,,France,75002,13.86,1,40
|
19,2009-03-14 00:00:00,13.86,1,40
|
||||||
20,2009-03-22 00:00:00,110 Raeburn Pl,Edinburgh ,,United Kingdom,EH4 1HH,0.99,1,54
|
20,2009-03-22 00:00:00,0.99,1,54
|
||||||
21,2009-04-04 00:00:00,421 Bourke Street,Sidney,NSW,Australia,2010,1.98,1,55
|
21,2009-04-04 00:00:00,1.98,1,55
|
||||||
22,2009-04-04 00:00:00,"Calle Lira, 198",Santiago,,Chile,,1.98,1,57
|
22,2009-04-04 00:00:00,1.98,1,57
|
||||||
23,2009-04-05 00:00:00,"3,Raj Bhavan Road",Bangalore,,India,560001,3.96,1,59
|
23,2009-04-05 00:00:00,3.96,1,59
|
||||||
24,2009-04-06 00:00:00,Ullevålsveien 14,Oslo,,Norway,0171,5.94,1,4
|
24,2009-04-06 00:00:00,5.94,1,4
|
||||||
25,2009-04-09 00:00:00,"Rua Dr. Falcão Filho, 155",São Paulo,SP,Brazil,01007-010,8.91,1,10
|
25,2009-04-09 00:00:00,8.91,1,10
|
||||||
26,2009-04-14 00:00:00,1 Infinite Loop,Cupertino,CA,USA,95014,13.86,1,19
|
26,2009-04-14 00:00:00,13.86,1,19
|
||||||
27,2009-04-22 00:00:00,5112 48 Street,Yellowknife,NT,Canada,X1A 1N6,0.99,1,33
|
27,2009-04-22 00:00:00,0.99,1,33
|
||||||
28,2009-05-05 00:00:00,Rua da Assunção 53,Lisbon,,Portugal,,1.98,1,34
|
28,2009-05-05 00:00:00,1.98,1,34
|
||||||
29,2009-05-05 00:00:00,Tauentzienstraße 8,Berlin,,Germany,10789,1.98,1,36
|
29,2009-05-05 00:00:00,1.98,1,36
|
||||||
30,2009-05-06 00:00:00,Barbarossastraße 19,Berlin,,Germany,10779,3.96,1,38
|
30,2009-05-06 00:00:00,3.96,1,38
|
||||||
31,2009-05-07 00:00:00,"9, Place Louis Barthou",Bordeaux,,France,33000,5.94,1,42
|
31,2009-05-07 00:00:00,5.94,1,42
|
||||||
32,2009-05-10 00:00:00,Lijnbaansgracht 120bg,Amsterdam,VV,Netherlands,1016,8.91,1,48
|
32,2009-05-10 00:00:00,8.91,1,48
|
||||||
33,2009-05-15 00:00:00,"Calle Lira, 198",Santiago,,Chile,,13.86,1,57
|
33,2009-05-15 00:00:00,13.86,1,57
|
||||||
34,2009-05-23 00:00:00,"Praça Pio X, 119",Rio de Janeiro,RJ,Brazil,20040-020,0.99,1,12
|
34,2009-05-23 00:00:00,0.99,1,12
|
||||||
35,2009-06-05 00:00:00,Qe 7 Bloco G,Brasília,DF,Brazil,71020-677,1.98,1,13
|
35,2009-06-05 00:00:00,1.98,1,13
|
||||||
36,2009-06-05 00:00:00,700 W Pender Street,Vancouver,BC,Canada,V6C 1G8,1.98,1,15
|
36,2009-06-05 00:00:00,1.98,1,15
|
||||||
37,2009-06-06 00:00:00,1 Microsoft Way,Redmond,WA,USA,98052-8300,3.96,1,17
|
37,2009-06-06 00:00:00,3.96,1,17
|
||||||
38,2009-06-07 00:00:00,801 W 4th Street,Reno,NV,USA,89503,5.94,1,21
|
38,2009-06-07 00:00:00,5.94,1,21
|
||||||
39,2009-06-10 00:00:00,1033 N Park Ave,Tucson,AZ,USA,85719,8.91,1,27
|
39,2009-06-10 00:00:00,8.91,1,27
|
||||||
40,2009-06-15 00:00:00,Tauentzienstraße 8,Berlin,,Germany,10789,13.86,1,36
|
40,2009-06-15 00:00:00,13.86,1,36
|
||||||
41,2009-06-23 00:00:00,C/ San Bernardo 85,Madrid,,Spain,28015,0.99,1,50
|
41,2009-06-23 00:00:00,0.99,1,50
|
||||||
42,2009-07-06 00:00:00,Celsiusg. 9,Stockholm,,Sweden,11230,1.98,1,51
|
42,2009-07-06 00:00:00,1.98,1,51
|
||||||
43,2009-07-06 00:00:00,113 Lupus St,London,,United Kingdom,SW1V 3EN,1.98,1,53
|
43,2009-07-06 00:00:00,1.98,1,53
|
||||||
44,2009-07-07 00:00:00,421 Bourke Street,Sidney,NSW,Australia,2010,3.96,1,55
|
44,2009-07-07 00:00:00,3.96,1,55
|
||||||
45,2009-07-08 00:00:00,"3,Raj Bhavan Road",Bangalore,,India,560001,5.94,1,59
|
45,2009-07-08 00:00:00,5.94,1,59
|
||||||
46,2009-07-11 00:00:00,Rilská 3174/6,Prague,,Czech Republic,14300,8.91,1,6
|
46,2009-07-11 00:00:00,8.91,1,6
|
||||||
47,2009-07-16 00:00:00,700 W Pender Street,Vancouver,BC,Canada,V6C 1G8,13.86,1,15
|
47,2009-07-16 00:00:00,13.86,1,15
|
||||||
48,2009-07-24 00:00:00,796 Dundas Street West,Toronto,ON,Canada,M6J 1V1,0.99,1,29
|
48,2009-07-24 00:00:00,0.99,1,29
|
||||||
49,2009-08-06 00:00:00,230 Elgin Street,Ottawa,ON,Canada,K2P 1L7,1.98,1,30
|
49,2009-08-06 00:00:00,1.98,1,30
|
||||||
50,2009-08-06 00:00:00,696 Osborne Street,Winnipeg,MB,Canada,R3L 2B9,1.98,1,32
|
50,2009-08-06 00:00:00,1.98,1,32
|
||||||
51,2009-08-07 00:00:00,Rua da Assunção 53,Lisbon,,Portugal,,3.96,1,34
|
51,2009-08-07 00:00:00,3.96,1,34
|
||||||
52,2009-08-08 00:00:00,Barbarossastraße 19,Berlin,,Germany,10779,5.94,1,38
|
52,2009-08-08 00:00:00,5.94,1,38
|
||||||
53,2009-08-11 00:00:00,Porthaninkatu 9,Helsinki,,Finland,00530,8.91,1,44
|
53,2009-08-11 00:00:00,8.91,1,44
|
||||||
54,2009-08-16 00:00:00,113 Lupus St,London,,United Kingdom,SW1V 3EN,13.86,1,53
|
54,2009-08-16 00:00:00,13.86,1,53
|
||||||
55,2009-08-24 00:00:00,Grétrystraat 63,Brussels,,Belgium,1000,0.99,1,8
|
55,2009-08-24 00:00:00,0.99,1,8
|
||||||
56,2009-09-06 00:00:00,Sønder Boulevard 51,Copenhagen,,Denmark,1720,1.98,1,9
|
56,2009-09-06 00:00:00,1.98,1,9
|
||||||
57,2009-09-06 00:00:00,"Av. Paulista, 2022",São Paulo,SP,Brazil,01310-200,1.98,1,11
|
57,2009-09-06 00:00:00,1.98,1,11
|
||||||
58,2009-09-07 00:00:00,Qe 7 Bloco G,Brasília,DF,Brazil,71020-677,3.96,1,13
|
58,2009-09-07 00:00:00,3.96,1,13
|
||||||
59,2009-09-08 00:00:00,1 Microsoft Way,Redmond,WA,USA,98052-8300,5.94,1,17
|
59,2009-09-08 00:00:00,5.94,1,17
|
||||||
60,2009-09-11 00:00:00,69 Salem Street,Boston,MA,USA,2113,8.91,1,23
|
60,2009-09-11 00:00:00,8.91,1,23
|
||||||
61,2009-09-16 00:00:00,696 Osborne Street,Winnipeg,MB,Canada,R3L 2B9,13.86,1,32
|
61,2009-09-16 00:00:00,13.86,1,32
|
||||||
62,2009-09-24 00:00:00,3 Chatham Street,Dublin,Dublin,Ireland,,0.99,1,46
|
62,2009-09-24 00:00:00,0.99,1,46
|
||||||
63,2009-10-07 00:00:00,"Via Degli Scipioni, 43",Rome,RM,Italy,00192,1.98,1,47
|
63,2009-10-07 00:00:00,1.98,1,47
|
||||||
64,2009-10-07 00:00:00,Ordynacka 10,Warsaw,,Poland,00-358,1.98,1,49
|
64,2009-10-07 00:00:00,1.98,1,49
|
||||||
65,2009-10-08 00:00:00,Celsiusg. 9,Stockholm,,Sweden,11230,3.96,1,51
|
65,2009-10-08 00:00:00,3.96,1,51
|
||||||
66,2009-10-09 00:00:00,421 Bourke Street,Sidney,NSW,Australia,2010,5.94,1,55
|
66,2009-10-09 00:00:00,5.94,1,55
|
||||||
67,2009-10-12 00:00:00,Theodor-Heuss-Straße 34,Stuttgart,,Germany,70174,8.91,1,2
|
67,2009-10-12 00:00:00,8.91,1,2
|
||||||
68,2009-10-17 00:00:00,"Av. Paulista, 2022",São Paulo,SP,Brazil,01310-200,13.86,1,11
|
68,2009-10-17 00:00:00,13.86,1,11
|
||||||
69,2009-10-25 00:00:00,319 N. Frances Street,Madison,WI,USA,53703,0.99,1,25
|
69,2009-10-25 00:00:00,0.99,1,25
|
||||||
70,2009-11-07 00:00:00,2211 W Berry Street,Fort Worth,TX,USA,76110,1.98,1,26
|
70,2009-11-07 00:00:00,1.98,1,26
|
||||||
71,2009-11-07 00:00:00,302 S 700 E,Salt Lake City,UT,USA,84102,1.98,1,28
|
71,2009-11-07 00:00:00,1.98,1,28
|
||||||
72,2009-11-08 00:00:00,230 Elgin Street,Ottawa,ON,Canada,K2P 1L7,3.96,1,30
|
72,2009-11-08 00:00:00,3.96,1,30
|
||||||
73,2009-11-09 00:00:00,Rua da Assunção 53,Lisbon,,Portugal,,5.94,1,34
|
73,2009-11-09 00:00:00,5.94,1,34
|
||||||
74,2009-11-12 00:00:00,"8, Rue Hanovre",Paris,,France,75002,8.91,1,40
|
74,2009-11-12 00:00:00,8.91,1,40
|
||||||
75,2009-11-17 00:00:00,Ordynacka 10,Warsaw,,Poland,00-358,13.86,1,49
|
75,2009-11-17 00:00:00,13.86,1,49
|
||||||
76,2009-11-25 00:00:00,Ullevålsveien 14,Oslo,,Norway,0171,0.99,1,4
|
76,2009-11-25 00:00:00,0.99,1,4
|
||||||
77,2009-12-08 00:00:00,Klanova 9/506,Prague,,Czech Republic,14700,1.98,1,5
|
77,2009-12-08 00:00:00,1.98,1,5
|
||||||
78,2009-12-08 00:00:00,"Rotenturmstraße 4, 1010 Innere Stadt",Vienne,,Austria,1010,1.98,1,7
|
78,2009-12-08 00:00:00,1.98,1,7
|
||||||
79,2009-12-09 00:00:00,Sønder Boulevard 51,Copenhagen,,Denmark,1720,3.96,1,9
|
79,2009-12-09 00:00:00,3.96,1,9
|
||||||
80,2009-12-10 00:00:00,Qe 7 Bloco G,Brasília,DF,Brazil,71020-677,5.94,1,13
|
80,2009-12-10 00:00:00,5.94,1,13
|
||||||
81,2009-12-13 00:00:00,1 Infinite Loop,Cupertino,CA,USA,95014,8.91,1,19
|
81,2009-12-13 00:00:00,8.91,1,19
|
||||||
82,2009-12-18 00:00:00,302 S 700 E,Salt Lake City,UT,USA,84102,13.86,1,28
|
82,2009-12-18 00:00:00,13.86,1,28
|
||||||
83,2009-12-26 00:00:00,"9, Place Louis Barthou",Bordeaux,,France,33000,0.99,1,42
|
83,2009-12-26 00:00:00,0.99,1,42
|
||||||
84,2010-01-08 00:00:00,"68, Rue Jouvence",Dijon,,France,21000,1.98,1,43
|
84,2010-01-08 00:00:00,1.98,1,43
|
||||||
85,2010-01-08 00:00:00,Erzsébet krt. 58.,Budapest,,Hungary,H-1073,1.98,1,45
|
85,2010-01-08 00:00:00,1.98,1,45
|
||||||
86,2010-01-09 00:00:00,"Via Degli Scipioni, 43",Rome,RM,Italy,00192,3.96,1,47
|
86,2010-01-09 00:00:00,3.96,1,47
|
||||||
87,2010-01-10 00:00:00,Celsiusg. 9,Stockholm,,Sweden,11230,6.94,1,51
|
87,2010-01-10 00:00:00,6.94,1,51
|
||||||
88,2010-01-13 00:00:00,"Calle Lira, 198",Santiago,,Chile,,17.91,1,57
|
88,2010-01-13 00:00:00,17.91,1,57
|
||||||
89,2010-01-18 00:00:00,"Rotenturmstraße 4, 1010 Innere Stadt",Vienne,,Austria,1010,18.86,1,7
|
89,2010-01-18 00:00:00,18.86,1,7
|
||||||
90,2010-01-26 00:00:00,801 W 4th Street,Reno,NV,USA,89503,0.99,1,21
|
90,2010-01-26 00:00:00,0.99,1,21
|
||||||
91,2010-02-08 00:00:00,120 S Orange Ave,Orlando,FL,USA,32801,1.98,1,22
|
91,2010-02-08 00:00:00,1.98,1,22
|
||||||
92,2010-02-08 00:00:00,162 E Superior Street,Chicago,IL,USA,60611,1.98,1,24
|
92,2010-02-08 00:00:00,1.98,1,24
|
||||||
93,2010-02-09 00:00:00,2211 W Berry Street,Fort Worth,TX,USA,76110,3.96,1,26
|
93,2010-02-09 00:00:00,3.96,1,26
|
||||||
94,2010-02-10 00:00:00,230 Elgin Street,Ottawa,ON,Canada,K2P 1L7,5.94,1,30
|
94,2010-02-10 00:00:00,5.94,1,30
|
||||||
95,2010-02-13 00:00:00,Tauentzienstraße 8,Berlin,,Germany,10789,8.91,1,36
|
95,2010-02-13 00:00:00,8.91,1,36
|
||||||
96,2010-02-18 00:00:00,Erzsébet krt. 58.,Budapest,,Hungary,H-1073,21.86,1,45
|
96,2010-02-18 00:00:00,21.86,1,45
|
||||||
97,2010-02-26 00:00:00,"3,Raj Bhavan Road",Bangalore,,India,560001,1.99,1,59
|
97,2010-02-26 00:00:00,1.99,1,59
|
||||||
98,2010-03-11 00:00:00,"Av. Brigadeiro Faria Lima, 2170",São José dos Campos,SP,Brazil,12227-000,3.98,1,1
|
98,2010-03-11 00:00:00,3.98,1,1
|
||||||
99,2010-03-11 00:00:00,1498 rue Bélanger,Montréal,QC,Canada,H2G 1A7,3.98,1,3
|
99,2010-03-11 00:00:00,3.98,1,3
|
||||||
100,2010-03-12 00:00:00,Klanova 9/506,Prague,,Czech Republic,14700,3.96,1,5
|
100,2010-03-12 00:00:00,3.96,1,5
|
||||||
101,2010-03-13 00:00:00,Sønder Boulevard 51,Copenhagen,,Denmark,1720,5.94,1,9
|
101,2010-03-13 00:00:00,5.94,1,9
|
||||||
102,2010-03-16 00:00:00,700 W Pender Street,Vancouver,BC,Canada,V6C 1G8,9.91,1,15
|
102,2010-03-16 00:00:00,9.91,1,15
|
||||||
103,2010-03-21 00:00:00,162 E Superior Street,Chicago,IL,USA,60611,15.86,1,24
|
103,2010-03-21 00:00:00,15.86,1,24
|
||||||
104,2010-03-29 00:00:00,Barbarossastraße 19,Berlin,,Germany,10779,0.99,1,38
|
104,2010-03-29 00:00:00,0.99,1,38
|
||||||
105,2010-04-11 00:00:00,"4, Rue Milton",Paris,,France,75009,1.98,1,39
|
105,2010-04-11 00:00:00,1.98,1,39
|
||||||
106,2010-04-11 00:00:00,"11, Place Bellecour",Lyon,,France,69002,1.98,1,41
|
106,2010-04-11 00:00:00,1.98,1,41
|
||||||
107,2010-04-12 00:00:00,"68, Rue Jouvence",Dijon,,France,21000,3.96,1,43
|
107,2010-04-12 00:00:00,3.96,1,43
|
||||||
108,2010-04-13 00:00:00,"Via Degli Scipioni, 43",Rome,RM,Italy,00192,5.94,1,47
|
108,2010-04-13 00:00:00,5.94,1,47
|
||||||
109,2010-04-16 00:00:00,113 Lupus St,London,,United Kingdom,SW1V 3EN,8.91,1,53
|
109,2010-04-16 00:00:00,8.91,1,53
|
||||||
110,2010-04-21 00:00:00,1498 rue Bélanger,Montréal,QC,Canada,H2G 1A7,13.86,1,3
|
110,2010-04-21 00:00:00,13.86,1,3
|
||||||
111,2010-04-29 00:00:00,1 Microsoft Way,Redmond,WA,USA,98052-8300,0.99,1,17
|
111,2010-04-29 00:00:00,0.99,1,17
|
||||||
112,2010-05-12 00:00:00,627 Broadway,New York,NY,USA,10012-2612,1.98,1,18
|
112,2010-05-12 00:00:00,1.98,1,18
|
||||||
113,2010-05-12 00:00:00,541 Del Medio Avenue,Mountain View,CA,USA,94040-111,1.98,1,20
|
113,2010-05-12 00:00:00,1.98,1,20
|
||||||
114,2010-05-13 00:00:00,120 S Orange Ave,Orlando,FL,USA,32801,3.96,1,22
|
114,2010-05-13 00:00:00,3.96,1,22
|
||||||
115,2010-05-14 00:00:00,2211 W Berry Street,Fort Worth,TX,USA,76110,5.94,1,26
|
115,2010-05-14 00:00:00,5.94,1,26
|
||||||
116,2010-05-17 00:00:00,696 Osborne Street,Winnipeg,MB,Canada,R3L 2B9,8.91,1,32
|
116,2010-05-17 00:00:00,8.91,1,32
|
||||||
117,2010-05-22 00:00:00,"11, Place Bellecour",Lyon,,France,69002,13.86,1,41
|
117,2010-05-22 00:00:00,13.86,1,41
|
||||||
118,2010-05-30 00:00:00,421 Bourke Street,Sidney,NSW,Australia,2010,0.99,1,55
|
118,2010-05-30 00:00:00,0.99,1,55
|
||||||
119,2010-06-12 00:00:00,307 Macacha Güemes,Buenos Aires,,Argentina,1106,1.98,1,56
|
119,2010-06-12 00:00:00,1.98,1,56
|
||||||
120,2010-06-12 00:00:00,"12,Community Centre",Delhi,,India,110017,1.98,1,58
|
120,2010-06-12 00:00:00,1.98,1,58
|
||||||
121,2010-06-13 00:00:00,"Av. Brigadeiro Faria Lima, 2170",São José dos Campos,SP,Brazil,12227-000,3.96,1,1
|
121,2010-06-13 00:00:00,3.96,1,1
|
||||||
122,2010-06-14 00:00:00,Klanova 9/506,Prague,,Czech Republic,14700,5.94,1,5
|
122,2010-06-14 00:00:00,5.94,1,5
|
||||||
123,2010-06-17 00:00:00,"Av. Paulista, 2022",São Paulo,SP,Brazil,01310-200,8.91,1,11
|
123,2010-06-17 00:00:00,8.91,1,11
|
||||||
124,2010-06-22 00:00:00,541 Del Medio Avenue,Mountain View,CA,USA,94040-111,13.86,1,20
|
124,2010-06-22 00:00:00,13.86,1,20
|
||||||
125,2010-06-30 00:00:00,Rua da Assunção 53,Lisbon,,Portugal,,0.99,1,34
|
125,2010-06-30 00:00:00,0.99,1,34
|
||||||
126,2010-07-13 00:00:00,"Rua dos Campeões Europeus de Viena, 4350",Porto,,Portugal,,1.98,1,35
|
126,2010-07-13 00:00:00,1.98,1,35
|
||||||
127,2010-07-13 00:00:00,Berger Straße 10,Frankfurt,,Germany,60316,1.98,1,37
|
127,2010-07-13 00:00:00,1.98,1,37
|
||||||
128,2010-07-14 00:00:00,"4, Rue Milton",Paris,,France,75009,3.96,1,39
|
128,2010-07-14 00:00:00,3.96,1,39
|
||||||
129,2010-07-15 00:00:00,"68, Rue Jouvence",Dijon,,France,21000,5.94,1,43
|
129,2010-07-15 00:00:00,5.94,1,43
|
||||||
130,2010-07-18 00:00:00,Ordynacka 10,Warsaw,,Poland,00-358,8.91,1,49
|
130,2010-07-18 00:00:00,8.91,1,49
|
||||||
131,2010-07-23 00:00:00,"12,Community Centre",Delhi,,India,110017,13.86,1,58
|
131,2010-07-23 00:00:00,13.86,1,58
|
||||||
132,2010-07-31 00:00:00,Qe 7 Bloco G,Brasília,DF,Brazil,71020-677,0.99,1,13
|
132,2010-07-31 00:00:00,0.99,1,13
|
||||||
133,2010-08-13 00:00:00,8210 111 ST NW,Edmonton,AB,Canada,T6G 2C7,1.98,1,14
|
133,2010-08-13 00:00:00,1.98,1,14
|
||||||
134,2010-08-13 00:00:00,1600 Amphitheatre Parkway,Mountain View,CA,USA,94043-1351,1.98,1,16
|
134,2010-08-13 00:00:00,1.98,1,16
|
||||||
135,2010-08-14 00:00:00,627 Broadway,New York,NY,USA,10012-2612,3.96,1,18
|
135,2010-08-14 00:00:00,3.96,1,18
|
||||||
136,2010-08-15 00:00:00,120 S Orange Ave,Orlando,FL,USA,32801,5.94,1,22
|
136,2010-08-15 00:00:00,5.94,1,22
|
||||||
137,2010-08-18 00:00:00,302 S 700 E,Salt Lake City,UT,USA,84102,8.91,1,28
|
137,2010-08-18 00:00:00,8.91,1,28
|
||||||
138,2010-08-23 00:00:00,Berger Straße 10,Frankfurt,,Germany,60316,13.86,1,37
|
138,2010-08-23 00:00:00,13.86,1,37
|
||||||
139,2010-08-31 00:00:00,Celsiusg. 9,Stockholm,,Sweden,11230,0.99,1,51
|
139,2010-08-31 00:00:00,0.99,1,51
|
||||||
140,2010-09-13 00:00:00,202 Hoxton Street,London,,United Kingdom,N1 5LH,1.98,1,52
|
140,2010-09-13 00:00:00,1.98,1,52
|
||||||
141,2010-09-13 00:00:00,110 Raeburn Pl,Edinburgh ,,United Kingdom,EH4 1HH,1.98,1,54
|
141,2010-09-13 00:00:00,1.98,1,54
|
||||||
142,2010-09-14 00:00:00,307 Macacha Güemes,Buenos Aires,,Argentina,1106,3.96,1,56
|
142,2010-09-14 00:00:00,3.96,1,56
|
||||||
143,2010-09-15 00:00:00,"Av. Brigadeiro Faria Lima, 2170",São José dos Campos,SP,Brazil,12227-000,5.94,1,1
|
143,2010-09-15 00:00:00,5.94,1,1
|
||||||
144,2010-09-18 00:00:00,"Rotenturmstraße 4, 1010 Innere Stadt",Vienne,,Austria,1010,8.91,1,7
|
144,2010-09-18 00:00:00,8.91,1,7
|
||||||
145,2010-09-23 00:00:00,1600 Amphitheatre Parkway,Mountain View,CA,USA,94043-1351,13.86,1,16
|
145,2010-09-23 00:00:00,13.86,1,16
|
||||||
146,2010-10-01 00:00:00,230 Elgin Street,Ottawa,ON,Canada,K2P 1L7,0.99,1,30
|
146,2010-10-01 00:00:00,0.99,1,30
|
||||||
147,2010-10-14 00:00:00,194A Chain Lake Drive,Halifax,NS,Canada,B3S 1C5,1.98,1,31
|
147,2010-10-14 00:00:00,1.98,1,31
|
||||||
148,2010-10-14 00:00:00,5112 48 Street,Yellowknife,NT,Canada,X1A 1N6,1.98,1,33
|
148,2010-10-14 00:00:00,1.98,1,33
|
||||||
149,2010-10-15 00:00:00,"Rua dos Campeões Europeus de Viena, 4350",Porto,,Portugal,,3.96,1,35
|
149,2010-10-15 00:00:00,3.96,1,35
|
||||||
150,2010-10-16 00:00:00,"4, Rue Milton",Paris,,France,75009,5.94,1,39
|
150,2010-10-16 00:00:00,5.94,1,39
|
||||||
151,2010-10-19 00:00:00,Erzsébet krt. 58.,Budapest,,Hungary,H-1073,8.91,1,45
|
151,2010-10-19 00:00:00,8.91,1,45
|
||||||
152,2010-10-24 00:00:00,110 Raeburn Pl,Edinburgh ,,United Kingdom,EH4 1HH,13.86,1,54
|
152,2010-10-24 00:00:00,13.86,1,54
|
||||||
153,2010-11-01 00:00:00,Sønder Boulevard 51,Copenhagen,,Denmark,1720,0.99,1,9
|
153,2010-11-01 00:00:00,0.99,1,9
|
||||||
154,2010-11-14 00:00:00,"Rua Dr. Falcão Filho, 155",São Paulo,SP,Brazil,01007-010,1.98,1,10
|
154,2010-11-14 00:00:00,1.98,1,10
|
||||||
155,2010-11-14 00:00:00,"Praça Pio X, 119",Rio de Janeiro,RJ,Brazil,20040-020,1.98,1,12
|
155,2010-11-14 00:00:00,1.98,1,12
|
||||||
156,2010-11-15 00:00:00,8210 111 ST NW,Edmonton,AB,Canada,T6G 2C7,3.96,1,14
|
156,2010-11-15 00:00:00,3.96,1,14
|
||||||
157,2010-11-16 00:00:00,627 Broadway,New York,NY,USA,10012-2612,5.94,1,18
|
157,2010-11-16 00:00:00,5.94,1,18
|
||||||
158,2010-11-19 00:00:00,162 E Superior Street,Chicago,IL,USA,60611,8.91,1,24
|
158,2010-11-19 00:00:00,8.91,1,24
|
||||||
159,2010-11-24 00:00:00,5112 48 Street,Yellowknife,NT,Canada,X1A 1N6,13.86,1,33
|
159,2010-11-24 00:00:00,13.86,1,33
|
||||||
160,2010-12-02 00:00:00,"Via Degli Scipioni, 43",Rome,RM,Italy,00192,0.99,1,47
|
160,2010-12-02 00:00:00,0.99,1,47
|
||||||
161,2010-12-15 00:00:00,Lijnbaansgracht 120bg,Amsterdam,VV,Netherlands,1016,1.98,1,48
|
161,2010-12-15 00:00:00,1.98,1,48
|
||||||
162,2010-12-15 00:00:00,C/ San Bernardo 85,Madrid,,Spain,28015,1.98,1,50
|
162,2010-12-15 00:00:00,1.98,1,50
|
||||||
163,2010-12-16 00:00:00,202 Hoxton Street,London,,United Kingdom,N1 5LH,3.96,1,52
|
163,2010-12-16 00:00:00,3.96,1,52
|
||||||
164,2010-12-17 00:00:00,307 Macacha Güemes,Buenos Aires,,Argentina,1106,5.94,1,56
|
164,2010-12-17 00:00:00,5.94,1,56
|
||||||
165,2010-12-20 00:00:00,1498 rue Bélanger,Montréal,QC,Canada,H2G 1A7,8.91,1,3
|
165,2010-12-20 00:00:00,8.91,1,3
|
||||||
166,2010-12-25 00:00:00,"Praça Pio X, 119",Rio de Janeiro,RJ,Brazil,20040-020,13.86,1,12
|
166,2010-12-25 00:00:00,13.86,1,12
|
||||||
167,2011-01-02 00:00:00,2211 W Berry Street,Fort Worth,TX,USA,76110,0.99,1,26
|
167,2011-01-02 00:00:00,0.99,1,26
|
||||||
168,2011-01-15 00:00:00,1033 N Park Ave,Tucson,AZ,USA,85719,1.98,1,27
|
168,2011-01-15 00:00:00,1.98,1,27
|
||||||
169,2011-01-15 00:00:00,796 Dundas Street West,Toronto,ON,Canada,M6J 1V1,1.98,1,29
|
169,2011-01-15 00:00:00,1.98,1,29
|
||||||
170,2011-01-16 00:00:00,194A Chain Lake Drive,Halifax,NS,Canada,B3S 1C5,3.96,1,31
|
170,2011-01-16 00:00:00,3.96,1,31
|
||||||
171,2011-01-17 00:00:00,"Rua dos Campeões Europeus de Viena, 4350",Porto,,Portugal,,5.94,1,35
|
171,2011-01-17 00:00:00,5.94,1,35
|
||||||
172,2011-01-20 00:00:00,"11, Place Bellecour",Lyon,,France,69002,8.91,1,41
|
172,2011-01-20 00:00:00,8.91,1,41
|
||||||
173,2011-01-25 00:00:00,C/ San Bernardo 85,Madrid,,Spain,28015,13.86,1,50
|
173,2011-01-25 00:00:00,13.86,1,50
|
||||||
174,2011-02-02 00:00:00,Klanova 9/506,Prague,,Czech Republic,14700,0.99,1,5
|
174,2011-02-02 00:00:00,0.99,1,5
|
||||||
175,2011-02-15 00:00:00,Rilská 3174/6,Prague,,Czech Republic,14300,1.98,1,6
|
175,2011-02-15 00:00:00,1.98,1,6
|
||||||
176,2011-02-15 00:00:00,Grétrystraat 63,Brussels,,Belgium,1000,1.98,1,8
|
176,2011-02-15 00:00:00,1.98,1,8
|
||||||
177,2011-02-16 00:00:00,"Rua Dr. Falcão Filho, 155",São Paulo,SP,Brazil,01007-010,3.96,1,10
|
177,2011-02-16 00:00:00,3.96,1,10
|
||||||
178,2011-02-17 00:00:00,8210 111 ST NW,Edmonton,AB,Canada,T6G 2C7,5.94,1,14
|
178,2011-02-17 00:00:00,5.94,1,14
|
||||||
179,2011-02-20 00:00:00,541 Del Medio Avenue,Mountain View,CA,USA,94040-111,8.91,1,20
|
179,2011-02-20 00:00:00,8.91,1,20
|
||||||
180,2011-02-25 00:00:00,796 Dundas Street West,Toronto,ON,Canada,M6J 1V1,13.86,1,29
|
180,2011-02-25 00:00:00,13.86,1,29
|
||||||
181,2011-03-05 00:00:00,"68, Rue Jouvence",Dijon,,France,21000,0.99,1,43
|
181,2011-03-05 00:00:00,0.99,1,43
|
||||||
182,2011-03-18 00:00:00,Porthaninkatu 9,Helsinki,,Finland,00530,1.98,1,44
|
182,2011-03-18 00:00:00,1.98,1,44
|
||||||
183,2011-03-18 00:00:00,3 Chatham Street,Dublin,Dublin,Ireland,,1.98,1,46
|
183,2011-03-18 00:00:00,1.98,1,46
|
||||||
184,2011-03-19 00:00:00,Lijnbaansgracht 120bg,Amsterdam,VV,Netherlands,1016,3.96,1,48
|
184,2011-03-19 00:00:00,3.96,1,48
|
||||||
185,2011-03-20 00:00:00,202 Hoxton Street,London,,United Kingdom,N1 5LH,5.94,1,52
|
185,2011-03-20 00:00:00,5.94,1,52
|
||||||
186,2011-03-23 00:00:00,"12,Community Centre",Delhi,,India,110017,8.91,1,58
|
186,2011-03-23 00:00:00,8.91,1,58
|
||||||
187,2011-03-28 00:00:00,Grétrystraat 63,Brussels,,Belgium,1000,13.86,1,8
|
187,2011-03-28 00:00:00,13.86,1,8
|
||||||
188,2011-04-05 00:00:00,120 S Orange Ave,Orlando,FL,USA,32801,0.99,1,22
|
188,2011-04-05 00:00:00,0.99,1,22
|
||||||
189,2011-04-18 00:00:00,69 Salem Street,Boston,MA,USA,2113,1.98,1,23
|
189,2011-04-18 00:00:00,1.98,1,23
|
||||||
190,2011-04-18 00:00:00,319 N. Frances Street,Madison,WI,USA,53703,1.98,1,25
|
190,2011-04-18 00:00:00,1.98,1,25
|
||||||
191,2011-04-19 00:00:00,1033 N Park Ave,Tucson,AZ,USA,85719,3.96,1,27
|
191,2011-04-19 00:00:00,3.96,1,27
|
||||||
192,2011-04-20 00:00:00,194A Chain Lake Drive,Halifax,NS,Canada,B3S 1C5,5.94,1,31
|
192,2011-04-20 00:00:00,5.94,1,31
|
||||||
193,2011-04-23 00:00:00,Berger Straße 10,Frankfurt,,Germany,60316,14.91,1,37
|
193,2011-04-23 00:00:00,14.91,1,37
|
||||||
194,2011-04-28 00:00:00,3 Chatham Street,Dublin,Dublin,Ireland,,21.86,1,46
|
194,2011-04-28 00:00:00,21.86,1,46
|
||||||
195,2011-05-06 00:00:00,"Av. Brigadeiro Faria Lima, 2170",São José dos Campos,SP,Brazil,12227-000,0.99,1,1
|
195,2011-05-06 00:00:00,0.99,1,1
|
||||||
196,2011-05-19 00:00:00,Theodor-Heuss-Straße 34,Stuttgart,,Germany,70174,1.98,1,2
|
196,2011-05-19 00:00:00,1.98,1,2
|
||||||
197,2011-05-19 00:00:00,Ullevålsveien 14,Oslo,,Norway,0171,1.98,1,4
|
197,2011-05-19 00:00:00,1.98,1,4
|
||||||
198,2011-05-20 00:00:00,Rilská 3174/6,Prague,,Czech Republic,14300,3.96,1,6
|
198,2011-05-20 00:00:00,3.96,1,6
|
||||||
199,2011-05-21 00:00:00,"Rua Dr. Falcão Filho, 155",São Paulo,SP,Brazil,01007-010,5.94,1,10
|
199,2011-05-21 00:00:00,5.94,1,10
|
||||||
200,2011-05-24 00:00:00,1600 Amphitheatre Parkway,Mountain View,CA,USA,94043-1351,8.91,1,16
|
200,2011-05-24 00:00:00,8.91,1,16
|
||||||
201,2011-05-29 00:00:00,319 N. Frances Street,Madison,WI,USA,53703,18.86,1,25
|
201,2011-05-29 00:00:00,18.86,1,25
|
||||||
202,2011-06-06 00:00:00,"4, Rue Milton",Paris,,France,75009,1.99,1,39
|
202,2011-06-06 00:00:00,1.99,1,39
|
||||||
203,2011-06-19 00:00:00,"8, Rue Hanovre",Paris,,France,75002,2.98,1,40
|
203,2011-06-19 00:00:00,2.98,1,40
|
||||||
204,2011-06-19 00:00:00,"9, Place Louis Barthou",Bordeaux,,France,33000,3.98,1,42
|
204,2011-06-19 00:00:00,3.98,1,42
|
||||||
205,2011-06-20 00:00:00,Porthaninkatu 9,Helsinki,,Finland,00530,7.96,1,44
|
205,2011-06-20 00:00:00,7.96,1,44
|
||||||
206,2011-06-21 00:00:00,Lijnbaansgracht 120bg,Amsterdam,VV,Netherlands,1016,8.94,1,48
|
206,2011-06-21 00:00:00,8.94,1,48
|
||||||
207,2011-06-24 00:00:00,110 Raeburn Pl,Edinburgh ,,United Kingdom,EH4 1HH,8.91,1,54
|
207,2011-06-24 00:00:00,8.91,1,54
|
||||||
208,2011-06-29 00:00:00,Ullevålsveien 14,Oslo,,Norway,0171,15.86,1,4
|
208,2011-06-29 00:00:00,15.86,1,4
|
||||||
209,2011-07-07 00:00:00,627 Broadway,New York,NY,USA,10012-2612,0.99,1,18
|
209,2011-07-07 00:00:00,0.99,1,18
|
||||||
210,2011-07-20 00:00:00,1 Infinite Loop,Cupertino,CA,USA,95014,1.98,1,19
|
210,2011-07-20 00:00:00,1.98,1,19
|
||||||
211,2011-07-20 00:00:00,801 W 4th Street,Reno,NV,USA,89503,1.98,1,21
|
211,2011-07-20 00:00:00,1.98,1,21
|
||||||
212,2011-07-21 00:00:00,69 Salem Street,Boston,MA,USA,2113,3.96,1,23
|
212,2011-07-21 00:00:00,3.96,1,23
|
||||||
213,2011-07-22 00:00:00,1033 N Park Ave,Tucson,AZ,USA,85719,5.94,1,27
|
213,2011-07-22 00:00:00,5.94,1,27
|
||||||
214,2011-07-25 00:00:00,5112 48 Street,Yellowknife,NT,Canada,X1A 1N6,8.91,1,33
|
214,2011-07-25 00:00:00,8.91,1,33
|
||||||
215,2011-07-30 00:00:00,"9, Place Louis Barthou",Bordeaux,,France,33000,13.86,1,42
|
215,2011-07-30 00:00:00,13.86,1,42
|
||||||
216,2011-08-07 00:00:00,307 Macacha Güemes,Buenos Aires,,Argentina,1106,0.99,1,56
|
216,2011-08-07 00:00:00,0.99,1,56
|
||||||
217,2011-08-20 00:00:00,"Calle Lira, 198",Santiago,,Chile,,1.98,1,57
|
217,2011-08-20 00:00:00,1.98,1,57
|
||||||
218,2011-08-20 00:00:00,"3,Raj Bhavan Road",Bangalore,,India,560001,1.98,1,59
|
218,2011-08-20 00:00:00,1.98,1,59
|
||||||
219,2011-08-21 00:00:00,Theodor-Heuss-Straße 34,Stuttgart,,Germany,70174,3.96,1,2
|
219,2011-08-21 00:00:00,3.96,1,2
|
||||||
220,2011-08-22 00:00:00,Rilská 3174/6,Prague,,Czech Republic,14300,5.94,1,6
|
220,2011-08-22 00:00:00,5.94,1,6
|
||||||
221,2011-08-25 00:00:00,"Praça Pio X, 119",Rio de Janeiro,RJ,Brazil,20040-020,8.91,1,12
|
221,2011-08-25 00:00:00,8.91,1,12
|
||||||
222,2011-08-30 00:00:00,801 W 4th Street,Reno,NV,USA,89503,13.86,1,21
|
222,2011-08-30 00:00:00,13.86,1,21
|
||||||
223,2011-09-07 00:00:00,"Rua dos Campeões Europeus de Viena, 4350",Porto,,Portugal,,0.99,1,35
|
223,2011-09-07 00:00:00,0.99,1,35
|
||||||
224,2011-09-20 00:00:00,Tauentzienstraße 8,Berlin,,Germany,10789,1.98,1,36
|
224,2011-09-20 00:00:00,1.98,1,36
|
||||||
225,2011-09-20 00:00:00,Barbarossastraße 19,Berlin,,Germany,10779,1.98,1,38
|
225,2011-09-20 00:00:00,1.98,1,38
|
||||||
226,2011-09-21 00:00:00,"8, Rue Hanovre",Paris,,France,75002,3.96,1,40
|
226,2011-09-21 00:00:00,3.96,1,40
|
||||||
227,2011-09-22 00:00:00,Porthaninkatu 9,Helsinki,,Finland,00530,5.94,1,44
|
227,2011-09-22 00:00:00,5.94,1,44
|
||||||
228,2011-09-25 00:00:00,C/ San Bernardo 85,Madrid,,Spain,28015,8.91,1,50
|
228,2011-09-25 00:00:00,8.91,1,50
|
||||||
229,2011-09-30 00:00:00,"3,Raj Bhavan Road",Bangalore,,India,560001,13.86,1,59
|
229,2011-09-30 00:00:00,13.86,1,59
|
||||||
230,2011-10-08 00:00:00,8210 111 ST NW,Edmonton,AB,Canada,T6G 2C7,0.99,1,14
|
230,2011-10-08 00:00:00,0.99,1,14
|
||||||
231,2011-10-21 00:00:00,700 W Pender Street,Vancouver,BC,Canada,V6C 1G8,1.98,1,15
|
231,2011-10-21 00:00:00,1.98,1,15
|
||||||
232,2011-10-21 00:00:00,1 Microsoft Way,Redmond,WA,USA,98052-8300,1.98,1,17
|
232,2011-10-21 00:00:00,1.98,1,17
|
||||||
233,2011-10-22 00:00:00,1 Infinite Loop,Cupertino,CA,USA,95014,3.96,1,19
|
233,2011-10-22 00:00:00,3.96,1,19
|
||||||
234,2011-10-23 00:00:00,69 Salem Street,Boston,MA,USA,2113,5.94,1,23
|
234,2011-10-23 00:00:00,5.94,1,23
|
||||||
235,2011-10-26 00:00:00,796 Dundas Street West,Toronto,ON,Canada,M6J 1V1,8.91,1,29
|
235,2011-10-26 00:00:00,8.91,1,29
|
||||||
236,2011-10-31 00:00:00,Barbarossastraße 19,Berlin,,Germany,10779,13.86,1,38
|
236,2011-10-31 00:00:00,13.86,1,38
|
||||||
237,2011-11-08 00:00:00,202 Hoxton Street,London,,United Kingdom,N1 5LH,0.99,1,52
|
237,2011-11-08 00:00:00,0.99,1,52
|
||||||
238,2011-11-21 00:00:00,113 Lupus St,London,,United Kingdom,SW1V 3EN,1.98,1,53
|
238,2011-11-21 00:00:00,1.98,1,53
|
||||||
239,2011-11-21 00:00:00,421 Bourke Street,Sidney,NSW,Australia,2010,1.98,1,55
|
239,2011-11-21 00:00:00,1.98,1,55
|
||||||
240,2011-11-22 00:00:00,"Calle Lira, 198",Santiago,,Chile,,3.96,1,57
|
240,2011-11-22 00:00:00,3.96,1,57
|
||||||
241,2011-11-23 00:00:00,Theodor-Heuss-Straße 34,Stuttgart,,Germany,70174,5.94,1,2
|
241,2011-11-23 00:00:00,5.94,1,2
|
||||||
242,2011-11-26 00:00:00,Grétrystraat 63,Brussels,,Belgium,1000,8.91,1,8
|
242,2011-11-26 00:00:00,8.91,1,8
|
||||||
243,2011-12-01 00:00:00,1 Microsoft Way,Redmond,WA,USA,98052-8300,13.86,1,17
|
243,2011-12-01 00:00:00,13.86,1,17
|
||||||
244,2011-12-09 00:00:00,194A Chain Lake Drive,Halifax,NS,Canada,B3S 1C5,0.99,1,31
|
244,2011-12-09 00:00:00,0.99,1,31
|
||||||
245,2011-12-22 00:00:00,696 Osborne Street,Winnipeg,MB,Canada,R3L 2B9,1.98,1,32
|
245,2011-12-22 00:00:00,1.98,1,32
|
||||||
246,2011-12-22 00:00:00,Rua da Assunção 53,Lisbon,,Portugal,,1.98,1,34
|
246,2011-12-22 00:00:00,1.98,1,34
|
||||||
247,2011-12-23 00:00:00,Tauentzienstraße 8,Berlin,,Germany,10789,3.96,1,36
|
247,2011-12-23 00:00:00,3.96,1,36
|
||||||
248,2011-12-24 00:00:00,"8, Rue Hanovre",Paris,,France,75002,5.94,1,40
|
248,2011-12-24 00:00:00,5.94,1,40
|
||||||
249,2011-12-27 00:00:00,3 Chatham Street,Dublin,Dublin,Ireland,,8.91,1,46
|
249,2011-12-27 00:00:00,8.91,1,46
|
||||||
250,2012-01-01 00:00:00,421 Bourke Street,Sidney,NSW,Australia,2010,13.86,1,55
|
250,2012-01-01 00:00:00,13.86,1,55
|
||||||
251,2012-01-09 00:00:00,"Rua Dr. Falcão Filho, 155",São Paulo,SP,Brazil,01007-010,0.99,1,10
|
251,2012-01-09 00:00:00,0.99,1,10
|
||||||
252,2012-01-22 00:00:00,"Av. Paulista, 2022",São Paulo,SP,Brazil,01310-200,1.98,1,11
|
252,2012-01-22 00:00:00,1.98,1,11
|
||||||
253,2012-01-22 00:00:00,Qe 7 Bloco G,Brasília,DF,Brazil,71020-677,1.98,1,13
|
253,2012-01-22 00:00:00,1.98,1,13
|
||||||
254,2012-01-23 00:00:00,700 W Pender Street,Vancouver,BC,Canada,V6C 1G8,3.96,1,15
|
254,2012-01-23 00:00:00,3.96,1,15
|
||||||
255,2012-01-24 00:00:00,1 Infinite Loop,Cupertino,CA,USA,95014,5.94,1,19
|
255,2012-01-24 00:00:00,5.94,1,19
|
||||||
256,2012-01-27 00:00:00,319 N. Frances Street,Madison,WI,USA,53703,8.91,1,25
|
256,2012-01-27 00:00:00,8.91,1,25
|
||||||
257,2012-02-01 00:00:00,Rua da Assunção 53,Lisbon,,Portugal,,13.86,1,34
|
257,2012-02-01 00:00:00,13.86,1,34
|
||||||
258,2012-02-09 00:00:00,Lijnbaansgracht 120bg,Amsterdam,VV,Netherlands,1016,0.99,1,48
|
258,2012-02-09 00:00:00,0.99,1,48
|
||||||
259,2012-02-22 00:00:00,Ordynacka 10,Warsaw,,Poland,00-358,1.98,1,49
|
259,2012-02-22 00:00:00,1.98,1,49
|
||||||
260,2012-02-22 00:00:00,Celsiusg. 9,Stockholm,,Sweden,11230,1.98,1,51
|
260,2012-02-22 00:00:00,1.98,1,51
|
||||||
261,2012-02-23 00:00:00,113 Lupus St,London,,United Kingdom,SW1V 3EN,3.96,1,53
|
261,2012-02-23 00:00:00,3.96,1,53
|
||||||
262,2012-02-24 00:00:00,"Calle Lira, 198",Santiago,,Chile,,5.94,1,57
|
262,2012-02-24 00:00:00,5.94,1,57
|
||||||
263,2012-02-27 00:00:00,Ullevålsveien 14,Oslo,,Norway,0171,8.91,1,4
|
263,2012-02-27 00:00:00,8.91,1,4
|
||||||
264,2012-03-03 00:00:00,Qe 7 Bloco G,Brasília,DF,Brazil,71020-677,13.86,1,13
|
264,2012-03-03 00:00:00,13.86,1,13
|
||||||
265,2012-03-11 00:00:00,1033 N Park Ave,Tucson,AZ,USA,85719,0.99,1,27
|
265,2012-03-11 00:00:00,0.99,1,27
|
||||||
266,2012-03-24 00:00:00,302 S 700 E,Salt Lake City,UT,USA,84102,1.98,1,28
|
266,2012-03-24 00:00:00,1.98,1,28
|
||||||
267,2012-03-24 00:00:00,230 Elgin Street,Ottawa,ON,Canada,K2P 1L7,1.98,1,30
|
267,2012-03-24 00:00:00,1.98,1,30
|
||||||
268,2012-03-25 00:00:00,696 Osborne Street,Winnipeg,MB,Canada,R3L 2B9,3.96,1,32
|
268,2012-03-25 00:00:00,3.96,1,32
|
||||||
269,2012-03-26 00:00:00,Tauentzienstraße 8,Berlin,,Germany,10789,5.94,1,36
|
269,2012-03-26 00:00:00,5.94,1,36
|
||||||
270,2012-03-29 00:00:00,"9, Place Louis Barthou",Bordeaux,,France,33000,8.91,1,42
|
270,2012-03-29 00:00:00,8.91,1,42
|
||||||
271,2012-04-03 00:00:00,Celsiusg. 9,Stockholm,,Sweden,11230,13.86,1,51
|
271,2012-04-03 00:00:00,13.86,1,51
|
||||||
272,2012-04-11 00:00:00,Rilská 3174/6,Prague,,Czech Republic,14300,0.99,1,6
|
272,2012-04-11 00:00:00,0.99,1,6
|
||||||
273,2012-04-24 00:00:00,"Rotenturmstraße 4, 1010 Innere Stadt",Vienne,,Austria,1010,1.98,1,7
|
273,2012-04-24 00:00:00,1.98,1,7
|
||||||
274,2012-04-24 00:00:00,Sønder Boulevard 51,Copenhagen,,Denmark,1720,1.98,1,9
|
274,2012-04-24 00:00:00,1.98,1,9
|
||||||
275,2012-04-25 00:00:00,"Av. Paulista, 2022",São Paulo,SP,Brazil,01310-200,3.96,1,11
|
275,2012-04-25 00:00:00,3.96,1,11
|
||||||
276,2012-04-26 00:00:00,700 W Pender Street,Vancouver,BC,Canada,V6C 1G8,5.94,1,15
|
276,2012-04-26 00:00:00,5.94,1,15
|
||||||
277,2012-04-29 00:00:00,801 W 4th Street,Reno,NV,USA,89503,8.91,1,21
|
277,2012-04-29 00:00:00,8.91,1,21
|
||||||
278,2012-05-04 00:00:00,230 Elgin Street,Ottawa,ON,Canada,K2P 1L7,13.86,1,30
|
278,2012-05-04 00:00:00,13.86,1,30
|
||||||
279,2012-05-12 00:00:00,Porthaninkatu 9,Helsinki,,Finland,00530,0.99,1,44
|
279,2012-05-12 00:00:00,0.99,1,44
|
||||||
280,2012-05-25 00:00:00,Erzsébet krt. 58.,Budapest,,Hungary,H-1073,1.98,1,45
|
280,2012-05-25 00:00:00,1.98,1,45
|
||||||
281,2012-05-25 00:00:00,"Via Degli Scipioni, 43",Rome,RM,Italy,00192,1.98,1,47
|
281,2012-05-25 00:00:00,1.98,1,47
|
||||||
282,2012-05-26 00:00:00,Ordynacka 10,Warsaw,,Poland,00-358,3.96,1,49
|
282,2012-05-26 00:00:00,3.96,1,49
|
||||||
283,2012-05-27 00:00:00,113 Lupus St,London,,United Kingdom,SW1V 3EN,5.94,1,53
|
283,2012-05-27 00:00:00,5.94,1,53
|
||||||
284,2012-05-30 00:00:00,"3,Raj Bhavan Road",Bangalore,,India,560001,8.91,1,59
|
284,2012-05-30 00:00:00,8.91,1,59
|
||||||
285,2012-06-04 00:00:00,Sønder Boulevard 51,Copenhagen,,Denmark,1720,13.86,1,9
|
285,2012-06-04 00:00:00,13.86,1,9
|
||||||
286,2012-06-12 00:00:00,69 Salem Street,Boston,MA,USA,2113,0.99,1,23
|
286,2012-06-12 00:00:00,0.99,1,23
|
||||||
287,2012-06-25 00:00:00,162 E Superior Street,Chicago,IL,USA,60611,1.98,1,24
|
287,2012-06-25 00:00:00,1.98,1,24
|
||||||
288,2012-06-25 00:00:00,2211 W Berry Street,Fort Worth,TX,USA,76110,1.98,1,26
|
288,2012-06-25 00:00:00,1.98,1,26
|
||||||
289,2012-06-26 00:00:00,302 S 700 E,Salt Lake City,UT,USA,84102,3.96,1,28
|
289,2012-06-26 00:00:00,3.96,1,28
|
||||||
290,2012-06-27 00:00:00,696 Osborne Street,Winnipeg,MB,Canada,R3L 2B9,5.94,1,32
|
290,2012-06-27 00:00:00,5.94,1,32
|
||||||
291,2012-06-30 00:00:00,Barbarossastraße 19,Berlin,,Germany,10779,8.91,1,38
|
291,2012-06-30 00:00:00,8.91,1,38
|
||||||
292,2012-07-05 00:00:00,"Via Degli Scipioni, 43",Rome,RM,Italy,00192,13.86,1,47
|
292,2012-07-05 00:00:00,13.86,1,47
|
||||||
293,2012-07-13 00:00:00,Theodor-Heuss-Straße 34,Stuttgart,,Germany,70174,0.99,1,2
|
293,2012-07-13 00:00:00,0.99,1,2
|
||||||
294,2012-07-26 00:00:00,1498 rue Bélanger,Montréal,QC,Canada,H2G 1A7,1.98,1,3
|
294,2012-07-26 00:00:00,1.98,1,3
|
||||||
295,2012-07-26 00:00:00,Klanova 9/506,Prague,,Czech Republic,14700,1.98,1,5
|
295,2012-07-26 00:00:00,1.98,1,5
|
||||||
296,2012-07-27 00:00:00,"Rotenturmstraße 4, 1010 Innere Stadt",Vienne,,Austria,1010,3.96,1,7
|
296,2012-07-27 00:00:00,3.96,1,7
|
||||||
297,2012-07-28 00:00:00,"Av. Paulista, 2022",São Paulo,SP,Brazil,01310-200,5.94,1,11
|
297,2012-07-28 00:00:00,5.94,1,11
|
||||||
298,2012-07-31 00:00:00,1 Microsoft Way,Redmond,WA,USA,98052-8300,10.91,1,17
|
298,2012-07-31 00:00:00,10.91,1,17
|
||||||
299,2012-08-05 00:00:00,2211 W Berry Street,Fort Worth,TX,USA,76110,23.86,1,26
|
299,2012-08-05 00:00:00,23.86,1,26
|
||||||
300,2012-08-13 00:00:00,"8, Rue Hanovre",Paris,,France,75002,0.99,1,40
|
300,2012-08-13 00:00:00,0.99,1,40
|
||||||
301,2012-08-26 00:00:00,"11, Place Bellecour",Lyon,,France,69002,1.98,1,41
|
301,2012-08-26 00:00:00,1.98,1,41
|
||||||
302,2012-08-26 00:00:00,"68, Rue Jouvence",Dijon,,France,21000,1.98,1,43
|
302,2012-08-26 00:00:00,1.98,1,43
|
||||||
303,2012-08-27 00:00:00,Erzsébet krt. 58.,Budapest,,Hungary,H-1073,3.96,1,45
|
303,2012-08-27 00:00:00,3.96,1,45
|
||||||
304,2012-08-28 00:00:00,Ordynacka 10,Warsaw,,Poland,00-358,5.94,1,49
|
304,2012-08-28 00:00:00,5.94,1,49
|
||||||
305,2012-08-31 00:00:00,421 Bourke Street,Sidney,NSW,Australia,2010,8.91,1,55
|
305,2012-08-31 00:00:00,8.91,1,55
|
||||||
306,2012-09-05 00:00:00,Klanova 9/506,Prague,,Czech Republic,14700,16.86,1,5
|
306,2012-09-05 00:00:00,16.86,1,5
|
||||||
307,2012-09-13 00:00:00,1 Infinite Loop,Cupertino,CA,USA,95014,1.99,1,19
|
307,2012-09-13 00:00:00,1.99,1,19
|
||||||
308,2012-09-26 00:00:00,541 Del Medio Avenue,Mountain View,CA,USA,94040-111,3.98,1,20
|
308,2012-09-26 00:00:00,3.98,1,20
|
||||||
309,2012-09-26 00:00:00,120 S Orange Ave,Orlando,FL,USA,32801,3.98,1,22
|
309,2012-09-26 00:00:00,3.98,1,22
|
||||||
310,2012-09-27 00:00:00,162 E Superior Street,Chicago,IL,USA,60611,7.96,1,24
|
310,2012-09-27 00:00:00,7.96,1,24
|
||||||
311,2012-09-28 00:00:00,302 S 700 E,Salt Lake City,UT,USA,84102,11.94,1,28
|
311,2012-09-28 00:00:00,11.94,1,28
|
||||||
312,2012-10-01 00:00:00,Rua da Assunção 53,Lisbon,,Portugal,,10.91,1,34
|
312,2012-10-01 00:00:00,10.91,1,34
|
||||||
313,2012-10-06 00:00:00,"68, Rue Jouvence",Dijon,,France,21000,16.86,1,43
|
313,2012-10-06 00:00:00,16.86,1,43
|
||||||
314,2012-10-14 00:00:00,"Calle Lira, 198",Santiago,,Chile,,0.99,1,57
|
314,2012-10-14 00:00:00,0.99,1,57
|
||||||
315,2012-10-27 00:00:00,"12,Community Centre",Delhi,,India,110017,1.98,1,58
|
315,2012-10-27 00:00:00,1.98,1,58
|
||||||
316,2012-10-27 00:00:00,"Av. Brigadeiro Faria Lima, 2170",São José dos Campos,SP,Brazil,12227-000,1.98,1,1
|
316,2012-10-27 00:00:00,1.98,1,1
|
||||||
317,2012-10-28 00:00:00,1498 rue Bélanger,Montréal,QC,Canada,H2G 1A7,3.96,1,3
|
317,2012-10-28 00:00:00,3.96,1,3
|
||||||
318,2012-10-29 00:00:00,"Rotenturmstraße 4, 1010 Innere Stadt",Vienne,,Austria,1010,5.94,1,7
|
318,2012-10-29 00:00:00,5.94,1,7
|
||||||
319,2012-11-01 00:00:00,Qe 7 Bloco G,Brasília,DF,Brazil,71020-677,8.91,1,13
|
319,2012-11-01 00:00:00,8.91,1,13
|
||||||
320,2012-11-06 00:00:00,120 S Orange Ave,Orlando,FL,USA,32801,13.86,1,22
|
320,2012-11-06 00:00:00,13.86,1,22
|
||||||
321,2012-11-14 00:00:00,Tauentzienstraße 8,Berlin,,Germany,10789,0.99,1,36
|
321,2012-11-14 00:00:00,0.99,1,36
|
||||||
322,2012-11-27 00:00:00,Berger Straße 10,Frankfurt,,Germany,60316,1.98,1,37
|
322,2012-11-27 00:00:00,1.98,1,37
|
||||||
323,2012-11-27 00:00:00,"4, Rue Milton",Paris,,France,75009,1.98,1,39
|
323,2012-11-27 00:00:00,1.98,1,39
|
||||||
324,2012-11-28 00:00:00,"11, Place Bellecour",Lyon,,France,69002,3.96,1,41
|
324,2012-11-28 00:00:00,3.96,1,41
|
||||||
325,2012-11-29 00:00:00,Erzsébet krt. 58.,Budapest,,Hungary,H-1073,5.94,1,45
|
325,2012-11-29 00:00:00,5.94,1,45
|
||||||
326,2012-12-02 00:00:00,Celsiusg. 9,Stockholm,,Sweden,11230,8.91,1,51
|
326,2012-12-02 00:00:00,8.91,1,51
|
||||||
327,2012-12-07 00:00:00,"Av. Brigadeiro Faria Lima, 2170",São José dos Campos,SP,Brazil,12227-000,13.86,1,1
|
327,2012-12-07 00:00:00,13.86,1,1
|
||||||
328,2012-12-15 00:00:00,700 W Pender Street,Vancouver,BC,Canada,V6C 1G8,0.99,1,15
|
328,2012-12-15 00:00:00,0.99,1,15
|
||||||
329,2012-12-28 00:00:00,1600 Amphitheatre Parkway,Mountain View,CA,USA,94043-1351,1.98,1,16
|
329,2012-12-28 00:00:00,1.98,1,16
|
||||||
330,2012-12-28 00:00:00,627 Broadway,New York,NY,USA,10012-2612,1.98,1,18
|
330,2012-12-28 00:00:00,1.98,1,18
|
||||||
331,2012-12-29 00:00:00,541 Del Medio Avenue,Mountain View,CA,USA,94040-111,3.96,1,20
|
331,2012-12-29 00:00:00,3.96,1,20
|
||||||
332,2012-12-30 00:00:00,162 E Superior Street,Chicago,IL,USA,60611,5.94,1,24
|
332,2012-12-30 00:00:00,5.94,1,24
|
||||||
333,2013-01-02 00:00:00,230 Elgin Street,Ottawa,ON,Canada,K2P 1L7,8.91,1,30
|
333,2013-01-02 00:00:00,8.91,1,30
|
||||||
334,2013-01-07 00:00:00,"4, Rue Milton",Paris,,France,75009,13.86,1,39
|
334,2013-01-07 00:00:00,13.86,1,39
|
||||||
335,2013-01-15 00:00:00,113 Lupus St,London,,United Kingdom,SW1V 3EN,0.99,1,53
|
335,2013-01-15 00:00:00,0.99,1,53
|
||||||
336,2013-01-28 00:00:00,110 Raeburn Pl,Edinburgh ,,United Kingdom,EH4 1HH,1.98,1,54
|
336,2013-01-28 00:00:00,1.98,1,54
|
||||||
337,2013-01-28 00:00:00,307 Macacha Güemes,Buenos Aires,,Argentina,1106,1.98,1,56
|
337,2013-01-28 00:00:00,1.98,1,56
|
||||||
338,2013-01-29 00:00:00,"12,Community Centre",Delhi,,India,110017,3.96,1,58
|
338,2013-01-29 00:00:00,3.96,1,58
|
||||||
339,2013-01-30 00:00:00,1498 rue Bélanger,Montréal,QC,Canada,H2G 1A7,5.94,1,3
|
339,2013-01-30 00:00:00,5.94,1,3
|
||||||
340,2013-02-02 00:00:00,Sønder Boulevard 51,Copenhagen,,Denmark,1720,8.91,1,9
|
340,2013-02-02 00:00:00,8.91,1,9
|
||||||
341,2013-02-07 00:00:00,627 Broadway,New York,NY,USA,10012-2612,13.86,1,18
|
341,2013-02-07 00:00:00,13.86,1,18
|
||||||
342,2013-02-15 00:00:00,696 Osborne Street,Winnipeg,MB,Canada,R3L 2B9,0.99,1,32
|
342,2013-02-15 00:00:00,0.99,1,32
|
||||||
343,2013-02-28 00:00:00,5112 48 Street,Yellowknife,NT,Canada,X1A 1N6,1.98,1,33
|
343,2013-02-28 00:00:00,1.98,1,33
|
||||||
344,2013-02-28 00:00:00,"Rua dos Campeões Europeus de Viena, 4350",Porto,,Portugal,,1.98,1,35
|
344,2013-02-28 00:00:00,1.98,1,35
|
||||||
345,2013-03-01 00:00:00,Berger Straße 10,Frankfurt,,Germany,60316,3.96,1,37
|
345,2013-03-01 00:00:00,3.96,1,37
|
||||||
346,2013-03-02 00:00:00,"11, Place Bellecour",Lyon,,France,69002,5.94,1,41
|
346,2013-03-02 00:00:00,5.94,1,41
|
||||||
347,2013-03-05 00:00:00,"Via Degli Scipioni, 43",Rome,RM,Italy,00192,8.91,1,47
|
347,2013-03-05 00:00:00,8.91,1,47
|
||||||
348,2013-03-10 00:00:00,307 Macacha Güemes,Buenos Aires,,Argentina,1106,13.86,1,56
|
348,2013-03-10 00:00:00,13.86,1,56
|
||||||
349,2013-03-18 00:00:00,"Av. Paulista, 2022",São Paulo,SP,Brazil,01310-200,0.99,1,11
|
349,2013-03-18 00:00:00,0.99,1,11
|
||||||
350,2013-03-31 00:00:00,"Praça Pio X, 119",Rio de Janeiro,RJ,Brazil,20040-020,1.98,1,12
|
350,2013-03-31 00:00:00,1.98,1,12
|
||||||
351,2013-03-31 00:00:00,8210 111 ST NW,Edmonton,AB,Canada,T6G 2C7,1.98,1,14
|
351,2013-03-31 00:00:00,1.98,1,14
|
||||||
352,2013-04-01 00:00:00,1600 Amphitheatre Parkway,Mountain View,CA,USA,94043-1351,3.96,1,16
|
352,2013-04-01 00:00:00,3.96,1,16
|
||||||
353,2013-04-02 00:00:00,541 Del Medio Avenue,Mountain View,CA,USA,94040-111,5.94,1,20
|
353,2013-04-02 00:00:00,5.94,1,20
|
||||||
354,2013-04-05 00:00:00,2211 W Berry Street,Fort Worth,TX,USA,76110,8.91,1,26
|
354,2013-04-05 00:00:00,8.91,1,26
|
||||||
355,2013-04-10 00:00:00,"Rua dos Campeões Europeus de Viena, 4350",Porto,,Portugal,,13.86,1,35
|
355,2013-04-10 00:00:00,13.86,1,35
|
||||||
356,2013-04-18 00:00:00,Ordynacka 10,Warsaw,,Poland,00-358,0.99,1,49
|
356,2013-04-18 00:00:00,0.99,1,49
|
||||||
357,2013-05-01 00:00:00,C/ San Bernardo 85,Madrid,,Spain,28015,1.98,1,50
|
357,2013-05-01 00:00:00,1.98,1,50
|
||||||
358,2013-05-01 00:00:00,202 Hoxton Street,London,,United Kingdom,N1 5LH,1.98,1,52
|
358,2013-05-01 00:00:00,1.98,1,52
|
||||||
359,2013-05-02 00:00:00,110 Raeburn Pl,Edinburgh ,,United Kingdom,EH4 1HH,3.96,1,54
|
359,2013-05-02 00:00:00,3.96,1,54
|
||||||
360,2013-05-03 00:00:00,"12,Community Centre",Delhi,,India,110017,5.94,1,58
|
360,2013-05-03 00:00:00,5.94,1,58
|
||||||
361,2013-05-06 00:00:00,Klanova 9/506,Prague,,Czech Republic,14700,8.91,1,5
|
361,2013-05-06 00:00:00,8.91,1,5
|
||||||
362,2013-05-11 00:00:00,8210 111 ST NW,Edmonton,AB,Canada,T6G 2C7,13.86,1,14
|
362,2013-05-11 00:00:00,13.86,1,14
|
||||||
363,2013-05-19 00:00:00,302 S 700 E,Salt Lake City,UT,USA,84102,0.99,1,28
|
363,2013-05-19 00:00:00,0.99,1,28
|
||||||
364,2013-06-01 00:00:00,796 Dundas Street West,Toronto,ON,Canada,M6J 1V1,1.98,1,29
|
364,2013-06-01 00:00:00,1.98,1,29
|
||||||
365,2013-06-01 00:00:00,194A Chain Lake Drive,Halifax,NS,Canada,B3S 1C5,1.98,1,31
|
365,2013-06-01 00:00:00,1.98,1,31
|
||||||
366,2013-06-02 00:00:00,5112 48 Street,Yellowknife,NT,Canada,X1A 1N6,3.96,1,33
|
366,2013-06-02 00:00:00,3.96,1,33
|
||||||
367,2013-06-03 00:00:00,Berger Straße 10,Frankfurt,,Germany,60316,5.94,1,37
|
367,2013-06-03 00:00:00,5.94,1,37
|
||||||
368,2013-06-06 00:00:00,"68, Rue Jouvence",Dijon,,France,21000,8.91,1,43
|
368,2013-06-06 00:00:00,8.91,1,43
|
||||||
369,2013-06-11 00:00:00,202 Hoxton Street,London,,United Kingdom,N1 5LH,13.86,1,52
|
369,2013-06-11 00:00:00,13.86,1,52
|
||||||
370,2013-06-19 00:00:00,"Rotenturmstraße 4, 1010 Innere Stadt",Vienne,,Austria,1010,0.99,1,7
|
370,2013-06-19 00:00:00,0.99,1,7
|
||||||
371,2013-07-02 00:00:00,Grétrystraat 63,Brussels,,Belgium,1000,1.98,1,8
|
371,2013-07-02 00:00:00,1.98,1,8
|
||||||
372,2013-07-02 00:00:00,"Rua Dr. Falcão Filho, 155",São Paulo,SP,Brazil,01007-010,1.98,1,10
|
372,2013-07-02 00:00:00,1.98,1,10
|
||||||
373,2013-07-03 00:00:00,"Praça Pio X, 119",Rio de Janeiro,RJ,Brazil,20040-020,3.96,1,12
|
373,2013-07-03 00:00:00,3.96,1,12
|
||||||
374,2013-07-04 00:00:00,1600 Amphitheatre Parkway,Mountain View,CA,USA,94043-1351,5.94,1,16
|
374,2013-07-04 00:00:00,5.94,1,16
|
||||||
375,2013-07-07 00:00:00,120 S Orange Ave,Orlando,FL,USA,32801,8.91,1,22
|
375,2013-07-07 00:00:00,8.91,1,22
|
||||||
376,2013-07-12 00:00:00,194A Chain Lake Drive,Halifax,NS,Canada,B3S 1C5,13.86,1,31
|
376,2013-07-12 00:00:00,13.86,1,31
|
||||||
377,2013-07-20 00:00:00,Erzsébet krt. 58.,Budapest,,Hungary,H-1073,0.99,1,45
|
377,2013-07-20 00:00:00,0.99,1,45
|
||||||
378,2013-08-02 00:00:00,3 Chatham Street,Dublin,Dublin,Ireland,,1.98,1,46
|
378,2013-08-02 00:00:00,1.98,1,46
|
||||||
379,2013-08-02 00:00:00,Lijnbaansgracht 120bg,Amsterdam,VV,Netherlands,1016,1.98,1,48
|
379,2013-08-02 00:00:00,1.98,1,48
|
||||||
380,2013-08-03 00:00:00,C/ San Bernardo 85,Madrid,,Spain,28015,3.96,1,50
|
380,2013-08-03 00:00:00,3.96,1,50
|
||||||
381,2013-08-04 00:00:00,110 Raeburn Pl,Edinburgh ,,United Kingdom,EH4 1HH,5.94,1,54
|
381,2013-08-04 00:00:00,5.94,1,54
|
||||||
382,2013-08-07 00:00:00,"Av. Brigadeiro Faria Lima, 2170",São José dos Campos,SP,Brazil,12227-000,8.91,1,1
|
382,2013-08-07 00:00:00,8.91,1,1
|
||||||
383,2013-08-12 00:00:00,"Rua Dr. Falcão Filho, 155",São Paulo,SP,Brazil,01007-010,13.86,1,10
|
383,2013-08-12 00:00:00,13.86,1,10
|
||||||
384,2013-08-20 00:00:00,162 E Superior Street,Chicago,IL,USA,60611,0.99,1,24
|
384,2013-08-20 00:00:00,0.99,1,24
|
||||||
385,2013-09-02 00:00:00,319 N. Frances Street,Madison,WI,USA,53703,1.98,1,25
|
385,2013-09-02 00:00:00,1.98,1,25
|
||||||
386,2013-09-02 00:00:00,1033 N Park Ave,Tucson,AZ,USA,85719,1.98,1,27
|
386,2013-09-02 00:00:00,1.98,1,27
|
||||||
387,2013-09-03 00:00:00,796 Dundas Street West,Toronto,ON,Canada,M6J 1V1,3.96,1,29
|
387,2013-09-03 00:00:00,3.96,1,29
|
||||||
388,2013-09-04 00:00:00,5112 48 Street,Yellowknife,NT,Canada,X1A 1N6,5.94,1,33
|
388,2013-09-04 00:00:00,5.94,1,33
|
||||||
389,2013-09-07 00:00:00,"4, Rue Milton",Paris,,France,75009,8.91,1,39
|
389,2013-09-07 00:00:00,8.91,1,39
|
||||||
390,2013-09-12 00:00:00,Lijnbaansgracht 120bg,Amsterdam,VV,Netherlands,1016,13.86,1,48
|
390,2013-09-12 00:00:00,13.86,1,48
|
||||||
391,2013-09-20 00:00:00,1498 rue Bélanger,Montréal,QC,Canada,H2G 1A7,0.99,1,3
|
391,2013-09-20 00:00:00,0.99,1,3
|
||||||
392,2013-10-03 00:00:00,Ullevålsveien 14,Oslo,,Norway,0171,1.98,1,4
|
392,2013-10-03 00:00:00,1.98,1,4
|
||||||
393,2013-10-03 00:00:00,Rilská 3174/6,Prague,,Czech Republic,14300,1.98,1,6
|
393,2013-10-03 00:00:00,1.98,1,6
|
||||||
394,2013-10-04 00:00:00,Grétrystraat 63,Brussels,,Belgium,1000,3.96,1,8
|
394,2013-10-04 00:00:00,3.96,1,8
|
||||||
395,2013-10-05 00:00:00,"Praça Pio X, 119",Rio de Janeiro,RJ,Brazil,20040-020,5.94,1,12
|
395,2013-10-05 00:00:00,5.94,1,12
|
||||||
396,2013-10-08 00:00:00,627 Broadway,New York,NY,USA,10012-2612,8.91,1,18
|
396,2013-10-08 00:00:00,8.91,1,18
|
||||||
397,2013-10-13 00:00:00,1033 N Park Ave,Tucson,AZ,USA,85719,13.86,1,27
|
397,2013-10-13 00:00:00,13.86,1,27
|
||||||
398,2013-10-21 00:00:00,"11, Place Bellecour",Lyon,,France,69002,0.99,1,41
|
398,2013-10-21 00:00:00,0.99,1,41
|
||||||
399,2013-11-03 00:00:00,"9, Place Louis Barthou",Bordeaux,,France,33000,1.98,1,42
|
399,2013-11-03 00:00:00,1.98,1,42
|
||||||
400,2013-11-03 00:00:00,Porthaninkatu 9,Helsinki,,Finland,00530,1.98,1,44
|
400,2013-11-03 00:00:00,1.98,1,44
|
||||||
401,2013-11-04 00:00:00,3 Chatham Street,Dublin,Dublin,Ireland,,3.96,1,46
|
401,2013-11-04 00:00:00,3.96,1,46
|
||||||
402,2013-11-05 00:00:00,C/ San Bernardo 85,Madrid,,Spain,28015,5.94,1,50
|
402,2013-11-05 00:00:00,5.94,1,50
|
||||||
403,2013-11-08 00:00:00,307 Macacha Güemes,Buenos Aires,,Argentina,1106,8.91,1,56
|
403,2013-11-08 00:00:00,8.91,1,56
|
||||||
404,2013-11-13 00:00:00,Rilská 3174/6,Prague,,Czech Republic,14300,25.86,1,6
|
404,2013-11-13 00:00:00,25.86,1,6
|
||||||
405,2013-11-21 00:00:00,541 Del Medio Avenue,Mountain View,CA,USA,94040-111,0.99,1,20
|
405,2013-11-21 00:00:00,0.99,1,20
|
||||||
406,2013-12-04 00:00:00,801 W 4th Street,Reno,NV,USA,89503,1.98,1,21
|
406,2013-12-04 00:00:00,1.98,1,21
|
||||||
407,2013-12-04 00:00:00,69 Salem Street,Boston,MA,USA,2113,1.98,1,23
|
407,2013-12-04 00:00:00,1.98,1,23
|
||||||
408,2013-12-05 00:00:00,319 N. Frances Street,Madison,WI,USA,53703,3.96,1,25
|
408,2013-12-05 00:00:00,3.96,1,25
|
||||||
409,2013-12-06 00:00:00,796 Dundas Street West,Toronto,ON,Canada,M6J 1V1,5.94,1,29
|
409,2013-12-06 00:00:00,5.94,1,29
|
||||||
410,2013-12-09 00:00:00,"Rua dos Campeões Europeus de Viena, 4350",Porto,,Portugal,,8.91,1,35
|
410,2013-12-09 00:00:00,8.91,1,35
|
||||||
411,2013-12-14 00:00:00,Porthaninkatu 9,Helsinki,,Finland,00530,13.86,1,44
|
411,2013-12-14 00:00:00,13.86,1,44
|
||||||
412,2013-12-22 00:00:00,"12,Community Centre",Delhi,,India,110017,1.99,1,58
|
412,2013-12-22 00:00:00,1.99,1,58
|
||||||
|
|||||||
|
@@ -1,6 +0,0 @@
|
|||||||
ID,name
|
|
||||||
1,MPEG audio file
|
|
||||||
2,Protected AAC audio file
|
|
||||||
3,Protected MPEG-4 video file
|
|
||||||
4,Purchased AAC audio file
|
|
||||||
5,AAC audio file
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,27 +1,22 @@
|
|||||||
namespace sap.capire.media.store;
|
namespace sap.capire.media.store;
|
||||||
|
|
||||||
aspect Named {
|
aspect Named {
|
||||||
key ID : Integer default 1;
|
key ID : Integer;
|
||||||
name : String(120);
|
name : String(120);
|
||||||
}
|
}
|
||||||
|
|
||||||
aspect Person {
|
aspect Person {
|
||||||
key ID : Integer;
|
key ID : Integer;
|
||||||
lastName : String(20) default 'dummy';
|
lastName : String(20) default 'dummy';
|
||||||
firstName : String(40) default 'dummy';
|
firstName : String(40) default 'dummy';
|
||||||
city : String(40) default 'dummy';
|
city : String(40) default 'dummy';
|
||||||
state : String(40) default 'dummy';
|
address : String(70) default 'dummy';
|
||||||
address : String(70) default 'dummy';
|
country : String(40) default 'dummy';
|
||||||
country : String(40) default 'dummy';
|
phone : String(24) default 'dummy';
|
||||||
postalCode : String(10) default 123;
|
email : String(60) default 'dummy@email.com';
|
||||||
phone : String(24) default 'dummy';
|
password : String(500) default 'dummy';
|
||||||
fax : String(24) default 'dummy';
|
|
||||||
email : String(60) default 'dummy@email.com';
|
|
||||||
password : String(500) default 'dummy';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entity MediaTypes : Named {}
|
|
||||||
|
|
||||||
entity Genres {
|
entity Genres {
|
||||||
key ID : Integer;
|
key ID : Integer;
|
||||||
name : localized String;
|
name : localized String;
|
||||||
@@ -56,25 +51,19 @@ entity Employees : Person {
|
|||||||
}
|
}
|
||||||
|
|
||||||
entity Customers : Person {
|
entity Customers : Person {
|
||||||
company : String(80);
|
|
||||||
supportRep : Association to Employees;
|
supportRep : Association to Employees;
|
||||||
invoices : Association to many Invoices
|
invoices : Association to many Invoices
|
||||||
on invoices.customer = $self;
|
on invoices.customer = $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
entity Invoices {
|
entity Invoices {
|
||||||
key ID : Integer;
|
key ID : Integer;
|
||||||
customer : Association to Customers;
|
customer : Association to Customers;
|
||||||
invoiceDate : DateTime;
|
invoiceDate : DateTime;
|
||||||
billingAddress : String(70) default 'dummy';
|
total : Decimal(10, 2);
|
||||||
billingCity : String(40) default 'dummy';
|
invoiceItems : Composition of many InvoiceItems
|
||||||
billingState : String(40) default 'dummy';
|
on invoiceItems.invoice = $self;
|
||||||
billingCountry : String(40) default 'dummy';
|
status : Integer enum {
|
||||||
billingPostalCode : String(40) default 123;
|
|
||||||
total : Decimal(10, 2);
|
|
||||||
invoiceItems : Composition of many InvoiceItems
|
|
||||||
on invoiceItems.invoice = $self;
|
|
||||||
status : Integer enum {
|
|
||||||
submitted = 1;
|
submitted = 1;
|
||||||
canceled = -1;
|
canceled = -1;
|
||||||
} default 1;
|
} default 1;
|
||||||
@@ -92,12 +81,9 @@ entity Tracks {
|
|||||||
key ID : Integer;
|
key ID : Integer;
|
||||||
name : String(200);
|
name : String(200);
|
||||||
album : Association to Albums;
|
album : Association to Albums;
|
||||||
mediaType : Association to MediaTypes;
|
|
||||||
genre : Association to Genres;
|
genre : Association to Genres;
|
||||||
composer : String(220);
|
composer : String(220);
|
||||||
milliseconds : Integer default 230619;
|
unitPrice : Decimal(10, 2);
|
||||||
bytes : Integer default 3990994;
|
|
||||||
unitPrice : Decimal(10, 2) default 0.99;
|
|
||||||
virtual alreadyOrdered : Boolean;
|
virtual alreadyOrdered : Boolean;
|
||||||
|
|
||||||
// Two compositions below needed for cascade delete track
|
// Two compositions below needed for cascade delete track
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
},
|
},
|
||||||
"cds": {
|
"cds": {
|
||||||
"ACCESS_TOKEN_SECRET": "secret",
|
"ACCESS_TOKEN_SECRET": "secret",
|
||||||
|
"REFRESH_TOKEN_SECRET": "refresh-secret",
|
||||||
"requires": {
|
"requires": {
|
||||||
"db": {
|
"db": {
|
||||||
"kind": "hana"
|
"kind": "hana"
|
||||||
|
|||||||
@@ -2,28 +2,26 @@ const cds = require("@sap/cds");
|
|||||||
const jwt = require("jsonwebtoken");
|
const jwt = require("jsonwebtoken");
|
||||||
|
|
||||||
const { ACCESS_TOKEN_SECRET } = cds.env;
|
const { ACCESS_TOKEN_SECRET } = cds.env;
|
||||||
|
|
||||||
class MyUser extends cds.User {
|
class MyUser extends cds.User {
|
||||||
constructor(attr, roles, id) {
|
constructor(attr, roles, id) {
|
||||||
super({ attr, _roles: [...roles, "authenticated-user"], id });
|
super({ attr, _roles: [...roles], id });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = (req, res, next) => {
|
module.exports = (req, res, next) => {
|
||||||
const { authorization: authHeader } = req.headers;
|
const { authorization: authHeader } = req.headers;
|
||||||
const token = authHeader && authHeader.split(" ")[1];
|
const token = authHeader && authHeader.split(" ")[1];
|
||||||
if (token === null) {
|
|
||||||
return res.sendStatus(401);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const decodedUser = jwt.verify(token, ACCESS_TOKEN_SECRET);
|
const decodedUser = jwt.verify(token, ACCESS_TOKEN_SECRET);
|
||||||
req.user = new MyUser(
|
req.user = new MyUser(
|
||||||
{ ID: decodedUser.ID },
|
{ ID: decodedUser.ID },
|
||||||
decodedUser.roles,
|
[decodedUser.roles, "authenticated-user"],
|
||||||
decodedUser.email
|
decodedUser.email
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
req.user = new MyUser({}, ["anonymous"], "");
|
req.user = new cds.User();
|
||||||
} finally {
|
} finally {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,18 +31,29 @@ module.exports = async function () {
|
|||||||
const utcNowDateTime = moment().utc().format(UTC_DATE_TIME_FORMAT);
|
const utcNowDateTime = moment().utc().format(UTC_DATE_TIME_FORMAT);
|
||||||
|
|
||||||
const transaction = await db.tx(req);
|
const transaction = await db.tx(req);
|
||||||
|
|
||||||
|
let { ID: lastInvoiceId } = await transaction.run(
|
||||||
|
SELECT.one(Invoices).columns("ID").orderBy({ ID: "desc" })
|
||||||
|
);
|
||||||
|
|
||||||
|
let { ID: lastInvoiceItemId } = await transaction.run(
|
||||||
|
SELECT.one(InvoiceItems).columns("ID").orderBy({ ID: "desc" })
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
results: [{ lastID: invoiceID }],
|
results: [{ lastID: invoiceID }],
|
||||||
} = await transaction.run(
|
} = await transaction.run(
|
||||||
INSERT.into(Invoices)
|
INSERT.into(Invoices)
|
||||||
.columns("customer_ID", "total", "invoiceDate")
|
.columns("ID", "customer_ID", "total", "invoiceDate")
|
||||||
.values(customerId, total, utcNowDateTime)
|
.values(++lastInvoiceId, customerId, total, utcNowDateTime)
|
||||||
);
|
);
|
||||||
|
|
||||||
await transaction.run(
|
await transaction.run(
|
||||||
INSERT.into(InvoiceItems)
|
INSERT.into(InvoiceItems)
|
||||||
.columns("invoice_ID", "track_ID", "unitPrice")
|
.columns("ID", "invoice_ID", "track_ID", "unitPrice")
|
||||||
.rows(
|
.rows(
|
||||||
tracks.map(({ ID: trackID, unitPrice }) => [
|
tracks.map(({ ID: trackID, unitPrice }, index) => [
|
||||||
|
lastInvoiceItemId + index + 1,
|
||||||
invoiceID,
|
invoiceID,
|
||||||
trackID,
|
trackID,
|
||||||
unitPrice,
|
unitPrice,
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
using {sap.capire.media.store as my} from '../db/schema';
|
using {sap.capire.media.store as my} from '../db/schema';
|
||||||
|
|
||||||
service ManageStore @(requires : 'employee') {
|
service ManageStore @(requires : 'employee') {
|
||||||
entity Tracks as projection on my.Tracks;
|
entity Tracks as projection on my.Tracks;
|
||||||
entity Albums as projection on my.Albums;
|
entity Albums as projection on my.Albums;
|
||||||
entity Artists as projection on my.Artists;
|
entity Artists as projection on my.Artists;
|
||||||
/**
|
/**
|
||||||
* Below entities exposed due to errors when creating
|
* Below entities exposed due to errors when creating
|
||||||
* Tracks/Albums/Artists
|
* Tracks/Albums/Artists
|
||||||
*/
|
*/
|
||||||
entity MediaTypes as projection on my.MediaTypes;
|
entity Genres as projection on my.Genres;
|
||||||
entity Genres as projection on my.Genres;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,11 +15,22 @@ service Users {
|
|||||||
supportRep
|
supportRep
|
||||||
};
|
};
|
||||||
|
|
||||||
action login(email : String(111), password : String(200)) returns {
|
type AuthData {
|
||||||
roles : array of String(111);
|
accessToken : String(500);
|
||||||
token : String(500);
|
refreshToken : String(500);
|
||||||
email : String(500);
|
ID : Integer;
|
||||||
ID : Integer;
|
email : String(500);
|
||||||
|
roles : array of String(111);
|
||||||
|
};
|
||||||
|
|
||||||
|
action login(email : String(111), password : String(200)) returns AuthData;
|
||||||
|
|
||||||
|
action refreshTokens(refreshToken : String(500)) returns {
|
||||||
|
accessToken : String(500);
|
||||||
|
refreshToken : String(500);
|
||||||
|
ID : Integer;
|
||||||
|
email : String(500);
|
||||||
|
roles : array of String(111);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ const cds = require("@sap/cds");
|
|||||||
const jwt = require("jsonwebtoken");
|
const jwt = require("jsonwebtoken");
|
||||||
const bcrypt = require("bcryptjs");
|
const bcrypt = require("bcryptjs");
|
||||||
|
|
||||||
const { ACCESS_TOKEN_SECRET } = cds.env;
|
const { ACCESS_TOKEN_SECRET, REFRESH_TOKEN_SECRET } = cds.env;
|
||||||
const ACCESS_TOKEN_EXP_IN = "10m";
|
const ACCESS_TOKEN_EXP_IN = "10m";
|
||||||
|
const REFRESH_TOKEN_EXPIRES_IN = "20m";
|
||||||
|
|
||||||
const comparePasswords = async (password, hashedPassword) => {
|
const comparePasswords = async (password, hashedPassword) => {
|
||||||
return new Promise((resolve, reject) =>
|
return new Promise((resolve, reject) =>
|
||||||
@@ -17,10 +18,30 @@ const comparePasswords = async (password, hashedPassword) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createTokens = (email, ID, roles) => {
|
||||||
|
const accessToken = jwt.sign({ email, ID, roles }, ACCESS_TOKEN_SECRET, {
|
||||||
|
expiresIn: ACCESS_TOKEN_EXP_IN,
|
||||||
|
});
|
||||||
|
const refreshToken = jwt.sign({ email, ID, roles }, REFRESH_TOKEN_SECRET, {
|
||||||
|
expiresIn: REFRESH_TOKEN_EXPIRES_IN,
|
||||||
|
});
|
||||||
|
return [accessToken, refreshToken];
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = async function () {
|
module.exports = async function () {
|
||||||
const db = await cds.connect.to("db");
|
const db = await cds.connect.to("db");
|
||||||
const { Employees, Customers } = db.entities;
|
const { Employees, Customers } = db.entities;
|
||||||
|
|
||||||
|
async function getUser(email) {
|
||||||
|
let userFromDb = await db.run(SELECT.one(Employees).where({ email }));
|
||||||
|
let roles = ["employee"];
|
||||||
|
if (!userFromDb) {
|
||||||
|
userFromDb = await db.run(SELECT.one(Customers).where({ email }));
|
||||||
|
roles = ["customer"];
|
||||||
|
}
|
||||||
|
return Object.assign({}, userFromDb, { roles });
|
||||||
|
}
|
||||||
|
|
||||||
this.before("UPDATE", "*", async (req) => {
|
this.before("UPDATE", "*", async (req) => {
|
||||||
req.query = req.query.where({ ID: req.user.attr.ID });
|
req.query = req.query.where({ ID: req.user.attr.ID });
|
||||||
});
|
});
|
||||||
@@ -32,35 +53,58 @@ module.exports = async function () {
|
|||||||
this.on("login", async (req) => {
|
this.on("login", async (req) => {
|
||||||
const { email, password } = req.data;
|
const { email, password } = req.data;
|
||||||
|
|
||||||
let userFromDb = await db.run(SELECT.one(Employees).where({ email }));
|
const userFromDb = await getUser(email);
|
||||||
let roles = ["employee"];
|
|
||||||
if (!userFromDb) {
|
|
||||||
userFromDb = await db.run(SELECT.one(Customers).where({ email }));
|
|
||||||
roles = ["customer"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!userFromDb) {
|
if (!userFromDb) {
|
||||||
req.reject(401);
|
req.reject(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await comparePasswords(password, userFromDb.password);
|
await comparePasswords(password, userFromDb.password);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
req.reject(401);
|
req.reject(401);
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = jwt.sign(
|
const [accessToken, refreshToken] = createTokens(
|
||||||
{ email, ID: userFromDb.ID, roles },
|
userFromDb.email,
|
||||||
ACCESS_TOKEN_SECRET,
|
userFromDb.ID,
|
||||||
{
|
userFromDb.roles
|
||||||
expiresIn: ACCESS_TOKEN_EXP_IN,
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
token,
|
accessToken,
|
||||||
roles,
|
refreshToken,
|
||||||
email: userFromDb.email,
|
|
||||||
ID: userFromDb.ID,
|
ID: userFromDb.ID,
|
||||||
|
email: userFromDb.email,
|
||||||
|
roles: userFromDb.roles,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on("refreshTokens", async (req) => {
|
||||||
|
let decodedUser;
|
||||||
|
try {
|
||||||
|
const { refreshToken } = req.data;
|
||||||
|
decodedUser = jwt.verify(refreshToken, REFRESH_TOKEN_SECRET);
|
||||||
|
} catch (error) {
|
||||||
|
req.reject(401);
|
||||||
|
}
|
||||||
|
|
||||||
|
const userFromDb = await getUser(decodedUser.email);
|
||||||
|
if (!userFromDb) {
|
||||||
|
req.reject(401);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [accessToken, refreshToken] = createTokens(
|
||||||
|
userFromDb.email,
|
||||||
|
userFromDb.ID,
|
||||||
|
userFromDb.roles
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
accessToken,
|
||||||
|
refreshToken,
|
||||||
|
ID: userFromDb.ID,
|
||||||
|
email: userFromDb.email,
|
||||||
|
roles: userFromDb.roles,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user