Merge pull request #28 from AAMasters/develop

One issue fix on client and code improvements on server
This commit is contained in:
z@tOr authored and GitHub committed 2018-11-15 09:16:32 -03:00
commit d45195f10f
93 files changed
+1249 -16361

No files matched your search

+4 -3
View File
@@ -1,6 +1,7 @@
client/node_modules/*
server/node_modules/*
client/src/auth/Auth0.js
server/auth/Auth0.js
server/models/MongoDB.js
server/.env
client/package-lock.json
server/package-lock.json
+46
View File
@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at feedback at advancedalgos dot org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
+45
View File
@@ -0,0 +1,45 @@
# Contributing
We are thrilled you are interested in contributing to this repository. Your help may be essential to the project's success and we want you in!
Advanced Algos LTD is a startup, currently at a very early stage. Although this repository is not open source software yet, we do welcome contributions from the community.
Contributions are deemed _voluntary work_. There might be incentives in place for certain kinds of contributions. Contact us for more information in this regards.
In any case, contributors agree to provide an express grant of patent rights for their contributions. Submitting Pull Requests to this repository represents an express agreement with the terms of our Balanced Contributor Intellectual Property Agreement. This agreement is a direct implementation of GitHub's [Balanced Employee Intellectual Property Agreement 1.0.1](https://github.com/github/balanced-employee-ip-agreement/blob/master/Balanced_Employee_IP_Agreement.md).
# Balanced Contributor Intellectual Property Agreement 1.0.1
This BALANCED CONTRIBUTOR INTELLECTUAL PROPERTY AGREEMENT is between person or team submitting Pull Requests to this repository and Advanced Algos LTD ("Company").
**What is this?** This is the Company's Intellectual Property Agreement ("Agreement"). If you've worked in the technology space before, there's a good chance that you've run across one or more of these in the past. This document is the official, entire and exclusive agreement on what intellectual property ("IP") is yours, and what belongs to the Company.
**Why is this?** The Company needs to be clear on what IP it owns and has rights to. Its customers, contributors, and investors depend on the Company having the legal rights to the products and services it is providing so that the Company can continue operating and doing business.
The Company also believes that it's important to be clear on what it doesn't own. The Company doesn't want you looking over your shoulder every time you work on something personal or worrying that the Company will someday seize your open source non-lethal mousetrap simulation software. In other words, the Company isn't interested in appropriating your personal projects.
**Read this.** Please read this document and be sure you understand it before you submit any Pull Requests. Due to legal risk and corporate obligations, the Company cannot, by and large, negotiate its terms. If you feel you have a particular circumstance that keeps you from signing, please let the Company's legal department ("Legal") know. And, of course, you're always free and encouraged to get your own legal counsel to explain anything you're not clear on.
Cool? Then, by submitting your first Pull Request, and as a condition of your contribution, you agree to the following:
1. **What the Company owns.** The Company owns any IP ("Company IP") that you create, or help create _as its contributor_, but only if it meets one or more of these additional conditions: The IP was (i) related to an existing or prospective Company product or service at the time you developed, invented, or created it, (ii) developed for use by the Company, or (iii) developed or promoted with existing Company IP or with the Company's endorsement. You hereby grant and assign, and will grant and assign, to the Company all rights and interests in all Company IP.
"Company IP" includes concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, and works of authorship.
2. **What the Company doesn't own.** If you create IP that doesn't fit into one of the categories listed above, the Company doesn't own it. In other words, the Company doesn't own concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, or works of authorship that you develop, invent, or create that do not meet any of the conditions in Section 1.
3. **Contribution of your IP to Company projects.** If you include your own IP – such as IP you created prior to working for the Company – into a Company product or service, it's still yours, of course, but you grant the Company a non-exclusive, irrevocable, fully paid-up, royalty-free, perpetual, sublicensable, transferable, worldwide license to use it without restriction in any way or implementation, in modified form, or as is, by itself, or incorporated into another product or service ("License"). If you include your name in any project over which the Company would have rights under this Agreement, such as in a copyright notice or a comment in code or documentation, then the License covers the rights associated with that use of your name as well.
4. **Your contributions to non-Company projects.** The Company recognizes that you may be engaged in work that requires you to submit IP to entities other than the Company, such as open source projects used by the Company. Please make sure that Legal is aware of what you're working on so that Legal can help with any licensing issues. If any project asks you to sign a contribution agreement, you should check with Legal before doing so. These agreements may be legally binding on the Company and so should be run through Legal first.
5. **Voluntary Works** All Company IP that you are involved with or create as part of your work for the Company is voluntary work which does not require compensation. There might be incentives in place for certain kinds of contributions. Feel free to contact the Company to learn more.
6. **No conflicts.** You agree that you don't have any outstanding agreements or obligations that conflict with those in this Agreement, and that you won't enter into conflicting agreements in the future.
7. **IP protection.** The Company might someday need to show the work that went into the development of IP that it uses or has used, or to make government filings to establish that it owns the IP or has rights over it. To help in those situations, you agree not to destroy any records you maintain relating to the development of any Company IP or IP under License (together, "All IP"), and, if the Company asks, to provide those records to the Company. You agree to help the Company secure and defend its rights in All IP. For your help the Company will compensate you at a reasonable rate. If the Company is unable to secure your help, you authorize the Company to act on your behalf (as your agent and attorney-in-fact) in securing all rights related to All IP.
8. **Confidentiality.** As an contributor or contractor of the Company, you will have access to sensitive confidential information that is important to the Company's business. You are responsible for keeping this information confidential, including after you end your work for the Company.
"Confidential Information" includes non-public technical details about our products or services, financial information, business strategies and forecasts, customer data, or any other information, data or know-how that is valuable to the Company because it is not publicly known.
The Company's Confidential Information is sensitive and we expect that you'll treat it as such. You agree to only use the Company's Confidential Information for the purpose of performing your contribution and for the benefit of the Company. You will do your best to keep Confidential Information secret. If you are not sure if something is Confidential Information, you should assume that it is, until you can confirm otherwise.
+42
View File
@@ -0,0 +1,42 @@
COPYRIGHT NOTICE
© Copyright 2018 Advanced Algos LTD.
LICENSE NOTICE
Advanced Algos LTD. is a startup, currently at a very early stage. Because certain aspects of
the business are still not clearly defined, we have chosen to --temporarily-- grant a
restrictive license for the use of this repository, until those business aspects are clarified
and a proper open source license can be granted.
Advanced Algos LTD. is publishing the code of this software for several reasons. However,
it shall not be considered free software yet. Advanced Algos LTD. is a for-profit company
in the crypto space and this module is still proprietary software.
The reasons for opening up the code of this module at this stage are the following:
* We believe that transparency is paramount to achieving our goals, so we want everyone
to be able to understand what this module does and how. Opening up the code of this module
allows anyone to take a close look.
* We welcome contributions from the community. Contributions are regarded as voluntary work.
There may be incentives in place for certain kinds of contributions. Contact us to learn more.
Contributors agree to provide an express grant of patent rights for their contributions.
LICENSE WORDING
Advanced Algos LTD. grants a limited license for the following uses:
1. CODE REVIEW AND AUDITS. You are granted permission to clone this repository to analyze,
review or audit the code.
2. COLLABORATING WITH ADVANCED ALGOS LTD. You are granted permission to fork this repository
with the sole purpose of correcting bugs and developing functionality in agreement with
Advanced Algos LTD. By contributing to this repository you explicitely agree to the terms
detailed in CONTRIBUTING.MD.
PLEASE SEE CONTRIBUTING.MD FOR MORE DETAILS ON THE IMPLICATIONS SURROUNDING YOUR CONTRIBUTIONS TO THIS REPOSITORY.
+1 -66
View File
@@ -1,67 +1,2 @@
# ModuleUsers
## Component Hierarchy
App.js
|
|- NavBar
| |
| |- LoggedInUser
| | |
| | |- LoggedInUserMenu
| | | |
| | | |- Menu 1 - Link to User
| | | |
| | | |- Menu 2 - Link to Logout
| |
|- Switch
| |
| |- User
| | |
| | |- UserTabs
| | | |
| | | |- Tab 1 - ProfileSheet
| | | |
| | | |- Tab 2 - ManageImages
| |
| |- Browse
| | |
| | |- UserLists
| |
| |- Search
| |
| |- About
| |
| |- Contact
| |
| |- Logout
| |
| |- Callback
| |
|- Footer
## Known Improvements
1. Remove the relationship to users, since it is not needed.
const RoleType = new GraphQLObjectType({
name: 'Role',
fields: () => ({
id: { type: GraphQLID},
name: {type: GraphQLString},
users: {
type: new GraphQLList(UserType),
resolve(parent, args) {
return User.find({roleId: parent.id});
}
}
})
});
2. Roles should be an Enum Type.
Since roles just have a name field, I think we should use the ENUM type... https://graphql.org/learn/schema/#enumeration-types
They would just be resolved in Mongoose/MongoDB as strings and we would validate specifcially to those strings.
Unless there's going to be many types of roles in the future.
+1
View File
@@ -0,0 +1 @@
build/
+46
View File
@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at feedback at advancedalgos dot org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
+45
View File
@@ -0,0 +1,45 @@
# Contributing
We are thrilled you are interested in contributing to this repository. Your help may be essential to the project's success and we want you in!
Advanced Algos LTD is a startup, currently at a very early stage. Although this repository is not open source software yet, we do welcome contributions from the community.
Contributions are deemed _voluntary work_. There might be incentives in place for certain kinds of contributions. Contact us for more information in this regards.
In any case, contributors agree to provide an express grant of patent rights for their contributions. Submitting Pull Requests to this repository represents an express agreement with the terms of our Balanced Contributor Intellectual Property Agreement. This agreement is a direct implementation of GitHub's [Balanced Employee Intellectual Property Agreement 1.0.1](https://github.com/github/balanced-employee-ip-agreement/blob/master/Balanced_Employee_IP_Agreement.md).
# Balanced Contributor Intellectual Property Agreement 1.0.1
This BALANCED CONTRIBUTOR INTELLECTUAL PROPERTY AGREEMENT is between person or team submitting Pull Requests to this repository and Advanced Algos LTD ("Company").
**What is this?** This is the Company's Intellectual Property Agreement ("Agreement"). If you've worked in the technology space before, there's a good chance that you've run across one or more of these in the past. This document is the official, entire and exclusive agreement on what intellectual property ("IP") is yours, and what belongs to the Company.
**Why is this?** The Company needs to be clear on what IP it owns and has rights to. Its customers, contributors, and investors depend on the Company having the legal rights to the products and services it is providing so that the Company can continue operating and doing business.
The Company also believes that it's important to be clear on what it doesn't own. The Company doesn't want you looking over your shoulder every time you work on something personal or worrying that the Company will someday seize your open source non-lethal mousetrap simulation software. In other words, the Company isn't interested in appropriating your personal projects.
**Read this.** Please read this document and be sure you understand it before you submit any Pull Requests. Due to legal risk and corporate obligations, the Company cannot, by and large, negotiate its terms. If you feel you have a particular circumstance that keeps you from signing, please let the Company's legal department ("Legal") know. And, of course, you're always free and encouraged to get your own legal counsel to explain anything you're not clear on.
Cool? Then, by submitting your first Pull Request, and as a condition of your contribution, you agree to the following:
1. **What the Company owns.** The Company owns any IP ("Company IP") that you create, or help create _as its contributor_, but only if it meets one or more of these additional conditions: The IP was (i) related to an existing or prospective Company product or service at the time you developed, invented, or created it, (ii) developed for use by the Company, or (iii) developed or promoted with existing Company IP or with the Company's endorsement. You hereby grant and assign, and will grant and assign, to the Company all rights and interests in all Company IP.
"Company IP" includes concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, and works of authorship.
2. **What the Company doesn't own.** If you create IP that doesn't fit into one of the categories listed above, the Company doesn't own it. In other words, the Company doesn't own concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, or works of authorship that you develop, invent, or create that do not meet any of the conditions in Section 1.
3. **Contribution of your IP to Company projects.** If you include your own IP – such as IP you created prior to working for the Company – into a Company product or service, it's still yours, of course, but you grant the Company a non-exclusive, irrevocable, fully paid-up, royalty-free, perpetual, sublicensable, transferable, worldwide license to use it without restriction in any way or implementation, in modified form, or as is, by itself, or incorporated into another product or service ("License"). If you include your name in any project over which the Company would have rights under this Agreement, such as in a copyright notice or a comment in code or documentation, then the License covers the rights associated with that use of your name as well.
4. **Your contributions to non-Company projects.** The Company recognizes that you may be engaged in work that requires you to submit IP to entities other than the Company, such as open source projects used by the Company. Please make sure that Legal is aware of what you're working on so that Legal can help with any licensing issues. If any project asks you to sign a contribution agreement, you should check with Legal before doing so. These agreements may be legally binding on the Company and so should be run through Legal first.
5. **Voluntary Works** All Company IP that you are involved with or create as part of your work for the Company is voluntary work which does not require compensation. There might be incentives in place for certain kinds of contributions. Feel free to contact the Company to learn more.
6. **No conflicts.** You agree that you don't have any outstanding agreements or obligations that conflict with those in this Agreement, and that you won't enter into conflicting agreements in the future.
7. **IP protection.** The Company might someday need to show the work that went into the development of IP that it uses or has used, or to make government filings to establish that it owns the IP or has rights over it. To help in those situations, you agree not to destroy any records you maintain relating to the development of any Company IP or IP under License (together, "All IP"), and, if the Company asks, to provide those records to the Company. You agree to help the Company secure and defend its rights in All IP. For your help the Company will compensate you at a reasonable rate. If the Company is unable to secure your help, you authorize the Company to act on your behalf (as your agent and attorney-in-fact) in securing all rights related to All IP.
8. **Confidentiality.** As an contributor or contractor of the Company, you will have access to sensitive confidential information that is important to the Company's business. You are responsible for keeping this information confidential, including after you end your work for the Company.
"Confidential Information" includes non-public technical details about our products or services, financial information, business strategies and forecasts, customer data, or any other information, data or know-how that is valuable to the Company because it is not publicly known.
The Company's Confidential Information is sensitive and we expect that you'll treat it as such. You agree to only use the Company's Confidential Information for the purpose of performing your contribution and for the benefit of the Company. You will do your best to keep Confidential Information secret. If you are not sure if something is Confidential Information, you should assume that it is, until you can confirm otherwise.
+42
View File
@@ -0,0 +1,42 @@
COPYRIGHT NOTICE
© Copyright 2018 Advanced Algos LTD.
LICENSE NOTICE
Advanced Algos LTD. is a startup, currently at a very early stage. Because certain aspects of
the business are still not clearly defined, we have chosen to --temporarily-- grant a
restrictive license for the use of this repository, until those business aspects are clarified
and a proper open source license can be granted.
Advanced Algos LTD. is publishing the code of this software for several reasons. However,
it shall not be considered free software yet. Advanced Algos LTD. is a for-profit company
in the crypto space and this module is still proprietary software.
The reasons for opening up the code of this module at this stage are the following:
* We believe that transparency is paramount to achieving our goals, so we want everyone
to be able to understand what this module does and how. Opening up the code of this module
allows anyone to take a close look.
* We welcome contributions from the community. Contributions are regarded as voluntary work.
There may be incentives in place for certain kinds of contributions. Contact us to learn more.
Contributors agree to provide an express grant of patent rights for their contributions.
LICENSE WORDING
Advanced Algos LTD. grants a limited license for the following uses:
1. CODE REVIEW AND AUDITS. You are granted permission to clone this repository to analyze,
review or audit the code.
2. COLLABORATING WITH ADVANCED ALGOS LTD. You are granted permission to fork this repository
with the sole purpose of correcting bugs and developing functionality in agreement with
Advanced Algos LTD. By contributing to this repository you explicitely agree to the terms
detailed in CONTRIBUTING.MD.
PLEASE SEE CONTRIBUTING.MD FOR MORE DETAILS ON THE IMPLICATIONS SURROUNDING YOUR CONTRIBUTIONS TO THIS REPOSITORY.
+41
View File
@@ -0,0 +1,41 @@
import { createLogger, format, transports } from 'winston'
const { combine, timestamp, simple } = format
import { inspect } from 'util'
const options = {
file: {
level: 'info',
filename: '../logs/app.log',
handleExceptions: true,
json: true,
maxsize: 5242880, // 5MB
maxFiles: 5,
colorize: false,
timestamp: true
},
console: {
level: 'debug',
handleExceptions: true,
json: false,
colorize: true,
timestamp: true
}
}
const logger = createLogger({
level: 'info',
format: format.combine(
format.colorize(),
format.timestamp({ format: 'YY/MM/DD HH:mm' }),
format.printf(
info => `${info.timestamp} - ${info.level}: ${JSON.parse(JSON.stringify(inspect(info.message)))}`
)
),
transports: [
new transports.File(options.file),
new transports.Console(options.console)
],
exitOnError: false // do not exit on handled exceptions
})
export default logger
-12650
View File
File diff suppressed because it is too large. Load diff
+17 -22
View File
@@ -1,34 +1,29 @@
{
"name": "client",
"version": "0.1.0",
"private": true,
"name": "@advancedalgos/users-client",
"description": "Advanced Algos Users client-side web app",
"version": "0.0.24",
"main": "src/index.js",
"dependencies": {
"@material-ui/core": "^3.0.2",
"@material-ui/core": "^3.2.0",
"@material-ui/icons": "^3.0.1",
"apollo-cache-inmemory": "^1.2.9",
"apollo-client": "^2.4.1",
"apollo-link": "^1.2.2",
"apollo-link-context": "^1.0.8",
"apollo-link-error": "^1.1.0",
"apollo-link-http": "^1.5.4",
"auth0-lock": "^11.9.0",
"filestack-js": "^1.5.1",
"filestack-react": "^2.0.0",
"graphql": "^14.0.0",
"graphql-tag": "^2.9.2",
"react": "^16.4.2",
"react-apollo": "^2.1.11",
"react-dom": "^16.4.2",
"react-easy-chart": "^1.0.0",
"react-redux": "^5.0.7",
"react": "^16.6.1",
"react-apollo": "^2.2.4",
"react-dom": "^16.6.1",
"react-router-dom": "^4.3.1",
"react-scripts": "1.1.5",
"redux": "^4.0.0"
"react-scripts": "^2.0.4",
"graphql": "^14.0.2",
"graphql-tag": "^2.10.0",
"prop-types": "^15.6.2",
"recompose": "^0.30.0",
"apollo-client": "2.4.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"devDependencies": {
"react-hot-loader": "^4.3.11"
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 758 B

-57
View File
@@ -1,57 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<style>
body {
display: flex;
min-height: 100vh;
flex-direction: column;
}
main {
flex: 1 0 auto;
}
</style>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link href="https://fonts.googleapis.com/css?family=Saira+Condensed:300,600|Saira:300,600&amp;subset=latin-ext,vietnamese" rel="stylesheet">
<!-- font awesome -->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.13/css/all.css" integrity="sha384-DNOHZ68U8hZfKXOrtjWvjxusGo9WQnrNx2sqG0tfsghAvtVlRW3tvkXWZh58N9jp" crossorigin="anonymous">
<!-- default font of Material-UI -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">
<!-- In order to use the font Icon component of Material-UI -->
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<title>Advanced Algos - Users Module</title>
<!-- Material-UI is developed mobile first -->
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"
/>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
</body>
</html>
-15
View File
@@ -1,15 +0,0 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
-109
View File
@@ -1,109 +0,0 @@
import React, { Component } from 'react'
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloProvider } from 'react-apollo'
import { ApolloLink } from 'apollo-link'
import { HttpLink } from 'apollo-link-http'
import { onError } from 'apollo-link-error'
import { setContext } from 'apollo-link-context'
import { Route, BrowserRouter, Switch } from 'react-router-dom'
// Material UI
import { MuiThemeProvider } from '@material-ui/core/styles'
import theme from './theme'
// Components
import NavBar from './components/NavBar'
import Home from './components/Home'
import User from './components/User'
import Browse from './components/Browse'
import Search from './components/Search'
import About from './components/About'
import Contact from './components/Contact'
import Logout from './components/Logout'
import Post from './components/Post'
// import Footer from './components/Footer'
import Callback from './components/Callback'
import Auth from './auth/Auth'
import {
// NavBar,
Footer
} from './views'
// Apollo Client Setup
const httpLink = new HttpLink({ uri: 'http://localhost:4000/graphql', changeOrigin: true })
const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.map(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`,
),
)
}
if (networkError) console.log(`[Network error]: ${networkError}`)
})
const authLink = setContext((_, { headers }) => {
// get the authentication token from local storage if it exists
const token = localStorage.getItem('access_token')
// return the headers to the context so httpLink can read them
return {
headers: {
...headers,
Authorization: token ? `Bearer ${token}` : ``
}
}
})
export const client = new ApolloClient({
link: ApolloLink.from([errorLink, authLink, httpLink]),
cache: new InMemoryCache()
})
/*
export const client = new ApolloClient({
uri:'http://localhost:4000/graphql'
})
*/
export const auth = new Auth(result => console.log('auth result', result), client)
class App extends Component {
render () {
return (
<BrowserRouter>
<ApolloProvider client={client}>
<MuiThemeProvider theme={theme}>
<div className='App'>
<NavBar />
<Switch>
<Route exact path='/' component={Home} />
<Route path='/user' component={User} />
<Route path='/browse' component={Browse} />
<Route path='/search' component={Search} />
<Route path='/about' component={About} />
<Route path='/contact' component={Contact} />
<Route path='/logout' component={Logout} />
<Route path='/:post_id' component={Post} />
<Route path='/callback' render={(props) => {
auth.handleAuthentication(props)
return <Callback {...props} />
}} />
</Switch>
<Footer />
</div>
</MuiThemeProvider>
</ApolloProvider>
</BrowserRouter>
)
}
}
export default App
-6
View File
@@ -1,6 +0,0 @@
export const deletePost = (id) => {
return {
type: 'DELETE_POST',
id
}
}
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 120 24"><defs><style>.cls-1,.cls-3{fill:none;}.cls-2{clip-path:url(#clip-path);}.cls-3{stroke:#2a96ff;stroke-miterlimit:10;stroke-width:0.5px;}.cls-4{fill:#fff;}.cls-5{fill:#e3493c;}</style><clipPath id="clip-path"><rect class="cls-1" x="272.54" y="79.59" width="600" height="600"/></clipPath></defs><title>aa-logo-dark</title><g id="Layer_1" data-name="Layer 1"><g class="cls-2"><circle class="cls-3" cx="338.14" cy="263.28" r="277.97"/></g></g><g id="Layer_4" data-name="Layer 4"><path class="cls-4" d="M27.67,15.74l-.19-1.58H26.29l-.2,1.58H24.51L25.7,7.79h2.39l1.19,8Zm-.75-6.39h-.08l-.4,3.41h.89Z"/><path class="cls-4" d="M32.15,7.79h1.93a2.39,2.39,0,0,1,1.46.35,1.68,1.68,0,0,1,.54,1.11,21,21,0,0,1,.1,2.52,20.93,20.93,0,0,1-.1,2.51,1.68,1.68,0,0,1-.54,1.11,2.39,2.39,0,0,1-1.46.35H32.15Zm1.93,6.51a.46.46,0,0,0,.37-.12,1.19,1.19,0,0,0,.13-.6c0-.32,0-.93,0-1.81s0-1.5,0-1.82a1.19,1.19,0,0,0-.13-.6.46.46,0,0,0-.37-.12h-.36V14.3Z"/><path class="cls-4" d="M39.94,15.74,38.87,7.79h1.59l.66,6.31h.12l.61-6.31h1.57l-1.07,8Z"/><path class="cls-4" d="M48.8,15.74l-.19-1.58H47.42l-.2,1.58H45.64l1.19-7.95h2.39l1.19,8Zm-.75-6.39H48l-.4,3.41h.89Z"/><path class="cls-4" d="M56.06,15.74l-1.23-4h0v4h-1.5V7.79h1.47l1.13,3.61h.06V7.79h1.51v8Z"/><path class="cls-4" d="M63.14,15.77a3.11,3.11,0,0,1-.59.06,2.06,2.06,0,0,1-1.36-.37,1.94,1.94,0,0,1-.58-1.19,17.1,17.1,0,0,1-.13-2.5,14.22,14.22,0,0,1,.15-2.5,1.94,1.94,0,0,1,.58-1.2,2,2,0,0,1,1.34-.37,4.21,4.21,0,0,1,.62,0,1.86,1.86,0,0,1,.45.12V9.2a5.77,5.77,0,0,0-.78-.06.77.77,0,0,0-.55.15,1.22,1.22,0,0,0-.18.64c0,.33,0,.94,0,1.84s0,1.5,0,1.83a1.22,1.22,0,0,0,.18.64.77.77,0,0,0,.55.15,4.74,4.74,0,0,0,.8-.06v1.29A1.56,1.56,0,0,1,63.14,15.77Z"/><path class="cls-4" d="M66.59,15.74V7.79h3.19V9.23h-1.6V11h1.41v1.45H68.18V14.3h1.6v1.44Z"/><path class="cls-4" d="M72.79,7.79h1.92a2.4,2.4,0,0,1,1.47.35,1.67,1.67,0,0,1,.53,1.11,20.46,20.46,0,0,1,.11,2.52,20.38,20.38,0,0,1-.11,2.51,1.67,1.67,0,0,1-.53,1.11,2.4,2.4,0,0,1-1.47.35H72.79Zm1.92,6.51a.48.48,0,0,0,.38-.12,1.19,1.19,0,0,0,.13-.6c0-.32,0-.93,0-1.81s0-1.5,0-1.82a1.19,1.19,0,0,0-.13-.6.48.48,0,0,0-.38-.12h-.35V14.3Z"/><path class="cls-5" d="M85.6,15.74l-.91-2.31H80.93L80,15.74h-.76l3.11-7.95h.89l3.12,8ZM82.84,8.66h-.06l-1.61,4.08h3.27Z"/><path class="cls-5" d="M88.44,15.74V7.79h.74V15H93v.72Z"/><path class="cls-5" d="M97.86,12.24v-.68h2.7v4c-.37.06-.8.12-1.26.16s-.87.06-1.22.06a5.68,5.68,0,0,1-2.14-.3A1.71,1.71,0,0,1,95,14.4a9.76,9.76,0,0,1-.26-2.63A9.85,9.85,0,0,1,95,9.13,1.71,1.71,0,0,1,96,8a5.91,5.91,0,0,1,2.13-.29c.38,0,.81,0,1.27.06s.86.1,1.18.16v.66a13.61,13.61,0,0,0-2-.19,8.76,8.76,0,0,0-2,.16,1.21,1.21,0,0,0-.79.85,8.45,8.45,0,0,0-.23,2.37A10.48,10.48,0,0,0,95.66,14a1.27,1.27,0,0,0,.7.91,4.41,4.41,0,0,0,1.72.24l.9,0c.35,0,.64,0,.87-.09V12.24Z"/><path class="cls-5" d="M103.84,15.54a1.48,1.48,0,0,1-.83-1.08,13.91,13.91,0,0,1-.17-2.69,14,14,0,0,1,.17-2.7A1.48,1.48,0,0,1,103.84,8a6,6,0,0,1,2.21-.29,5.94,5.94,0,0,1,2.2.29,1.46,1.46,0,0,1,.83,1.08,13.75,13.75,0,0,1,.18,2.7,13.7,13.7,0,0,1-.18,2.69,1.46,1.46,0,0,1-.83,1.08,5.94,5.94,0,0,1-2.2.29A6,6,0,0,1,103.84,15.54Zm3.93-.57a1,1,0,0,0,.61-.81,13.62,13.62,0,0,0,.14-2.39,13.68,13.68,0,0,0-.14-2.4,1,1,0,0,0-.61-.81,8.84,8.84,0,0,0-3.45,0,1,1,0,0,0-.6.81,12.47,12.47,0,0,0-.15,2.4,12.42,12.42,0,0,0,.15,2.39,1,1,0,0,0,.6.81,8.84,8.84,0,0,0,3.45,0Z"/><path class="cls-5" d="M112.94,15.79c-.5,0-.94-.06-1.31-.11V15l1.33.1c.48,0,.88.05,1.2.05a8.75,8.75,0,0,0,1-.05,1.78,1.78,0,0,0,.65-.22.68.68,0,0,0,.35-.47,3.13,3.13,0,0,0,.09-.83,4.54,4.54,0,0,0-.06-.9.57.57,0,0,0-.31-.37,3.72,3.72,0,0,0-.88-.18l-2-.22a2.08,2.08,0,0,1-1.06-.32,1.18,1.18,0,0,1-.44-.64,5,5,0,0,1-.09-1.07,2.57,2.57,0,0,1,.3-1.38,1.56,1.56,0,0,1,.9-.63,6.12,6.12,0,0,1,1.59-.16c.45,0,.9,0,1.35,0s.81.08,1.07.13v.66c-.31,0-.68-.07-1.11-.1s-.83,0-1.19,0a6.52,6.52,0,0,0-1.1.07,1.88,1.88,0,0,0-.66.22.73.73,0,0,0-.33.44,2.52,2.52,0,0,0-.08.75,2.94,2.94,0,0,0,.07.77.61.61,0,0,0,.29.36,2.05,2.05,0,0,0,.69.16l2,.21a4.86,4.86,0,0,1,1.17.24,1,1,0,0,1,.55.63,4.24,4.24,0,0,1,.13,1.27,3,3,0,0,1-.31,1.54,1.36,1.36,0,0,1-.85.64,5.78,5.78,0,0,1-1.47.14C113.93,15.83,113.45,15.82,112.94,15.79Z"/><path class="cls-5" d="M11.36,13.89a7.43,7.43,0,0,1,2.52.4c.82.58,2,.89,2.5.3s0-1.61-.79-2.38a7.64,7.64,0,0,1-.93-2.35c.11-1-.23-2.23-1-2.35s-1.47,1-1.65,1.88a7.38,7.38,0,0,1-1.61,2c-.9.42-1.77,1.3-1.49,2S10.48,14.16,11.36,13.89Z"/><path class="cls-5" d="M14.75,3.42C16,3.47,16.49,6,16.29,7.91a26.16,26.16,0,0,0,1.64,4.69,1.88,1.88,0,0,0,.79.79,10.55,10.55,0,0,1-.84-5c.79-2.19.44-5.15-.75-5.84a2.71,2.71,0,0,0-3.68,1.2A1.8,1.8,0,0,1,14.75,3.42Z"/><path class="cls-5" d="M5,14C4.4,13,6.3,11.26,8.09,10.45,8.66,10.2,11,7.2,11.33,6.7a2,2,0,0,0,.29-1.09A10.62,10.62,0,0,1,7.68,8.86C5.38,9.27,3,11.05,3,12.42A2.71,2.71,0,0,0,5.87,15,1.88,1.88,0,0,1,5,14Z"/><path class="cls-5" d="M19.12,17.42c-.66,1-3.07.23-4.67-.92a25.88,25.88,0,0,0-4.87-.92,1.79,1.79,0,0,0-1.08.29,10.37,10.37,0,0,1,4.Line truncated

Before

Width:  |  Height:  |  Size: 5.0 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 98 140"><defs><style>.cls-1,.cls-3{fill:none;}.cls-2{clip-path:url(#clip-path);}.cls-3{stroke:#2a96ff;stroke-miterlimit:10;stroke-width:0.5px;}.cls-4{fill:#4d4d4d;}.cls-5{fill:#e3493c;}</style><clipPath id="clip-path"><rect class="cls-1" x="144.54" y="59.59" width="600" height="600"/></clipPath></defs><title>aa-logo-vert</title><g id="Layer_1" data-name="Layer 1"><g class="cls-2"><circle class="cls-3" cx="210.14" cy="243.28" r="277.97"/></g></g><g id="Layer_4" data-name="Layer 4"><path class="cls-4" d="M11.27,108.29l-.38-3H8.62l-.38,3h-3L7.49,93.1h4.57l2.28,15.19ZM9.83,96.08H9.68L8.9,102.6h1.71Z"/><path class="cls-4" d="M18,93.1h3.69a4.53,4.53,0,0,1,2.79.67,3.22,3.22,0,0,1,1,2.11,41.13,41.13,0,0,1,.19,4.82,41,41,0,0,1-.19,4.81,3.19,3.19,0,0,1-1,2.11,4.46,4.46,0,0,1-2.79.67H18Zm3.69,12.43a.89.89,0,0,0,.71-.22,2.31,2.31,0,0,0,.25-1.15c0-.61,0-1.77,0-3.46s0-2.85,0-3.47a2.31,2.31,0,0,0-.25-1.15.89.89,0,0,0-.71-.22H21v9.67Z"/><path class="cls-4" d="M31.16,108.29,29.11,93.1h3l1.25,12.06h.23L34.8,93.1h3l-2.05,15.19Z"/><path class="cls-4" d="M46.35,108.29l-.38-3H43.7l-.38,3h-3L42.57,93.1h4.57l2.28,15.19ZM44.91,96.08h-.15L44,102.6h1.7Z"/><path class="cls-4" d="M58.44,108.29l-2.36-7.62H56v7.62H53.12V93.1h2.8L58.09,100h.11V93.1h2.89v15.19Z"/><path class="cls-4" d="M70.19,108.36a6.43,6.43,0,0,1-1.12.11,4,4,0,0,1-2.61-.71,3.72,3.72,0,0,1-1.1-2.28,31.28,31.28,0,0,1-.26-4.78,29.46,29.46,0,0,1,.28-4.77,3.82,3.82,0,0,1,1.12-2.3,3.9,3.9,0,0,1,2.57-.71,7.72,7.72,0,0,1,1.18.1,3.21,3.21,0,0,1,.85.24v2.53a11.75,11.75,0,0,0-1.48-.11,1.48,1.48,0,0,0-1.05.29,2.16,2.16,0,0,0-.35,1.23c0,.62-.08,1.79-.08,3.5s0,2.87.08,3.5a2.15,2.15,0,0,0,.35,1.22,1.48,1.48,0,0,0,1.05.29,9.89,9.89,0,0,0,1.53-.11v2.47A4.23,4.23,0,0,1,70.19,108.36Z"/><path class="cls-4" d="M75,108.29V93.1h6.09v2.76H78v3.38h2.7V102H78v3.53h3.07v2.76Z"/><path class="cls-4" d="M85.08,93.1h3.69a4.55,4.55,0,0,1,2.79.67,3.16,3.16,0,0,1,1,2.11,38.45,38.45,0,0,1,.2,4.82,38.37,38.37,0,0,1-.2,4.81,3.14,3.14,0,0,1-1,2.11,4.48,4.48,0,0,1-2.79.67H85.08Zm3.69,12.43a.89.89,0,0,0,.71-.22,2.31,2.31,0,0,0,.25-1.15c0-.61,0-1.77,0-3.46s0-2.85,0-3.47a2.31,2.31,0,0,0-.25-1.15.89.89,0,0,0-.71-.22h-.69v9.67Z"/><path class="cls-5" d="M19.79,134.79l-2.1-5.3H9.08L7,134.79H5.24l7.15-18.23h2l7.16,18.23Zm-6.33-16.24h-.14L9.64,127.9h7.5Z"/><path class="cls-5" d="M26.41,134.79V116.56h1.7v16.58H37v1.65Z"/><path class="cls-5" d="M48.1,126.76V125.2h6.2v9.3c-.87.14-1.84.26-2.9.35s-2,.15-2.8.15a12.88,12.88,0,0,1-4.9-.69,3.89,3.89,0,0,1-2.15-2.6,22.5,22.5,0,0,1-.58-6,22.11,22.11,0,0,1,.6-6A3.87,3.87,0,0,1,43.72,117a13.15,13.15,0,0,1,4.88-.67c.88,0,1.85.05,2.92.14s2,.22,2.7.36v1.51a33.49,33.49,0,0,0-4.66-.42,18.69,18.69,0,0,0-4.55.37,2.7,2.7,0,0,0-1.81,1.93,18.81,18.81,0,0,0-.53,5.43,23.5,23.5,0,0,0,.39,5.13,3,3,0,0,0,1.59,2.09,10.15,10.15,0,0,0,4,.55c.56,0,1.25,0,2.07-.08s1.47-.12,2-.19v-6.41Z"/><path class="cls-5" d="M61.91,134.32A3.33,3.33,0,0,1,60,131.86a31.94,31.94,0,0,1-.41-6.19,31.89,31.89,0,0,1,.41-6.18A3.33,3.33,0,0,1,61.91,117a13.45,13.45,0,0,1,5.07-.67A13.42,13.42,0,0,1,72,117a3.33,3.33,0,0,1,1.89,2.47,31.89,31.89,0,0,1,.41,6.18,31.94,31.94,0,0,1-.41,6.19A3.33,3.33,0,0,1,72,134.32,13.38,13.38,0,0,1,67,135,13.4,13.4,0,0,1,61.91,134.32Zm9-1.29a2.34,2.34,0,0,0,1.37-1.86,29.55,29.55,0,0,0,.34-5.5,29.7,29.7,0,0,0-.34-5.5,2.32,2.32,0,0,0-1.37-1.85,13.69,13.69,0,0,0-4-.38,13.73,13.73,0,0,0-4,.38,2.32,2.32,0,0,0-1.37,1.85,28.82,28.82,0,0,0-.34,5.5,28.68,28.68,0,0,0,.34,5.5A2.34,2.34,0,0,0,63,133a13.73,13.73,0,0,0,4,.38A13.69,13.69,0,0,0,70.94,133Z"/><path class="cls-5" d="M82.89,134.91c-1.17-.07-2.18-.15-3-.25v-1.59c.91.08,1.93.16,3,.23s2,.11,2.76.11a17.72,17.72,0,0,0,2.32-.12,4,4,0,0,0,1.49-.49,1.67,1.67,0,0,0,.81-1.07,7.68,7.68,0,0,0,.2-1.92,9.6,9.6,0,0,0-.15-2.07,1.14,1.14,0,0,0-.71-.83,7.63,7.63,0,0,0-2-.42L83,126a4.91,4.91,0,0,1-2.42-.74,2.61,2.61,0,0,1-1-1.47,10.4,10.4,0,0,1-.23-2.45,5.81,5.81,0,0,1,.71-3.17,3.47,3.47,0,0,1,2-1.44,14.24,14.24,0,0,1,3.66-.37c1,0,2,0,3.09.1a19.49,19.49,0,0,1,2.44.29v1.51c-.7-.08-1.55-.16-2.54-.22s-1.9-.09-2.73-.09a15.54,15.54,0,0,0-2.52.16,4.18,4.18,0,0,0-1.51.5,1.74,1.74,0,0,0-.76,1,6,6,0,0,0-.19,1.72,6.83,6.83,0,0,0,.17,1.76,1.32,1.32,0,0,0,.67.82,4.9,4.9,0,0,0,1.57.39l4.51.47a10.3,10.3,0,0,1,2.69.56,2.23,2.23,0,0,1,1.25,1.43,9.9,9.9,0,0,1,.3,2.91,6.84,6.84,0,0,1-.72,3.54,3.17,3.17,0,0,1-2,1.47,14.17,14.17,0,0,1-3.38.32C85.14,135,84.05,135,82.89,134.91Z"/><path class="cls-5" d="M47.08,49.62c1.17-.36,8.61.83,9.61,1.53,3.13,2.21,7.71,3.41,9.55,1.15s-.08-6.13-3-9.1c-.88-.88-3.7-7.75-3.56-9,.42-3.87-.85-8.5-3.73-9s-5.61,3.66-6.3,7.16c-.24,1.22-5,7.11-6.14,7.62-3.48,1.62-6.77,5-5.73,7.69S43.7,50.65,47.08,49.62Z"/><path class="cls-5" d="M60,9.61c4.68.2,6.65,9.72,5.89,17.18-.24,2.37,5.27,15.71,6.24,17.91a7.29,7.29,0,0,0,3,3C71.63,38.07,71.32,30.32,72,28.51c3-8.4,1.71-19.69-2.85-22.32-3.07-1.77-9.79-2.48-14.07,4.56A6.91,6.91,0,0,1,60,9.61Z"/><path class="cls-5" d="M22.61,50.2C20.Line truncated

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

@@ -1,9 +0,0 @@
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#e3493c">
<meta name="apple-mobile-web-app-title" content="Advanced Algos">
<meta name="application-name" content="Advanced Algos">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

@@ -1 +0,0 @@
<svg version="1" xmlns="http://www.w3.org/2000/svg" width="1365.333" height="1365.333" viewBox="0 0 1024.000000 1024.000000"><path d="M685.9 27.4c-.2.2-3 .7-6.1 1-12.6 1.5-34.6 8.5-45.2 14.5-2 1.2-5.3 3.1-7.3 4.2-14.3 8.1-30.2 22.3-43.5 38.8-5.9 7.4-16.2 22.1-15.5 22.1.2 0 3.6-1.7 7.5-3.9 17.4-9.6 28.8-12.1 52.2-11.7 13.4.3 17.7.8 23.1 2.5 25.1 8 45.2 36.6 58.9 83.7 1.8 6 3.3 11.6 3.5 12.4 2.3 10.8 3.5 17.1 4 20 .3 1.9 1 6 1.5 9 1.2 7.3 1.8 11.3 2.5 18.5.4 3.3.8 7.6 1.1 9.5 1.6 14.3 2.2 51.4 1 69.5-1.4 21.3-1.5 26-.5 31 .5 2.7 1.2 6.3 1.5 8 2.3 12.9 20.6 69 33.4 102.5 1.6 4.1 4.8 12.4 7.1 18.5 17.1 45.2 47.3 118.6 49.1 119.3.4.2.8.9.8 1.5.1 3.8 18.3 22 29.2 29.1 4.7 3.1 8.8 5.6 9 5.6.3 0-3.2-10.9-7.7-24.3-4.5-13.3-8.4-25.3-8.7-26.7-.4-1.4-2-7.2-3.7-13-4.3-14.5-12.2-45.3-13.7-54-.3-1.4-.7-3.3-1-4.2-.3-1-.7-3-1-4.5-.2-1.6-.9-4.8-1.4-7.3-.5-2.5-1.4-7.2-2-10.5-.5-3.3-1.2-7.1-1.5-8.5-.3-1.4-1-5.7-1.5-9.5-.6-3.9-1.2-8.1-1.5-9.5-.3-2.3-.7-5.4-2-16.3-3.1-25.8-3.8-58.6-1.5-73.2.7-4.4 2.2-10.7 3.5-14 2.3-6.1 9-28.9 9.9-33.5.3-1.4 1.2-5.2 2-8.5s1.7-7.4 1.9-9c.3-1.7 1.4-8.2 2.6-14.6 1.1-6.3 2.3-14.7 2.6-18.5.4-3.8.9-8.3 1.1-9.9 2.2-16.2 2.2-69.4 0-83.5-.2-1.4-.7-5-1.1-8-6.7-56.6-26.4-102.4-53.1-123.1-11.1-8.5-31-16.4-49.9-19.7-9.6-1.7-38.4-2.9-39.6-1.8zM465 215.4c-2.3 3-9.7 11.7-14.5 17-1.1 1.2-5.6 6.2-10 11.1-8.3 9.3-43.9 45.2-53.5 54-51.1 46.9-108.8 86-132.5 90-2.2.4-4.4.8-5 .9-.5.2-2.8.6-5 1.1-24.5 4.7-70 20.4-91 31.3-2.7 1.4-5.2 2.6-5.5 2.7-.7.1-12.3 6.2-16.7 8.7-2.1 1.2-5.4 3.1-7.5 4.2C62.4 471.4 16.3 519 4.3 559.8.9 571.3.5 590 3.4 603.5c2.6 12.1 7.2 25.6 11.8 35 19.6 39.1 52.7 65.8 95.3 76.8 5.5 1.4 12 2.9 14.5 3.2 2.5.4 5.4.9 6.5 1.1 2.8.5 11.7 1.4 19.5 1.9l6.4.4-3.4-2.1c-20.8-12.5-29.7-21.3-39-38.3-1.8-3.3-4.3-7.8-5.5-10-6.1-11.2-8.2-22.8-6.4-35.1 7.4-48 72.3-111.2 159.4-155 10.5-5.3 21-11.2 23.5-13.1 8.7-6.7 26.9-25.3 45.4-46.3 1.7-2 4.9-5.6 7.1-8.1 2.2-2.4 6-6.9 8.5-9.8 2.5-3 5-5.9 5.5-6.5.6-.6 3-3.6 5.5-6.6 6.5-8 7.1-8.6 15.2-18.5 12.7-15.4 51.5-64.5 61.3-77.6 1.1-1.5 5.9-7.8 10.6-14 11.5-15.2 13.3-18.1 16.8-26.9 3-7.7 3.5-9.3 5.1-19 1.2-7.1 1.9-21.9 1.1-22.4-.3-.2-1.7 1.1-3.1 2.8zM563.9 315c-21.5 5.4-43.9 28.6-59.4 61.3-5.2 11-10.1 24.9-12.5 35.7-2 8.8-6.1 16.2-21 37.4-1.8 2.6-17.8 23.2-20.7 26.6-14.7 17.6-22.4 26.2-31.2 35.1-8.7 8.6-12.2 11.3-19.6 15.2-16.7 8.7-25.6 14.5-37 23.8-22.2 18.1-36.8 38.2-41 56.4-1.6 6.6-2.2 17.6-1.1 19.3.3.5.7 2.1 1 3.7.8 4.3 5.3 12.7 9.1 16.8 10.1 11.1 27.7 18.5 50.5 21.3 12.2 1.5 36.1.8 49-1.6 11.6-2 12.6-2.3 20.5-4.5s31.7-2.2 43.5 0c.8.2 4.4.6 8 1 3.6.4 7.4.9 8.4 1.1 1.1.2 4.2.6 6.9.9 2.8.3 5.3.8 5.6.9.3.2 2.9.7 5.6 1 9.1 1.3 39 7.5 47.9 10.1 8.9 2.6 18.5 7 20.6 9.6 1.9 2.3 30.1 16.5 39.5 20 9.1 3.3 26.6 7.7 33.7 8.6 9.2 1.1 23.9.7 30-.7 19.5-4.6 33.3-18.5 36.3-36.7.7-4.2.8-19 .1-20.1-.2-.4-.7-2.4-1-4.6-1-6.1-5.5-18.3-10.3-28.1-4.2-8.3-15.4-26.1-20.1-31.6-5.8-7-14.5-17-18.6-21.4-2.6-2.8-6.5-8-8.7-11.7-6.3-10.8-17.6-35.1-25.4-55.3-1.5-3.9-3.3-8.4-4-10-1.4-3.5-4.9-12.8-5-13.5 0-.3-1.2-3.7-2.5-7.5-1.3-3.9-2.5-7.5-2.6-8-.1-.6-.9-3.5-1.8-6.6-2.6-8.9-2.8-10-2.6-17.4.7-25.5.3-39.3-1.3-49.5-.3-1.4-.8-4.5-1.2-7-.3-2.4-.8-4.7-1-5.1-.2-.3-.7-2.1-1-4-.9-5.4-6.3-20.6-9.7-27.3-7.5-14.9-16.6-24.9-27.5-30.3-6.3-3.1-8.3-3.6-16-3.9-4.8-.2-10.4.1-12.4.6zM340 752.1c-12.3 2.1-18.9 4.4-31.5 10.7-10.5 5.3-11.8 4.4 13 9.2 69 13.5 135.5 34.9 186.8 60.2 24.5 12.1 41 22.8 49.7 32.3 24.3 26.6 37.9 39.4 60 56.6 50.3 39.2 116.2 69.8 162.5 75.5 2.8.3 6.8.9 9 1.3 4.8.9 28.3.6 34-.3 23.2-4 37.1-11.8 56.6-31.7 33-33.8 46.8-81.2 37.4-128.4-3.2-16-8-29.9-16.2-46.5l-4.2-8.5-.1 8c-.1 4.4-.3 8.7-.4 9.5-.2.8-.6 3.8-1 6.6-1.8 14.4-15.1 40.8-26.4 52.7-17.8 18.7-53.6 23.1-99.2 12.2-5.8-1.4-11.5-2.7-12.6-3-1.2-.3-7.7-2.3-14.5-4.6-36.3-12-78-32.8-111.4-55.7-6-4.1-13-8.4-15.5-9.4-2.5-1.1-5.4-2.3-6.5-2.8-5.6-2.4-39.7-11.2-52.5-13.5-1.9-.3-4.2-.7-5-.9-.8-.1-4-.8-7-1.4-9.8-2-26.4-5.1-30-5.6-3-.5-29.1-4.8-37-6.1-1.4-.2-4.3-.7-6.5-1-6.9-1.1-9.8-1.5-15.5-2.5-3-.5-8.2-1.2-11.5-1.6-3.3-.3-6.2-.7-6.5-.9-.3-.2-4.4-.9-9-1.5-4.7-.6-9.6-1.3-11-1.5-1.4-.2-6.3-.9-11-1.5s-9.6-1.3-11-1.5c-5.9-.8-10.8-1.5-15-2-5.1-.6-9.4-1.2-16-2.1-7.1-.9-20.1-1.1-25-.3z"/></svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

@@ -1,19 +0,0 @@
{
"name": "Advanced Algos",
"short_name": "Advanced Algos",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}
-207
View File
@@ -1,207 +0,0 @@
import Auth0Lock from 'auth0-lock'
import gql from 'graphql-tag'
import { getItem, setItem, removeItem } from '../utils/local-storage'
import { validObject, deleteCookie } from '../utils/js-helpers'
import { client } from '../App'
import { AUTH_CONFIG } from './Auth0' // create by renaming Auth0.sample.js to Auth0.js and setting vars
const AUTHENTICATE = gql`
mutation authenticate($idToken: String!) {
authenticate(idToken: $idToken) {
alias
authId
}
}
`
const lock = new Auth0Lock(AUTH_CONFIG.clientId, AUTH_CONFIG.domain, {
oidcConformant: true,
autoclose: true,
auth: {
sso: true,
redirectUrl: window.location.origin + '/callback',
responseType: 'token id_token',
audience: `${AUTH_CONFIG.api_audience}`,
params: {
scope: `openid profile email user_metadata app_metadata picture`
}
}
})
class Auth {
constructor (cb, apolloClient) {
this.handleAuthentication()
// binds functions to keep this context
this.apolloClient = apolloClient
this.cb = cb.bind(this)
this.login = this.login.bind(this)
this.logout = this.logout.bind(this)
this.isAuthenticated = this.isAuthenticated.bind(this)
this.checkSession = this.checkSession.bind(this)
}
login () {
// Call the show method to display the widget.
lock.show()
}
handleAuthentication () {
// Add a callback for Lock's `authenticated` event
lock.on('authenticated', this.setSession.bind(this))
// Add a callback for Lock's `authorization_error` event
lock.on('authorization_error', err => {
console.log(err)
const data = { status: `error`, errMessage: err.error }
this.cb(data)
})
}
checkSession () {
return new Promise((resolve, reject) => {
// Add a callback for Lock's `authenticated` event
lock.checkSession(
{
responseType: 'token id_token',
audience: AUTH_CONFIG.api_audience,
scope:
'openid email profile read:teams write:teams read:member write:member',
connection: 'github',
prompt: 'none'
},
function (err, authResult) {
if (!err) {
resolve(authResult)
} else {
reject(err)
}
}
)
})
}
setSession (authResult) {
console.log('setSession')
if (authResult && authResult.accessToken && authResult.idToken) {
// Set the time that the access token will expire at
let expiresAt = JSON.stringify(
authResult.expiresIn * 1000 + new Date().getTime()
)
setItem('access_token', authResult.accessToken)
setItem('id_token', authResult.idToken)
setItem('expires_at', expiresAt)
const data = {
status: `success`,
accessToken: authResult.accessToken,
idToken: authResult.idToken,
expiresAt
}
console.log('setSession idTokenPayload: ', authResult.idTokenPayload)
this.signinOrCreateAccount({ ...data })
this.cb(data)
console.log('idTokenPayload', authResult.idTokenPayload)
setItem('authUser', JSON.stringify(authResult.idTokenPayload))
setItem('authId', authResult.idTokenPayload.sub)
if (window.location.href.includes(`callback`)) {
window.location.href = '/'
}
return true
}
}
async signinOrCreateAccount ({ accessToken, idToken, expiresAt }) {
console.log(
'signinOrCreateAccount: ',
client,
this.apolloClient,
accessToken,
idToken,
expiresAt
)
try {
const data = await client.mutate({
mutation: AUTHENTICATE,
variables: { idToken }
})
console.log('signinOrCreateAccount auth: ', await data)
setItem('authUser', JSON.stringify(data.data.authenticate))
setItem('authId', data.data.authenticate.authId)
if (window.location.href.includes(`callback`)) {
window.location.href = '/'
} else {
window.location.reload()
}
return data
} catch (err) {
return console.log('Sign in or create account error: ', err)
}
}
logout () {
// Clear access token and ID token from local storage
removeItem('access_token')
removeItem('id_token')
removeItem('expires_at')
removeItem('authUser')
removeItem('auth0.ssodata')
window.localStorage.clear()
deleteCookie('ajs_anonymous_id')
deleteCookie('ajs_user_id')
deleteCookie('current_tenant')
lock.logout({ returnTo: AUTH_CONFIG.logoutUrl })
console.log('logout')
}
async isAuthenticated () {
// check session and run Auth0 SS0
const getUser = await getItem('authUser')
let user = JSON.parse(getUser)
if (validObject(user, 'exp') && new Date().getTime() < (user.exp * 1000)) {
console.log('handleAuth.user exp: ', user, window.location.href)
return user
}
const checkSSO = await this.checkSession()
.then(result => {
console.log('handleAuth.checksessions: ', result)
setItem('authUser', result.idTokenPayload.sub)
setItem('authId', result.idTokenPayload.sub)
// user confirmed, log into client
this.setSession(result)
return result.idTokenPayload
})
.catch(err => {
console.log('handleAuth.checksessions err: ', err)
if (err.error === 'login_required') {
// return this.login()
}
return err
})
if (
(window.location.href.includes(`manage`) ||
window.location.href.includes(`profile`)) &&
!user
) {
window.location.href = '/'
}
if (/manage|profile|create|dashboard/.test(window.location.href) && !user) {
this.login()
}
console.log('handleAuth.isAuthenticated 2: ', checkSSO, user)
if (validObject(checkSSO, 'error')) {
return false
} else {
return checkSSO
}
}
}
export default Auth
-7
View File
@@ -1,7 +0,0 @@
export const AUTH_CONFIG = {
api_audience: '<AUTH0_API_AUDIENCE>',
domain: '<AUTH0_API_DOMAIN>',
clientId: '<AUTH0_API_CLIENTID>',
callbackUrl: '<AUTH0_CALLBACK_URL>',
logoutUrl: '<AUTH0_LOGOUT_URL>'
}
-51
View File
@@ -1,51 +0,0 @@
import React from 'react'
import Button from '@material-ui/core/Button'
import Dialog from '@material-ui/core/Dialog'
import DialogActions from '@material-ui/core/DialogActions'
import DialogContent from '@material-ui/core/DialogContent'
import DialogContentText from '@material-ui/core/DialogContentText'
import DialogTitle from '@material-ui/core/DialogTitle'
import CssBaseline from '@material-ui/core/CssBaseline'
class About extends React.Component {
state = {
open: true
}
handleClickOpen = () => {
this.setState({ open: true })
}
handleClose = () => {
this.setState({ open: false })
}
render () {
return (
<React.Fragment>
<CssBaseline />
<Dialog
open={this.state.open}
onClose={this.handleClose}
aria-labelledby='alert-dialog-title'
aria-describedby='alert-dialog-description'>
<DialogTitle id='alert-dialog-title'>
{"Section under development."}
</DialogTitle>
<DialogContent>
<DialogContentText id='alert-dialog-description'>
The functionality of this section has not been developed yet. We expect to have it for October 2018. Thanks for your understanding.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color='primary' autoFocus>
Close
</Button>
</DialogActions>
</Dialog>
</React.Fragment>
)
}
}
export default About
@@ -1,30 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
const styles = theme => ({
button: {
margin: theme.spacing.unit,
},
input: {
display: 'none',
},
});
function AddUserNextButton(props) {
const { classes } = props;
return (
<div>
<Button type="submit" variant="contained" color="primary" className={classes.button}>
Next
</Button>
</div>
);
}
AddUserNextButton.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(AddUserNextButton);
@@ -0,0 +1,18 @@
import React from 'react'
import Typography from '@material-ui/core/Typography'
const BannerTopBar = ({
size,
backgroundUrl,
title,
text
}) => (
<div className={`bannerTopBar ${size}`} style={backgroundUrl ? { backgroundImage: `url(${backgroundUrl})` } : {}}>
<div className='caption'>
<Typography className='title' variant='h1' align='center'>{title}</Typography>
<Typography className='text' variant='h2' align='center'>{text}</Typography>
</div>
</div>
)
export default BannerTopBar
+19 -9
View File
@@ -1,14 +1,24 @@
import React from 'react'
import React, { Component } from 'react'
import UserList from './UserList'
import CssBaseline from '@material-ui/core/CssBaseline'
import BannerTopBar from './BannerTopBar'
const Browse = () => {
return (
<React.Fragment>
<CssBaseline />
<UserList />
</React.Fragment>
)
class Browse extends Component {
render () {
return (
<React.Fragment>
<BannerTopBar
size='medium'
title='Users Directory'
text='Everyone involved in Advanced Algos is here.'
backgroundUrl='https://advancedalgos.net/img/photos/users.jpg'
/>
<div className='container'>
<UserList />
</div>
</React.Fragment>
)
}
}
export default Browse
-13
View File
@@ -1,13 +0,0 @@
import React, { Component } from 'react'
class Callback extends Component {
render() {
return (
<div>
Authenticating...
</div>
)
}
}
export default Callback
-52
View File
@@ -1,52 +0,0 @@
import React from 'react'
import Button from '@material-ui/core/Button'
import Dialog from '@material-ui/core/Dialog'
import DialogActions from '@material-ui/core/DialogActions'
import DialogContent from '@material-ui/core/DialogContent'
import DialogContentText from '@material-ui/core/DialogContentText'
import DialogTitle from '@material-ui/core/DialogTitle'
import CssBaseline from '@material-ui/core/CssBaseline'
class Contact extends React.Component {
state = {
open: true
}
handleClickOpen = () => {
this.setState({ open: true })
}
handleClose = () => {
this.setState({ open: false })
}
render () {
return (
<React.Fragment>
<CssBaseline />
<Dialog
open={this.state.open}
onClose={this.handleClose}
aria-labelledby='alert-dialog-title'
aria-describedby='alert-dialog-description'>
<DialogTitle id='alert-dialog-title'>
{"Section under development."}
</DialogTitle>
<DialogContent>
<DialogContentText id='alert-dialog-description'>
The functionality of this section has not been developed yet. We expect to have it for October 2018. Thanks for your understanding.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color='primary' autoFocus>
Close
</Button>
</DialogActions>
</Dialog>
</React.Fragment>
)
}
}
export default Contact
+5 -5
View File
@@ -25,7 +25,7 @@ import ExpandMore from '@material-ui/icons/ExpandMore';
import StarBorder from '@material-ui/icons/StarBorder';
// Images
import PortraitImage from '../img/portrait.jpg'
import UserDefaultPicture from '../img/user-default-pic.jpg'
const styles = theme => ({
card: {
@@ -132,7 +132,7 @@ class DescendentsTree extends Component {
<CardActionArea>
<CardMedia
className={classes.media}
image={PortraitImage}
image={UserDefaultPicture}
title='User Profile'
/>
@@ -188,10 +188,10 @@ class DescendentsTree extends Component {
if (data.loading) {
return (<div> Loading Descendents... </div>)
} else {
if (data.descendents === undefined) {
if (data.users_Descendents === undefined) {
return (<div> No Descendents to Display </div>)
} else {
return data.descendents.map(descendent => {
return data.users_Descendents.map(descendent => {
return (
<div key={descendent.alias}>
@@ -201,7 +201,7 @@ class DescendentsTree extends Component {
<CardActionArea>
<CardMedia
className={classes.media}
image={PortraitImage}
image={UserDefaultPicture}
title='User Profile'
/>
+26 -90
View File
@@ -1,105 +1,41 @@
import React, { Component } from 'react'
import { compose } from 'recompose'
import { withStyles } from '@material-ui/core/styles'
import {LineChart} from 'react-easy-chart'
import Grid from '@material-ui/core/Grid'
import Typography from '@material-ui/core/Typography'
import CssBaseline from '@material-ui/core/CssBaseline'
const styles = theme => ({
root: {
flexGrow: 1,
padding: 100
},
grid: {
margin: theme.spacing.unit,
width: '50%'
},
typography: {
width: '100%',
marginTop: 20,
marginBottom: 20
},
'@global': {
body: {
backgroundColor: theme.palette.common.white
}
},
layout: {
width: 'auto',
marginLeft: theme.spacing.unit * 3,
marginRight: theme.spacing.unit * 3,
[theme.breakpoints.up(900 + theme.spacing.unit * 3 * 2)]: {
width: 900,
marginLeft: 'auto',
marginRight: 'auto'
}
},
heroContent: {
maxWidth: 600,
margin: '0 auto',
padding: `${theme.spacing.unit * 8}px 0 ${theme.spacing.unit * 6}px`
}
})
import BannerTopBar from './BannerTopBar'
import { Typography } from '@material-ui/core'
class Home extends Component {
render () {
const { classes } = this.props
return (
<React.Fragment>
<CssBaseline />
<main className={classes.layout}>
<div className={classes.heroContent}>
<Typography
variant='display3'
align='center'
color='textPrimary'
gutterBottom
>
Collaborate. Innovate. Evolve.
<BannerTopBar
size='big'
title='Users Module'
text='Responsible for all human users of the Advanced Algos Platform.'
backgroundUrl='https://advancedalgos.net/img/photos/users.jpg'
/>
<div className='homePage container'>
<Typography variant='h1' align='center' className='title'>Welcome to the Users Module!</Typography>
<Typography variant='h2' align='center' className='subtitle'>The human component of the Advanced Algos Ecosystem.</Typography>
<div className='column'>
<Typography align='justify'>
The Advanced Algos Ecosystem is made out of humans, financial beings and other entities such as teams.
</Typography>
<Typography
variant='title'
align='center'
color='textSecondary'
component='h3'
>
Welcome to Advanced Algos Users Module
<Typography align='justify'>
Humans are either <strong>users</strong> or <strong>guests</strong>. If you haven’t signed up yet or you are logged off, then you are acting as a guest, with limited features. Please sign-up or log-in for a richer experience.
</Typography>
</div>
</main>
<Grid container justify='center' spacing={24}>
<Grid className={classes.grid} item>
<Typography className={classes.typography} gutterBottom variant='headline' component='h2'>
Intro
</Typography>
<Typography className={classes.typography} component='p'>
This module is responsible for managing users across the Advanced Algos system. Here you can browse the Users Directory, search for users and get to their profiles. You can create your own User profile if you sign up, or manage it if you already have one by logging in.
</Typography>
<Typography className={classes.typography} gutterBottom variant='headline' component='h2'>
Development Status
</Typography>
<Typography className={classes.typography} component='p'>
This module is is currently under heavy development. Implementation started 1st of September 2018 and this is the result of the 2nd sprint of 2 weeks of work each.
</Typography>
<Typography className={classes.typography} gutterBottom variant='headline' component='h2'>
What can you do?
</Typography>
<Typography className={classes.typography} component='p'>
Currently you can use the Browse section to list all registered users. At the Search page you can searh for users by name. Clicking on View Profile you can see some more info about that user. You can signup with your Github account and manage your profile information while logged in. While loggedin, you can edit your profile info, define your referrer and view your descendants. You will find all features under develpment with a dialog indicating it is not ready.
</Typography>
</Grid>
</Grid>
<div className='column'>
<Typography align='justify'>
Users may have different roles, such as developer, trader, analyst, etc. Each of these roles usually have personalized features throughout the system.
</Typography>
<Typography align='justify'>
The Users Module allows you to handle all of your details as a user of the system as well as finding other people in the ecosystem.
</Typography>
</div>
</div>
</React.Fragment>
)
}
}
export default compose(
withStyles(styles)
)(Home)
export default Home
+137 -21
View File
@@ -1,14 +1,69 @@
import React, { Component } from 'react'
import {graphql} from 'react-apollo'
import {graphql, compose} from 'react-apollo'
import {getUserByAuthIdQuery} from '../queries/queries'
import {auth} from '../App'
import LoggedInUserMenu from './LoggedInUserMenu'
import { withStyles } from '@material-ui/core/styles'
import classNames from 'classnames'
import Button from '@material-ui/core/Button'
import IconButton from '@material-ui/core/IconButton'
// icons
import UserIcon from '@material-ui/icons/Person'
import { Link } from 'react-router-dom'
import ProfileSheetIcon from '@material-ui/icons/Create'
import ProfileImagesIcon from '@material-ui/icons/Wallpaper'
import YourReferrerIcon from '@material-ui/icons/AccessibilityNew'
import DescendentsIcon from '@material-ui/icons/DeviceHub'
const ProfileSheetLink = props => <Link to='/users/profile-sheet' {...props} />
const ProfileImagesLink = props => <Link to='/users/profile-images' {...props} />
const YourReferrerLink = props => <Link to='/users/referrer' {...props} />
const YourDescendentsLink = props => <Link to='/users/descendents' {...props} />
const UserLink = props => <Link to='/users/user' {...props} />
const styles = theme => ({
root: {
flexGrow: 1
},
flex: {
flexGrow: 1,
marginLeft: 30
},
menuButton: {
marginLeft: -12,
marginRight: 20
},
cssRoot: {
color: '#FFFFFF',
backgroundColor: theme.palette.secondary,
'&:hover': {
backgroundColor: theme.palette.dark
},
whiteSpace: 'nowrap',
paddingRight: 2 * theme.spacing.unit,
paddingLeft: 2 * theme.spacing.unit
},
button: {
margin: theme.spacing.unit
},
leftIcon: {
marginRight: theme.spacing.unit
},
rightIcon: {
marginLeft: theme.spacing.unit
},
iconSmall: {
fontSize: 20
}
})
class LoggedInUser extends Component {
displayLoggedInUser () {
const user = this.props.data.userByAuthId
const user = this.props.data.users_UserByAuthId
const { classes, match } = this.props
if (user) {
let displayName = 'No Display Name'
@@ -34,15 +89,73 @@ class LoggedInUser extends Component {
let identityProvider = authArray[0]
return (
<div>
<p><LoggedInUserMenu menuLabel={displayName} identityProvider={identityProvider} /></p>
</div>
<li className='menu-item-has-children'>
<Button
variant='text'
size='small'
className={classNames(classes.button, classes.cssRoot)}
title='Manage Your Profile'
component={UserLink}
to={`${match.url}/user`}>
<UserIcon className={classNames(classes.leftIcon, classes.iconSmall)} />
Your Profile
</Button>
<ul>
<li>
<Button
variant='text'
size='small'
className={classNames(classes.button, classes.cssRoot)}
title='Profile Sheet'
component={ProfileSheetLink}
to={`${match.url}/profile-sheet`}>
<ProfileSheetIcon className={classNames(classes.leftIcon, classes.iconSmall)} />
Profile Sheet
</Button>
</li>
<li>
<Button
variant='text'
size='small'
className={classNames(classes.button, classes.cssRoot)}
title='Profile Images'
component={ProfileImagesLink}
to={`${match.url}/profile-images`}>
<ProfileImagesIcon className={classNames(classes.leftIcon, classes.iconSmall)} />
Profile Images
</Button>
</li>
<li>
<Button
variant='text'
size='small'
className={classNames(classes.button, classes.cssRoot)}
title='Your Referrer'
component={YourReferrerLink}
to={`${match.url}/referrer`}>
<YourReferrerIcon className={classNames(classes.leftIcon, classes.iconSmall)} />
Your Referrer
</Button>
</li>
<li>
<Button
variant='text'
size='small'
className={classNames(classes.button, classes.cssRoot)}
title='Your Descendents'
component={YourDescendentsLink}
to={`${match.url}/descendents`}>
<DescendentsIcon className={classNames(classes.leftIcon, classes.iconSmall)} />
Your Descendents
</Button>
</li>
</ul>
</li>
)
} else {
return (
<div onClick={() => auth.login()}>
<Button color='inherit'>Login / Sign up</Button>
</div>
<div />
)
}
}
@@ -53,28 +166,31 @@ class LoggedInUser extends Component {
render () {
if (this.loggedInUserStored !== true) {
let user = this.props.data.userByAuthId
let user = this.props.data.users_UserByAuthId
if (user !== undefined) {
localStorage.setItem('loggedInUser', JSON.stringify(this.props.data.userByAuthId))
localStorage.setItem('loggedInUser', JSON.stringify(this.props.data.users_UserByAuthId))
this.loggedInUserStored = true
}
}
return (
<div>
<React.Fragment>
{this.displayLoggedInUser()}
</div>
</React.Fragment>
)
}
}
export default graphql(getUserByAuthIdQuery, { // What follows is the way to pass a parameter to a query.
options: (props) => {
return {
variables: {
authId: props.authId
export default compose(
graphql(getUserByAuthIdQuery, { // What follows is the way to pass a parameter to a query.
options: (props) => {
return {
variables: {
authId: props.authId
}
}
}
}
})(LoggedInUser) // This binds the querty to the component
}),
withStyles(styles)
)(LoggedInUser)
-98
View File
@@ -1,98 +0,0 @@
import React, { Component } from 'react'
import toRenderProps from 'recompose/toRenderProps'
import withState from 'recompose/withState'
import { Link } from 'react-router-dom'
import {compose} from 'react-apollo'
// Materia UI
import { withStyles } from '@material-ui/core/styles'
import Button from '@material-ui/core/Button'
import Menu from '@material-ui/core/Menu'
import MenuItem from '@material-ui/core/MenuItem'
// Images
import GithubLogo from '../img/github-head-negative.png'
import EmailIcon from '../img/email.png'
import ProfileIcon from '@material-ui/icons/Person'
import LogoutIcon from '@material-ui/icons/DirectionsWalk'
const UserLink = props => <Link to='/user' {...props} />
const LogoutLink = props => <Link to='/logout' {...props} />
const WithState = toRenderProps(withState('anchorEl', 'updateAnchorEl', null))
const styles = {
img: {
margin: 20,
display: 'block',
maxWidth: 15,
maxHeight: 15
}
}
class LoggedInUserMenu extends Component {
constructor (props) {
super(props)
this.state = {
user: {}
}
}
displayIdentityProvider () {
const { classes } = this.props
switch (this.props.identityProvider) {
case 'github':
return (
<img className={classes.img} src={GithubLogo} alt='Github' />
)
break
case 'auth0':
return (
<img className={classes.img} src={EmailIcon} alt='Auth0' />
)
break
default:
}
}
render () {
const { classes } = this.props
return (
<WithState>
{({ anchorEl, updateAnchorEl }) => {
const open = Boolean(anchorEl)
const handleClose = () => {
updateAnchorEl(null)
}
return (
<React.Fragment>
<Button
aria-owns={open ? 'render-props-menu' : null}
aria-haspopup='true'
onClick={event => {
updateAnchorEl(event.currentTarget)
}}
color='inherit'
>
{this.displayIdentityProvider()}
{this.props.menuLabel}
</Button>
<Menu id='render-props-menu' anchorEl={anchorEl} open={open} onClose={handleClose}>
<MenuItem onClick={handleClose} component={UserLink}><ProfileIcon /><div>Profile</div></MenuItem>
<MenuItem onClick={handleClose} component={LogoutLink}><LogoutIcon /><div>Logout</div></MenuItem>
</Menu>
</React.Fragment>
)
}}
</WithState>
)
}
}
export default compose(
withStyles(styles)
)(LoggedInUserMenu)
-14
View File
@@ -1,14 +0,0 @@
import React, { Component } from 'react';
import {Redirect} from 'react-router';
import {auth} from '../App';
class Logout extends Component {
render() {
//window.localStorage.removeItem("user");
auth.logout();
return <Redirect to='/' />
}
}
export default Logout
-48
View File
@@ -1,48 +0,0 @@
import React from 'react';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
class Modules extends React.Component {
state = {
open: true,
};
handleClickOpen = () => {
this.setState({ open: true });
};
handleClose = () => {
this.setState({ open: false });
};
render() {
return (
<div>
<Dialog
open={this.state.open}
onClose={this.handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">{"Section under development."}</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
The functionality of this section has not been developed yet. We expect to have it for October 2018. Thanks for your understanding.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={this.handleClose} color="primary" autoFocus>
Close
</Button>
</DialogActions>
</Dialog>
</div>
);
}
}
export default Modules;
-122
View File
@@ -1,122 +0,0 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { withStyles } from '@material-ui/core/styles'
import AppBar from '@material-ui/core/AppBar'
import Toolbar from '@material-ui/core/Toolbar'
import Typography from '@material-ui/core/Typography'
import IconButton from '@material-ui/core/IconButton'
// icons
import HomeIcon from '@material-ui/icons/Home'
import BrowseIcon from '@material-ui/icons/ImportContacts'
import SearchIcon from '@material-ui/icons/Search'
import ContactIcon from '@material-ui/icons/ContactMail'
import AboutIcon from '@material-ui/icons/FormatShapes'
import { Link } from 'react-router-dom'
// components
import LoggedInUser from './LoggedInUser'
// Images
import AALogo from '../assets/logos/advanced-algos/aa-logo-dark.svg'
const AboutLink = props => <Link to='/about' {...props} />
const ContactLink = props => <Link to='/contact' {...props} />
const SearchLink = props => <Link to='/search' {...props} />
const BrowseLink = props => <Link to='/browse' {...props} />
const HomeLink = props => <Link to='/' {...props} />
const styles = {
root: {
flexGrow: 1
},
flex: {
flexGrow: 1
},
menuButton: {
marginLeft: -12,
marginRight: 20
},
img: {
margin: 20,
display: 'block',
maxWidth: 240,
maxHeight: 48
}
}
class NavBar extends Component {
constructor (props) {
super(props)
this.state = {
authId: null
}
}
componentDidMount () {
const authId = localStorage.getItem('authId')
if (authId !== null && authId !== undefined && authId !== 'undefined') {
this.setState({ authId: authId })
}
}
render () {
const { classes } = this.props
return (
<div className={classes.root}>
<AppBar position='static'>
<Toolbar>
<img className={classes.img} src={AALogo} alt='Advanced Algos' />
<Typography variant='title' color='inherit' className={classes.flex}>
Users
</Typography>
<IconButton
className={classes.menuButton}
color='inherit'
title='Home'
component={HomeLink}>
<HomeIcon />
</IconButton>
<IconButton
className={classes.menuButton}
color='inherit'
title='Browse the Users Directory'
component={BrowseLink}>
<BrowseIcon />
</IconButton>
<IconButton
className={classes.menuButton}
color='inherit'
title='Search Users'
component={SearchLink}>
<SearchIcon />
</IconButton>
<IconButton
className={classes.menuButton}
color='inherit'
title='Contact Form'
component={ContactLink}>
<ContactIcon />
</IconButton>
<IconButton
className={classes.menuButton}
color='inherit'
title='About this Module'
component={AboutLink}>
<AboutIcon />
</IconButton>
<LoggedInUser authId={this.state.authId} />
</Toolbar>
</AppBar>
</div>
)
}
}
NavBar.propTypes = {
classes: PropTypes.object.isRequired
}
export default withStyles(styles)(NavBar)
-47
View File
@@ -1,47 +0,0 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { deletePost } from '../actions/postActions'
class Post extends Component {
handleClick = () => {
this.props.deletePost(this.props.post.id);
this.props.history.push('/');
}
render() {
const post = this.props.post ? (
<div className="post">
<h4 className="center">{this.props.post.title}</h4>
<p>{this.props.post.body}</p>
<div className="center">
<button className="btn grey" onClick={this.handleClick}>
Delete Post
</button>
</div>
</div>
) : (
<div className="center">Loading post...</div>
);
return (
<div className="container">
{post}
</div>
)
}
}
const mapStateToProps = (state, ownProps) => {
let id = ownProps.match.params.post_id;
return {
post: state.posts.find(post => post.id === id)
}
}
const mapDispatchToProps = (dispatch) => {
return {
deletePost: (id) => dispatch(deletePost(id))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Post)
+16 -296
View File
@@ -1,322 +1,42 @@
import React from 'react';
import {graphql, compose} from 'react-apollo'
import {updateUserImagesMutation, getUsersQuery} from '../queries/queries'
import Avatar from '@material-ui/core/Avatar';
import classNames from 'classnames';
import ReactFilestack from 'filestack-react'
// Material-ui
import React, { Component } from 'react'
import { compose } from 'recompose'
import { withStyles } from '@material-ui/core/styles'
import Button from '@material-ui/core/Button';
import Paper from '@material-ui/core/Paper'
import Grid from '@material-ui/core/Grid'
import Typography from '@material-ui/core/Typography'
const options = {
accept: ['image/jpeg', 'image/jpg', 'image/png'],
maxFiles: 1,
imageDim: [300, 300],
maxSize: 0.25 * 1024 * 1024, // 1/4 of 1 Mb
storeTo: {
location: 's3',
},
};
const styles = theme => ({
button: {
margin: theme.spacing.unit,
marginTop: theme.spacing.unit * 3
},
row: {
display: 'flex',
justifyContent: 'center',
},
avatar: {
margin: 10,
},
bigAvatar: {
width: 60,
height: 60,
},
root: {
width: '50%',
flexGrow: 1,
padding: 10,
marginLeft: '25%',
marginTop: '2%'
marginTop: '5%',
marginBottom: '10%'
},
typography: {
width: '80%',
marginLeft: '10%',
marginTop: 40
marginTop: 40,
marginBottom: 40
}
})
class ProfileImages extends React.Component {
class ProfileImages extends Component {
constructor (props) {
super(props)
this.defaultValuesSet = false
this.state = {
avatarHandle: '',
avatarChangeDate: '',
newAvatarHandle: '',
saveDisabled: true,
uploadToolDisabled: false,
showNewAvatar: false,
needToWait: false,
removeCurrentAvatar: false
}
}
submitForm (e) {
e.preventDefault()
this.props.updateUserImagesMutation({
variables: {
id: this.state.id,
avatarHandle: this.state.newAvatarHandle,
avatarChangeDate: this.state.avatarChangeDate
},
refetchQueries: [{ query: getUsersQuery}] // This allow us to re run whatever queries are necesary after the mutation.
})
this.setState({saveDisabled: true, removeCurrentAvatar:true})
/* Before we are done, we need to update the state of the local storage. */
let user = JSON.parse(localStorage.getItem('loggedInUser'))
user.avatarHandle = this.state.newAvatarHandle
user.avatarChangeDate = this.state.avatarChangeDate
localStorage.setItem('loggedInUser', JSON.stringify(user))
}
componentWillMount () {
if (this.defaultValuesSet === false) {
let userData = localStorage.getItem('loggedInUser')
if (userData === 'undefined') { return }
let user = JSON.parse(userData)
this.defaultValuesSet = true
/* To avoid console warning, we need to take care of the fields that are null. */
if (user.avatarHandle === null) { user.avatarHandle = '' }
if (user.avatarChangeDate === null) { user.avatarChangeDate = '' }
/* Here we will check that the user does not change the avatar more often than once a day. */
let avatarChangeDate = (new Date(user.avatarChangeDate)).valueOf()
let now = (new Date()).valueOf()
let timePassed = now - avatarChangeDate
let oneDay = 1000 * 60 * 60 * 24
if (timePassed < oneDay) {
this.setState({
needToWait: true
})
} else {
this.setState({
needToWait: false
})
}
/* Now we are ready to set the initial state. */
this.setState({
id: user.id,
avatarHandle: user.avatarHandle,
avatarChangeDate: user.avatarChangeDate
})
}
}
onSuccess = (uploadResults) => {
console.log('onSuccess')
console.log(uploadResults)
const handle = uploadResults.filesUploaded[0].handle
let localDate = new Date()
let currentDate = new Date(Date.UTC(
localDate.getUTCFullYear(),
localDate.getUTCMonth(),
localDate.getUTCDate(),
localDate.getUTCHours(),
localDate.getUTCMinutes(),
localDate.getUTCSeconds(),
localDate.getUTCMilliseconds())
)
currentDate.toISOString()
this.setState(
{
newAvatarHandle: handle,
avatarChangeDate: currentDate,
showNewAvatar: true,
uploadToolDisabled: true,
saveDisabled: false
}
)
}
onError = (err) => {
console.log('onError')
console.log(err)
}
onRemoveSuccess = (err) => {
console.log('onRemoveSuccess')
console.log(err)
}
showCurrentAvatar() {
const { classes } = this.props
if (this.state.removeCurrentAvatar === false) {
return (
<div>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
This is your current Avatar:
</Typography>
<Grid container justify='center' >
<Grid item>
<Avatar
alt="Avatar"
src={"https://cdn.filestackcontent.com/" + this.state.avatarHandle}
className={classNames(classes.bigAvatar)}
/>
</Grid>
</Grid>
</div>
)
} else {
return (
<div>
<ReactFilestack
apikey={'AH97QJOXTHwdBXjydQgABz'}
mode="remove"
options={options}
fileHandle={this.state.avatarHandle}
onSuccess={this.onRemoveSuccess}
onError={this.onError}
link
></ReactFilestack>
</div>
)
}
}
showNewAvatar() {
if (this.state.showNewAvatar === true) {
const { classes } = this.props
return (
<div>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
This is how your new avatar will look like. Press save to proceed with the change.
</Typography>
<Grid container justify='center' >
<Grid item>
<Avatar
alt="Avatar"
src={"https://cdn.filestackcontent.com/" + this.state.newAvatarHandle}
className={classNames(classes.bigAvatar)}
/>
</Grid>
</Grid>
</div>
)
}
}
showUploadTool() {
const { classes } = this.props
if (this.state.needToWait === true) {
return (
<div>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
You updated your Avatar in the last 24 hours. As a protection against denial of service attacks, the system does not allow users to update their Avatar in less than 24 hs since their last update. Please come back tomorrow.
</Typography>
</div>
)
} else {
return(
<div>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
If you want, you can choose a new one by picking an image from your computer, camera or the web, and crop it with the following tool.
</Typography>
<Grid container justify='center' >
<Grid item>
<Button
disabled={this.state.uploadToolDisabled}
variant='contained'
color='secondary'
className={classes.button}>
<ReactFilestack
apikey={'AH97QJOXTHwdBXjydQgABz'}
options={options}
onSuccess={this.onSuccess}
onError={this.onError}
link
>File Upload Tool</ReactFilestack>
</Button>
</Grid>
</Grid>
</div>
)
}
}
render() {
render () {
const { classes } = this.props
return (
<Paper className={classes.root}>
<Typography className={classes.typography} variant='headline' gutterBottom>
Profile Images
<React.Fragment>
<Paper className={classes.root}>
<Typography className={classes.typography} variant='h5' gutterBottom>
Comming Soon
</Typography>
<form onSubmit={this.submitForm.bind(this)}>
{this.showCurrentAvatar()}
{this.showUploadTool()}
{this.showNewAvatar()}
<Grid container justify='center' >
<Grid item>
<Button
disabled={this.state.saveDisabled}
variant='contained'
color='secondary'
className={classes.button}
onClick={this.submitForm.bind(this)}
>Save</Button>
</Grid>
</Grid>
</form>
</Paper>
);
</Paper>
</React.Fragment>
)
}
}
export default compose(
graphql(updateUserImagesMutation, {name: 'updateUserImagesMutation'}),
withStyles(styles)
)(ProfileImages) // This technique binds more than one query to a single component.
)(ProfileImages)
+72 -45
View File
@@ -27,11 +27,11 @@ import AALogo from '../img/aa-logo.png'
const styles = theme => ({
root: {
width: '50%',
width: '100%',
flexGrow: 1,
padding: 10,
marginLeft: '25%',
marginTop: '2%'
marginTop: '5%',
marginBottom: '10%'
},
inputField: {
width: '80%',
@@ -85,7 +85,8 @@ class ProfileSheet extends Component {
firstNameError: false,
middleNameError: false,
lastNameError: false,
bioError: false
bioError: false,
updated: false
}
}
@@ -96,7 +97,7 @@ class ProfileSheet extends Component {
<MenuItem><em>Loading roles</em></MenuItem>
)
} else {
return data.roles.map(role => {
return data.users_Roles.map(role => {
return (
<MenuItem key={role.id} value={role.id}>{ role.name }</MenuItem>
)
@@ -108,7 +109,6 @@ class ProfileSheet extends Component {
e.preventDefault()
this.props.updateUserMutation({
variables: {
id: this.state.id,
firstName: this.state.firstName,
middleName: this.state.middleName,
lastName: this.state.lastName,
@@ -135,6 +135,8 @@ class ProfileSheet extends Component {
user.role.id = this.state.roleId
localStorage.setItem('loggedInUser', JSON.stringify(user))
this.setState({updated: true})
}
handleCheckBoxes (e) {
@@ -241,10 +243,11 @@ class ProfileSheet extends Component {
componentWillMount () {
if (this.defaultValuesSet === false) {
let authId = localStorage.getItem('authId')
let authUser = JSON.parse(localStorage.getItem('user'))
let authId = authUser.authId
let userData = localStorage.getItem('loggedInUser')
if (userData === 'undefined') { return }
if (userData === 'undefined' || userData === null) { return }
let user = JSON.parse(userData)
this.defaultValuesSet = true
@@ -279,8 +282,8 @@ class ProfileSheet extends Component {
displayIdentityProvider () {
const { classes } = this.props
let authId = this.state.authId
console.log('state', this.state)
if (authId !== undefined) {
if (authId !== undefined && authId !== null) {
let authArray = this.state.authId.split('|')
let identityProvider = authArray[0]
@@ -301,19 +304,29 @@ class ProfileSheet extends Component {
}
}
render () {
displayButtonTitle () {
if (this.state.updated === true) {
return 'Updated'
} else {
return 'Update'
}
}
addForm () {
const { classes } = this.props
return (
<Paper className={classes.root}>
<Typography className={classes.typography} variant='headline' gutterBottom>
Profile Sheet
</Typography>
<form onSubmit={this.submitForm.bind(this)}>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
Use this form to control the information you keep at the Advanced Algos system about yourself.
<Typography className={classes.typography} variant='h5' gutterBottom>
Profile Sheet
</Typography>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
Use this form to control the information you keep at the Advanced Algos system about yourself.
</Typography>
<Grid container justify='center' >
<Grid item>
{this.displayIdentityProvider()}
@@ -321,8 +334,8 @@ class ProfileSheet extends Component {
</Grid>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
This is your basic information we have gotten from the identity provider you used to sign up. This information can not be changed.
</Typography>
This is your basic information we have gotten from the identity provider you used to sign up. This information can not be changed.
</Typography>
<TextField
id='alias'
@@ -348,10 +361,10 @@ class ProfileSheet extends Component {
id='emailVerified'
checked={this.rightCheckboxValue(this.state.emailVerified)}
color='primary'
/>
}
/>
}
label='Email Verified'
/>
/>
<Grid container justify='center' >
<Grid item>
@@ -360,8 +373,8 @@ class ProfileSheet extends Component {
</Grid>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
Complete your profile with the following optional information. Providing your real name might help other users trust you more.
</Typography>
Complete your profile with the following optional information. Providing your real name might help other users trust you more.
</Typography>
<TextField
error={this.state.firstNameError}
@@ -371,7 +384,7 @@ class ProfileSheet extends Component {
label='First Name'
className={classes.inputField}
onChange={this.handleTextField.bind(this)}
/>
/>
<TextField
error={this.state.middleNameError}
@@ -381,7 +394,7 @@ class ProfileSheet extends Component {
label='Middle Name'
className={classes.inputField}
onChange={this.handleTextField.bind(this)}
/>
/>
<TextField
error={this.state.lastNameError}
@@ -391,11 +404,11 @@ class ProfileSheet extends Component {
label='Last Name'
className={classes.inputField}
onChange={this.handleTextField.bind(this)}
/>
/>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
If you wish, you can add a short paragraph with your Bio or anything you would like to communicate to whoever finds your user profile.
</Typography>
If you wish, you can add a short paragraph with your Bio or anything you would like to communicate to whoever finds your user profile.
</Typography>
<TextField
error={this.state.bioError}
@@ -405,11 +418,11 @@ class ProfileSheet extends Component {
label='Bio'
className={classes.inputField}
onChange={this.handleTextField.bind(this)}
/>
/>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
Check the following options to enable specialized tools designed for each role. You can allways come back and change these settings later.
</Typography>
Check the following options to enable specialized tools designed for each role. You can allways come back and change these settings later.
</Typography>
<FormGroup row className={classes.inputField}>
<Grid container justify='center' >
@@ -422,10 +435,10 @@ class ProfileSheet extends Component {
onChange={this.handleCheckBoxes.bind(this)}
checked={this.rightCheckboxValue(this.state.isDeveloper)}
color='secondary'
/>
}
/>
}
label='Developer'
/>
/>
</Grid>
<Grid item>
<FormControlLabel
@@ -436,10 +449,10 @@ class ProfileSheet extends Component {
onChange={this.handleCheckBoxes.bind(this)}
checked={this.rightCheckboxValue(this.state.isTrader)}
color='secondary'
/>
}
/>
}
label='Trader'
/>
/>
</Grid>
<Grid item>
<FormControlLabel
@@ -450,10 +463,10 @@ class ProfileSheet extends Component {
onChange={this.handleCheckBoxes.bind(this)}
checked={this.rightCheckboxValue(this.state.isDataAnalyst)}
color='secondary'
/>
}
/>
}
label='Data Analyst'
/>
/>
</Grid>
</Grid>
</FormGroup>
@@ -462,8 +475,8 @@ class ProfileSheet extends Component {
<FormControl className={classes.inputField}>
<InputLabel shrink htmlFor='select'>
Current Role
</InputLabel>
Current Role
</InputLabel>
<Select
id='select'
ref='select'
@@ -473,7 +486,7 @@ class ProfileSheet extends Component {
displayEmpty
name='select'
className={classes.selectEmpty}
>
>
{ this.displayRoles() }
</Select>
<FormHelperText>Select from the list your current role</FormHelperText>
@@ -481,12 +494,26 @@ class ProfileSheet extends Component {
<Grid container justify='center' >
<Grid item>
<Button variant='contained' color='secondary' className={classes.button} onClick={this.submitForm.bind(this)}>Update</Button>
<Button
variant='contained'
color='secondary'
className={classes.button}
onClick={this.submitForm.bind(this)}
disabled={this.state.updated}
>{this.displayButtonTitle()}</Button>
</Grid>
</Grid>
</form>
</Paper>
)
}
render () {
return (
<React.Fragment>
<div className='container'>
{this.addForm()}
</div>
</React.Fragment>
)
}
}
+18 -10
View File
@@ -1,7 +1,8 @@
import React, { Component } from 'react'
import UserSearch from './UserSearch'
import {compose} from 'react-apollo'
import CssBaseline from '@material-ui/core/CssBaseline'
import Paper from '@material-ui/core/Paper'
import BannerTopBar from './BannerTopBar'
// Materia UI
@@ -9,24 +10,31 @@ import { withStyles } from '@material-ui/core/styles'
const styles = theme => ({
root: {
width: '100%',
flexGrow: 1,
padding: 60,
margin: 2
padding: 10,
marginTop: '5%',
marginBottom: '10%'
}
})
class Search extends Component {
constructor (props) {
super(props)
this.state = {
}
}
render () {
const { classes } = this.props
return (
<React.Fragment>
<CssBaseline />
<UserSearch />
<BannerTopBar
size='medium'
title='Users Search'
text='Find anyone involved in Advanced Algos here.'
backgroundUrl='https://advancedalgos.net/img/photos/users.jpg'
/>
<div className='container'>
<Paper className={classes.root}>
<UserSearch />
</Paper>
</div>
</React.Fragment>
)
}
+7 -2
View File
@@ -1,11 +1,16 @@
import React from 'react'
import UserTabs from './UserTabs'
import CssBaseline from '@material-ui/core/CssBaseline'
import BannerTopBar from './BannerTopBar'
const User = () => {
return (
<React.Fragment>
<CssBaseline />
<BannerTopBar
size='medium'
title='Your Profile'
text='Manage your profile info, pictures and more.'
backgroundUrl='https://advancedalgos.net/img/photos/users.jpg'
/>
<UserTabs />
</React.Fragment>
)
+10 -9
View File
@@ -30,13 +30,13 @@ import Slide from '@material-ui/core/Slide';
import UserProfile from './UserProfile';
// Images
import PortraitImage from '../img/portrait.jpg'
import UserDefaultPicture from '../img/user-default-pic.jpg'
const styles = theme => ({
root: {
flexGrow: 1,
padding: 60,
margin: 2,
paddingTop:30,
paddingBottom:30,
flexGrow: 1
},
card: {
maxWidth: 345,
@@ -89,13 +89,14 @@ class UserList extends Component {
};
displayUsers(){
let data = this.props.getUsersQuery;
const { classes } = this.props;
if(data.loading){
return ( <div> Loading Users... </div>);
} else {
return data.users.map(user => {
return data.users_Users.map(user => {
return (
@@ -107,12 +108,12 @@ class UserList extends Component {
<CardActionArea>
<CardMedia
className={classes.media}
image={PortraitImage}
image={UserDefaultPicture}
title="User Profile"
/>
<CardContent>
<Typography gutterBottom variant="headline" component="h2">
<Typography gutterBottom variant="h5" component="h2">
{user.alias}
</Typography>
<Typography className={classes.typography} gutterBottom>
@@ -135,7 +136,7 @@ class UserList extends Component {
<IconButton color="inherit" onClick={this.handleClose} aria-label="Close">
<CloseIcon />
</IconButton>
<Typography variant="title" color="inherit" className={classes.flex}>
<Typography variant="h6" color="inherit" className={classes.flex}>
User Profile
</Typography>
<Button color="inherit" onClick={this.handleClose}>
@@ -166,7 +167,7 @@ class UserList extends Component {
const { classes } = this.props;
return (
<React.Fragment>
<Grid container justify="center" spacing={24} className={classes.root}>
<Grid container justify="center" spacing={40} className={classes.root}>
{this.displayUsers()}
</Grid>
</React.Fragment>
+57 -14
View File
@@ -14,7 +14,7 @@ import Typography from '@material-ui/core/Typography'
import Divider from '@material-ui/core/Divider'
// Images
import PortraitImage from '../img/portrait.jpg'
import UserDefaultPicture from '../img/user-default-pic.jpg'
const styles = theme => ({
root: {
@@ -23,7 +23,8 @@ const styles = theme => ({
margin: 2
},
card: {
width: '80%',
maxWidth: 500,
minWidth: 500,
paddingTop: '30'
},
media: {
@@ -46,8 +47,53 @@ const styles = theme => ({
class UserProfile extends Component {
displayNames () {
const user = this.props.data.users_User
const { classes } = this.props
if (user.firstName !== null && user.lastName !== null) {
return (
<Typography className={classes.typography} gutterBottom variant='h5' component='h2'>
{ user.firstName + ' ' + user.lastName}
</Typography>
)
}
}
displayRole () {
const user = this.props.data.users_User
const { classes } = this.props
if (user.role.name !== null && user.role.name !== 'Not Defined') {
return (
<div>
<Divider />
<Typography className={classes.typography} align='left' gutterBottom variant='subtitle1' component='h2'>
{ user.role.name }
</Typography>
</div>
)
}
}
displayBio () {
const user = this.props.data.users_User
const { classes } = this.props
if (user.bio !== null && user.bio !== '') {
return (
<div>
<Divider />
<Typography className={classes.typography} component='p'>
{ user.bio }
</Typography>
</div>
)
}
}
displayUserProfile () {
const {user} = this.props.data
const user = this.props.data.users_User
const { classes } = this.props
if (user) {
@@ -61,24 +107,21 @@ class UserProfile extends Component {
<CardActionArea>
<CardMedia
className={classes.media}
image={PortraitImage}
image={UserDefaultPicture}
title='User Profile'
/>
<CardContent>
<Typography className={classes.typography} gutterBottom variant='headline' component='h2'>
{ user.firstName } { user.lastName } ( {user.alias} )
</Typography>
<Divider />
<Typography className={classes.typography} align='left' gutterBottom variant='subheading' component='h2'>
{ user.role.name }
</Typography>
<Divider />
{this.displayNames()}
<Typography className={classes.typography} component='p'>
{ user.bio }
<Typography className={classes.typography} gutterBottom variant='h6' component='h3'>
{user.alias}
</Typography>
{this.displayRole()}
{this.displayBio()}
</CardContent>
</CardActionArea>
</Card>
+13 -5
View File
@@ -17,7 +17,7 @@ import Grid from '@material-ui/core/Grid'
import TextField from '@material-ui/core/TextField'
// Images
import PortraitImage from '../img/portrait.jpg'
import UserDefaultPicture from '../img/user-default-pic.jpg'
const styles = theme => ({
card: {
@@ -44,6 +44,8 @@ const styles = theme => ({
flex: 1
},
grid: {
width: '80%',
marginLeft: '10%',
paddingTop: '30',
marginTop: 30
},
@@ -156,10 +158,10 @@ class UserSearch extends Component {
if (data.loading) {
return (<div> Loading Users... </div>)
} else {
if (data.usersSearch === undefined) {
if (data.users_UsersSearch === undefined) {
return (<div> No Users to Display </div>)
} else {
return data.usersSearch.map(user => {
return data.users_UsersSearch.map(user => {
return (
<Grid key={user.id} item>
@@ -170,12 +172,12 @@ class UserSearch extends Component {
<CardActionArea>
<CardMedia
className={classes.media}
image={PortraitImage}
image={UserDefaultPicture}
title='User Profile'
/>
<CardContent>
<Typography gutterBottom variant='headline' component='h2'>
<Typography gutterBottom component='h2'>
{user.alias}
</Typography>
</CardContent>
@@ -196,9 +198,14 @@ class UserSearch extends Component {
}
}
componentDidMount () {
window.dispatchEvent(new Event('load')) // This is a workaround to solve the problem that the slider does not show up
}
render () {
const { classes } = this.props
return (
<div>
<form onSubmit={this.submitForm.bind(this)}>
@@ -257,6 +264,7 @@ class UserSearch extends Component {
{this.displayUsers()}
</Grid>
</div>
)
}
}
+2 -1
View File
@@ -62,9 +62,10 @@ class UserTabs extends React.Component {
scrollButtons="off"
indicatorColor="primary"
textColor="primary"
fullWidth
>
<Tab label="Profile Sheet" icon={<ProfileSheetIcon />} />
<Tab label="Profile Images" icon={<ProfileImagesIcon />} />
<Tab disabled label="Profile Images" icon={<ProfileImagesIcon />} />
<Tab label="Your Referrer" icon={<YourReferrerIcon />} />
<Tab label="Your Descendents" icon={<DescendentsIcon />} />
</Tabs>
+20 -9
View File
@@ -13,11 +13,11 @@ import DescendentsTree from './DescendentsTree'
const styles = theme => ({
root: {
width: '50%',
width: '100%',
flexGrow: 1,
padding: 10,
marginLeft: '25%',
marginTop: '2%'
marginTop: '5%',
marginBottom: '10%'
},
typography: {
width: '80%',
@@ -59,18 +59,19 @@ class YourDescendents extends Component {
}
}
render () {
addForm () {
const { classes } = this.props
return (
<Paper className={classes.root}>
<Typography className={classes.typography} variant='headline' gutterBottom>
Your Descendents
</Typography>
<Typography className={classes.typography} variant='h5' gutterBottom>
Your Decendents
</Typography>
<Typography className={classes.typography} variant='body1' gutterBottom align='left'>
These are your decendents within the project. Your children referred you as the one who brought them to the project, while
your grandchildren referred your children and so on.
your grandchildren referred your children and so on. In order to be able to see your descendents, the users who you referred
must first point to you as your referrer.
</Typography>
<DescendentsTree userId={this.state.id} />
@@ -78,6 +79,16 @@ class YourDescendents extends Component {
</Paper>
)
}
render () {
return (
<React.Fragment>
<div className='container'>
{this.addForm()}
</div>
</React.Fragment>
)
}
}
export default compose(
+17 -9
View File
@@ -15,11 +15,11 @@ import Typography from '@material-ui/core/Typography'
const styles = theme => ({
root: {
width: '50%',
width: '100%',
flexGrow: 1,
padding: 10,
marginLeft: '25%',
marginTop: '2%'
marginTop: '5%',
marginBottom: '10%'
},
typography: {
width: '80%',
@@ -60,7 +60,6 @@ class YourReferrer extends Component {
this.props.updateReferrerMutation({
variables: {
id: this.state.id,
referrerId: referrerUser.id
}
})
@@ -126,18 +125,27 @@ class YourReferrer extends Component {
}
}
render () {
addForm () {
const { classes } = this.props
return (
<Paper className={classes.root}>
<Typography className={classes.typography} variant='headline' gutterBottom>
Your Referrer
</Typography>
<Typography className={classes.typography} variant='h5' gutterBottom>
Your Referrer
</Typography>
{this.renderMode()}
</Paper>
)
}
render () {
return (
<React.Fragment>
<div className='container'>
{this.addForm()}
</div>
</React.Fragment>
)
}
}
export default compose(
-21
View File
@@ -1,21 +0,0 @@
import NavBar from './navbar'
import Footer from './footer'
import Callback from './callback'
import Home from './home'
import About from './about'
import Dashboard from './dashboard'
import Teams from './teams'
import { theme, globalStyles } from './theme'
export {
NavBar,
Footer,
Callback,
Home,
About,
Dashboard,
Teams,
theme,
globalStyles
}
-21
View File
@@ -1,21 +0,0 @@
import NavBar from './navbar'
import Footer from './footer'
import Callback from './callback'
import Home from './home'
import About from './about'
import Dashboard from './dashboard'
import Teams from './teams'
import { theme, globalStyles } from './theme'
export {
NavBar,
Footer,
Callback,
Home,
About,
Dashboard,
Teams,
theme,
globalStyles
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 689 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

-1
View File
@@ -1 +0,0 @@
+23 -5
View File
@@ -1,6 +1,24 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import React from 'react'
import { Route, Switch } from 'react-router-dom'
import { MuiPickersUtilsProvider } from 'material-ui-pickers'
import LuxonUtils from 'material-ui-pickers/utils/luxon-utils'
import Home from './components/Home'
import User from './components/User'
import Browse from './components/Browse'
import Search from './components/Search'
const App = () => (
<MuiPickersUtilsProvider utils={LuxonUtils}>
<Switch>
<Route exact path='/users/' component={Home} />
<Route path='/users/user' component={User} />
<Route path='/users/browse' component={Browse} />
<Route path='/users/search' component={Search} />
</Switch>
</MuiPickersUtilsProvider>
)
export default App
ReactDOM.render(<App />, document.getElementById('root'));
-36
View File
@@ -1,36 +0,0 @@
mutation {
addUser (alias: "aaa", firstName:"fff", lastName: "lll", roleId: "1", isTrader: 1, isDeveloper: 0) {
alias
isTrader
isDeveloper
}
}
mutation {
updateUser (
id: "5b8d152f6f4d5b3db44ee103" ,
alias: "luis",
firstName:"Luis",
lastName: "Molina",
isDeveloper: 1,
isTrader: 1,
isDataAnalyst: 1,
roleId: "2"
) {
alias
}
}
query {
users{
alias
firstName
isDeveloper
role{
id
name
}
}
}
+9 -32
View File
@@ -2,7 +2,7 @@ import gql from 'graphql-tag'
const getUsersQuery = gql`
{
users {
users_Users {
id
alias
firstName
@@ -18,7 +18,7 @@ const getUsersQuery = gql`
`
const getUserProfileQuery = gql`
query($id: ID){
user (id: $id){
users_User (id: $id){
id
alias
firstName
@@ -35,7 +35,7 @@ query($id: ID){
`
const getUserByAuthIdQuery = gql`
query($authId: String){
userByAuthId (authId: $authId){
users_UserByAuthId (authId: $authId){
id
referrerId
alias
@@ -63,7 +63,7 @@ query(
$middleName: String,
$lastName: String
){
usersSearch (alias: $alias, firstName: $firstName, middleName: $middleName, lastName: $lastName){
users_UsersSearch (alias: $alias, firstName: $firstName, middleName: $middleName, lastName: $lastName){
id
alias
firstName
@@ -76,7 +76,7 @@ const getDescendentsQuery = gql`
query(
$id: String
){
descendents (id: $id){
users_Descendents (id: $id){
id
alias
firstName
@@ -104,7 +104,7 @@ query(
`
const getRolesQuery = gql`
{
roles {
users_Roles {
id
name
}
@@ -112,7 +112,6 @@ const getRolesQuery = gql`
`
const updateUserMutation = gql`
mutation(
$id: ID!,
$firstName:String,
$middleName:String,
$lastName:String,
@@ -123,8 +122,7 @@ mutation(
$roleId:String!
)
{
updateUser (
id: $id,
users_UpdateUser (
firstName:$firstName,
middleName: $middleName,
lastName: $lastName,
@@ -142,12 +140,10 @@ mutation(
`
const updateReferrerMutation = gql`
mutation(
$id: ID!,
$referrerId:String!
)
{
updateUserReferrer (
id: $id,
users_UpdateUserReferrer (
referrerId:$referrerId
)
{
@@ -156,24 +152,6 @@ mutation(
}
}
`
const updateUserImagesMutation = gql`
mutation(
$id: ID!,
$avatarHandle:String,
$avatarChangeDate:String
)
{
updateUserImages (
id: $id,
avatarHandle:$avatarHandle,
avatarChangeDate: $avatarChangeDate
)
{
id
alias
}
}
`
export {
getUsersQuery,
getUserByAuthIdQuery,
@@ -182,6 +160,5 @@ export {
getUsersBySearchFields,
getDescendentsQuery,
updateUserMutation,
updateReferrerMutation,
updateUserImagesMutation
updateReferrerMutation
}
-117
View File
@@ -1,117 +0,0 @@
// In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
// This link also includes instructions on opting out of this behavior.
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export default function register() {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Lets check if a service worker still exists or not.
checkValidServiceWorker(swUrl);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://goo.gl/SC7cgQ'
);
});
} else {
// Is not local host. Just register service worker
registerValidSW(swUrl);
}
});
}
}
function registerValidSW(swUrl) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and
// the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is
// available; please refresh." message in your web app.
console.log('New content is available; please refresh.');
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
if (
response.status === 404 ||
response.headers.get('content-type').indexOf('javascript') === -1
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}
-5
View File
@@ -59,11 +59,6 @@ export const globalStyles = theme => ({
[theme.breakpoints.up('sm')]: {
paddingBottom: theme.spacing.unit * 2
}
},
footer: {
marginTop: theme.spacing.unit * 8,
borderTop: `1px solid ${theme.palette.divider}`,
padding: `${theme.spacing.unit * 6}px 0`
}
})
-60
View File
@@ -1,60 +0,0 @@
export function isDefined (d) {
return d !== null && typeof d !== 'undefined'
}
export function isNotDefined (d) {
return !isDefined(d)
}
export const isArray = Array.isArray
export function isObject (d) {
return isDefined(d) && typeof d === 'object' && !Array.isArray(d)
}
export function isEmpty (obj) {
for (var key in obj) {
if (obj.hasOwnProperty(key)) return false
}
return true
}
export function validObject (object, ...keys) {
return keys.reduce((a, b) => (a || { })[b], object) !== undefined
}
export function mergeDeep (target, ...sources) {
if (!sources.length) return target
const source = sources.shift()
if (isObject(target) && isObject(source)) {
for (const key in source) {
if (isObject(source[key])) {
if (!target[key]) Object.assign(target, { [key]: {} })
mergeDeep(target[key], source[key])
} else {
Object.assign(target, { [key]: source[key] })
}
}
}
return mergeDeep(target, ...sources)
}
export function deleteCookie (c) {
document.cookie.split(';').forEach(function (c) { document.cookie = c.replace(/^ +/, '').replace(/=.*/, '=;expires=' + new Date().toUTCString() + ';path=/') })
}
export function slugify (string) {
const a = 'àáäâãåèéëêìíïîòóöôùúüûñçßÿœæŕśńṕẃǵǹḿǘẍźḧ·/_,:;'
const b = 'aaaaaaeeeeiiiioooouuuuncsyoarsnpwgnmuxzh------'
const p = new RegExp(a.split('').join('|'), 'g')
return string.toString().toLowerCase()
.replace(/\s+/g, '-') // Replace spaces with -
.replace(p, c => b.charAt(a.indexOf(c))) // Replace special characters
.replace(/&/g, '-and-') // Replace & with 'and'
.replace(/[^\w-]+/g, '') // Remove all non-word characters
.replace(/--+/g, '-') // Replace multiple - with single -
.replace(/^-+/, '') // Trim - from start of text
.replace(/-+$/, '') // Trim - from end of text
}
-26
View File
@@ -1,34 +1,8 @@
const getStateFromStorage = version => {
const localState = JSON.parse(window.localStorage.getItem('aa-team'))
try {
if (localState !== undefined && localState !== null) {
if (
localState.appVersion !== undefined &&
localState.appVersion !== null
) {
if (localState.appVersion === version) {
return localState
}
}
} else {
throw new Error()
}
} catch (error) {
return false
}
}
const storeStateInStorage = state =>
window.localStorage.setItem('aa-team', JSON.stringify(state))
const getItem = async name => window.localStorage.getItem(name)
const setItem = async (name, value) => window.localStorage.setItem(name, value)
const removeItem = async name => window.localStorage.removeItem(name)
export {
getStateFromStorage,
storeStateInStorage,
getItem,
setItem,
removeItem
-160
View File
@@ -1,160 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import { NavLink } from 'react-router-dom'
import { withStyles } from '@material-ui/core/styles'
import classNames from 'classnames'
import Typography from '@material-ui/core/Typography'
import Grid from '@material-ui/core/Grid'
import aalogo from '../../assets/logos/advanced-algos/aa-logo-vert.svg'
const styles = theme => ({
'@global': {
body: {
backgroundColor: theme.palette.common.white
}
},
layout: {
width: 'auto',
marginTop: theme.spacing.unit * 7,
marginLeft: theme.spacing.unit * 3,
marginRight: theme.spacing.unit * 3,
[theme.breakpoints.up(1200 + theme.spacing.unit * 3 * 2)]: {
width: 1200,
marginLeft: 'auto',
marginRight: 'auto'
}
},
footer: {
borderTop: `1px solid ${theme.palette.divider}`,
padding: `${theme.spacing.unit * 6}px 0`
},
footerContainer: {
marginRight: theme.spacing.unit * 8,
marginLeft: theme.spacing.unit * 8
},
footerLink: {
textDecoration: 'none'
}
})
const Footer = ({ classes }) => {
return (
<footer className={classNames(classes.footer, classes.layout)}>
<Grid
container
spacing={32}
justify='space-evenly'
className={classNames(classes.footerContainer)}
>
<Grid item xs>
<Typography variant='title' color='textPrimary' gutterBottom>
Pages
</Typography>
<NavLink to='/' className={classNames(classes.footerLink)}>
<Typography variant='subheading' color='textSecondary'>
Home
</Typography>
</NavLink>
<NavLink to='/browse' className={classNames(classes.footerLink)}>
<Typography variant='subheading' color='textSecondary'>
Browse
</Typography>
</NavLink>
<NavLink to='/search' className={classNames(classes.footerLink)}>
<Typography variant='subheading' color='textSecondary'>
Search
</Typography>
</NavLink>
<NavLink to='/contact' className={classNames(classes.footerLink)}>
<Typography variant='subheading' color='textSecondary'>
Contact
</Typography>
</NavLink>
<NavLink to='/about' className={classNames(classes.footerLink)}>
<Typography variant='subheading' color='textSecondary'>
About
</Typography>
</NavLink>
</Grid>
<Grid item xs>
<Typography variant='title' color='textPrimary' gutterBottom>
Support
</Typography>
<a
href='https://advancedalgos.net/documentation-quick-start.shtml'
target='_blank>'
className={classNames(classes.footerLink)}
>
<Typography variant='subheading' color='textSecondary'>
Documentation
</Typography>
</a>
<a
href='https://t.me/advancedalgoscommunity'
target='_blank>'
className={classNames(classes.footerLink)}
>
<Typography variant='subheading' color='textSecondary'>
Telegram
</Typography>
</a>
</Grid>
<Grid item xs>
<Typography variant='title' color='textPrimary' gutterBottom>
Modules
</Typography>
<a
href='https://develop.advancedalgos.net'
target='_blank>'
className={classNames(classes.footerLink)}
>
<Typography variant='subheading' color='textSecondary'>
Platform
</Typography>
</a>
<a
href='https://users.advancedalgos.net'
target='_blank>'
className={classNames(classes.footerLink)}
>
<Typography variant='subheading' color='textSecondary'>
Users
</Typography>
</a>
<a
href='https://teams.advancedalgos.net'
target='_blank>'
className={classNames(classes.footerLink)}
>
<Typography variant='subheading' color='textSecondary'>
Teams
</Typography>
</a>
<a
href='https://keyvault.advancedalgos.net'
target='_blank>'
className={classNames(classes.footerLink)}
>
<Typography variant='subheading' color='textSecondary'>
Key Vault
</Typography>
</a>
</Grid>
<Grid item xs>
<NavLink to='/'>
<img alt='' src={aalogo} width={98} height={140} />
</NavLink>
</Grid>
</Grid>
</footer>
)
}
Footer.propTypes = {
classes: PropTypes.object.isRequired
}
export default withStyles(styles)(Footer)
-21
View File
@@ -1,21 +0,0 @@
// import NavBar from './navbar'
import Footer from './footer'
// import Callback from './callback'
// import Home from './home'
// import About from './about'
// import Dashboard from './dashboard'
// import Teams from './teams'
// import { theme, globalStyles } from './theme'
export {
// NavBar,
Footer
// Callback,
// Home,
// About,
// Dashboard,
// Teams,
// theme,
// globalStyles
}
-47
View File
@@ -1,47 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import { graphql } from 'react-apollo'
import LoggedInMenu from './LoggedInMenu'
import { GetCurrentMember } from '../../graphql/members'
import { isDefined } from '../../utils/js-helpers'
export const LoggedIn = props => {
let { data, user, auth } = props
console.log('LoggedIn :', data, user)
let displayName = 'No Display Name'
if (isDefined(user.alias)) {
displayName = user.alias
}
if (isDefined(user.nickname)) {
displayName = user.nickname
}
if (isDefined(user.firstName)) {
displayName = user.firstName
}
if (isDefined(user.firstName) && isDefined(user.lastName)) {
displayName = user.firstName + ' ' + user.lastName
}
return (
<div>
<p>
<LoggedInMenu menuLabel={displayName} auth={auth} />
</p>
</div>
)
}
LoggedIn.propTypes = {
data: PropTypes.object,
user: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired
}
export default graphql(GetCurrentMember)(LoggedIn) // This binds the querty to the component
-77
View File
@@ -1,77 +0,0 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Button from '@material-ui/core/Button'
import Menu from '@material-ui/core/Menu'
import MenuItem from '@material-ui/core/MenuItem'
import { Link } from 'react-router-dom'
import ProfileIcon from '@material-ui/icons/Person'
import LogoutIcon from '@material-ui/icons/DirectionsWalk'
const UserLink = props => <Link to='/user' {...props} />
const LogoutLink = props => <Link to='/' {...props} />
class LoggedInUserMenu extends Component {
constructor (props) {
super(props)
this.handleMenu = this.handleMenu.bind(this)
this.handleClose = this.handleClose.bind(this)
this.handleLogout = this.handleLogout.bind(this)
this.state = {
menu: null
}
}
render () {
const { menuLabel } = this.props
return (
<React.Fragment>
<Button
aria-owns={this.state.open ? 'render-props-menu' : null}
aria-haspopup='true'
onClick={e => this.handleMenu(e)}
color='inherit'
>
{menuLabel}
</Button>
<Menu
id='render-props-menu'
anchorEl={this.state.menu}
open={Boolean(this.state.menu)}
onClose={this.handleClose}
>
<MenuItem onClick={this.handleClose} component={UserLink}>
<ProfileIcon />
<div>Profile</div>
</MenuItem>
<MenuItem onClick={this.handleLogout} component={LogoutLink}>
<LogoutIcon />
<div>Logout</div>
</MenuItem>
</Menu>
</React.Fragment>
)
}
handleMenu (e) {
this.setState({ menu: e.currentTarget })
}
handleClose () {
this.setState({ menu: null })
}
handleLogout () {
this.props.auth.logout()
this.setState({ menu: null })
}
}
LoggedInUserMenu.propTypes = {
menuLabel: PropTypes.string.isRequired,
auth: PropTypes.object.isRequired
}
export default LoggedInUserMenu
-15
View File
@@ -1,15 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import Button from '@material-ui/core/Button'
export const LoggedOut = ({ auth }) => (
<div onClick={() => auth.login()}>
<Button color='inherit'>Login / Sign up</Button>
</div>
)
LoggedOut.propTypes = {
auth: PropTypes.object.isRequired
}
export default LoggedOut // This binds the querty to the component
-141
View File
@@ -1,141 +0,0 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { withStyles } from '@material-ui/core/styles'
import AppBar from '@material-ui/core/AppBar'
import Toolbar from '@material-ui/core/Toolbar'
import Typography from '@material-ui/core/Typography'
import IconButton from '@material-ui/core/IconButton'
import Button from '@material-ui/core/Button'
// icons
import HomeIcon from '@material-ui/icons/Home'
import DashboardIcon from '@material-ui/icons/Dashboard'
import { Link } from 'react-router-dom'
import { getItem } from '../../utils/local-storage'
// components
import { LoggedIn } from './LoggedIn'
import { LoggedOut } from './LoggedOut'
import AALogo from '../../assets/logos/advanced-algos/aa-logo-dark.svg'
const AboutLink = props => <Link to='/about' {...props} />
const TeamsLink = props => <Link to='/teams' {...props} />
const DashboardLink = props => <Link to='/dashboard' {...props} />
const HomeLink = props => <Link to='/' {...props} />
const styles = theme => ({
'@global': {
body: {
backgroundColor: theme.palette.common.white
}
},
root: {
flexGrow: 1
},
colorDefault: {
color: '#000'
},
flex: {
flexGrow: 1
},
toolbarTitle: {
flex: 1
},
menuButton: {
marginLeft: -12,
marginRight: 20
},
appBar: {
position: 'relative'
},
img: {
margin: 20,
display: 'block',
maxWidth: 240,
maxHeight: 48
}
})
class NavBar extends Component {
constructor (props) {
super(props)
this.state = {
user: null,
open: false
}
}
async componentDidMount () {
const user = await getItem('user')
console.log('NavBar CDM: ', user, this.state)
this.setState({ user })
}
render () {
let { classes, auth } = this.props
let user = JSON.parse(this.state.user)
return (
<div className={classes.root}>
<AppBar
position='static'
classes={{ root: classes.appBar, colorDefault: classes.colorDefault }}
>
<Toolbar>
<img className={classes.img} src={AALogo} alt='Advanced Algos' />
<Typography
variant='title'
color='inherit'
className={classes.toolbarTitle}
>
Teams
</Typography>
<IconButton
className={classes.menuButton}
color='inherit'
title='Home'
component={HomeLink}
>
<HomeIcon />
</IconButton>
<Button component={TeamsLink} color='inherit'>
Teams
</Button>
<Button component={AboutLink} color='inherit'>
About
</Button>
{this.state.user !== undefined && this.state.user !== null ? (
<React.Fragment>
<IconButton
className={classes.menuButton}
color='inherit'
title='Dashboard'
component={DashboardLink}
>
<DashboardIcon />
</IconButton>
<LoggedIn user={user} auth={auth} styles={styles} />
</React.Fragment>
) : (
<LoggedOut auth={auth} styles={styles} />
)}
</Toolbar>
</AppBar>
</div>
)
}
}
NavBar.propTypes = {
classes: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired
}
export default withStyles(styles)(NavBar)
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

+20
View File
@@ -0,0 +1,20 @@
NODE_ENV=development
VIRTUAL_HOST=users-api.advancedalgos.net
VIRTUAL_PORT=4000
PORT=4000
DB_USERNAME=
DB_PASSWORD=
DB_DOMAIN=
GATEWAY_ENDPOINT=http://localhost:4100/graphql
USERS_API_PRESHARED=
AUTH0_DOMAIN=
AUTH0_AUDIENCE=
AUTH0_ISSUER=
AUTH0_CLIENTID=
AUTH0_CALLBACK_URL=
AUTH0_LOGOUT_URL=
+46
View File
@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at feedback at advancedalgos dot org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
+45
View File
@@ -0,0 +1,45 @@
# Contributing
We are thrilled you are interested in contributing to this repository. Your help may be essential to the project's success and we want you in!
Advanced Algos LTD is a startup, currently at a very early stage. Although this repository is not open source software yet, we do welcome contributions from the community.
Contributions are deemed _voluntary work_. There might be incentives in place for certain kinds of contributions. Contact us for more information in this regards.
In any case, contributors agree to provide an express grant of patent rights for their contributions. Submitting Pull Requests to this repository represents an express agreement with the terms of our Balanced Contributor Intellectual Property Agreement. This agreement is a direct implementation of GitHub's [Balanced Employee Intellectual Property Agreement 1.0.1](https://github.com/github/balanced-employee-ip-agreement/blob/master/Balanced_Employee_IP_Agreement.md).
# Balanced Contributor Intellectual Property Agreement 1.0.1
This BALANCED CONTRIBUTOR INTELLECTUAL PROPERTY AGREEMENT is between person or team submitting Pull Requests to this repository and Advanced Algos LTD ("Company").
**What is this?** This is the Company's Intellectual Property Agreement ("Agreement"). If you've worked in the technology space before, there's a good chance that you've run across one or more of these in the past. This document is the official, entire and exclusive agreement on what intellectual property ("IP") is yours, and what belongs to the Company.
**Why is this?** The Company needs to be clear on what IP it owns and has rights to. Its customers, contributors, and investors depend on the Company having the legal rights to the products and services it is providing so that the Company can continue operating and doing business.
The Company also believes that it's important to be clear on what it doesn't own. The Company doesn't want you looking over your shoulder every time you work on something personal or worrying that the Company will someday seize your open source non-lethal mousetrap simulation software. In other words, the Company isn't interested in appropriating your personal projects.
**Read this.** Please read this document and be sure you understand it before you submit any Pull Requests. Due to legal risk and corporate obligations, the Company cannot, by and large, negotiate its terms. If you feel you have a particular circumstance that keeps you from signing, please let the Company's legal department ("Legal") know. And, of course, you're always free and encouraged to get your own legal counsel to explain anything you're not clear on.
Cool? Then, by submitting your first Pull Request, and as a condition of your contribution, you agree to the following:
1. **What the Company owns.** The Company owns any IP ("Company IP") that you create, or help create _as its contributor_, but only if it meets one or more of these additional conditions: The IP was (i) related to an existing or prospective Company product or service at the time you developed, invented, or created it, (ii) developed for use by the Company, or (iii) developed or promoted with existing Company IP or with the Company's endorsement. You hereby grant and assign, and will grant and assign, to the Company all rights and interests in all Company IP.
"Company IP" includes concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, and works of authorship.
2. **What the Company doesn't own.** If you create IP that doesn't fit into one of the categories listed above, the Company doesn't own it. In other words, the Company doesn't own concepts, designs, developments, discoveries, ideas, improvements, inventions, trade secrets, trademarks, or works of authorship that you develop, invent, or create that do not meet any of the conditions in Section 1.
3. **Contribution of your IP to Company projects.** If you include your own IP – such as IP you created prior to working for the Company – into a Company product or service, it's still yours, of course, but you grant the Company a non-exclusive, irrevocable, fully paid-up, royalty-free, perpetual, sublicensable, transferable, worldwide license to use it without restriction in any way or implementation, in modified form, or as is, by itself, or incorporated into another product or service ("License"). If you include your name in any project over which the Company would have rights under this Agreement, such as in a copyright notice or a comment in code or documentation, then the License covers the rights associated with that use of your name as well.
4. **Your contributions to non-Company projects.** The Company recognizes that you may be engaged in work that requires you to submit IP to entities other than the Company, such as open source projects used by the Company. Please make sure that Legal is aware of what you're working on so that Legal can help with any licensing issues. If any project asks you to sign a contribution agreement, you should check with Legal before doing so. These agreements may be legally binding on the Company and so should be run through Legal first.
5. **Voluntary Works** All Company IP that you are involved with or create as part of your work for the Company is voluntary work which does not require compensation. There might be incentives in place for certain kinds of contributions. Feel free to contact the Company to learn more.
6. **No conflicts.** You agree that you don't have any outstanding agreements or obligations that conflict with those in this Agreement, and that you won't enter into conflicting agreements in the future.
7. **IP protection.** The Company might someday need to show the work that went into the development of IP that it uses or has used, or to make government filings to establish that it owns the IP or has rights over it. To help in those situations, you agree not to destroy any records you maintain relating to the development of any Company IP or IP under License (together, "All IP"), and, if the Company asks, to provide those records to the Company. You agree to help the Company secure and defend its rights in All IP. For your help the Company will compensate you at a reasonable rate. If the Company is unable to secure your help, you authorize the Company to act on your behalf (as your agent and attorney-in-fact) in securing all rights related to All IP.
8. **Confidentiality.** As an contributor or contractor of the Company, you will have access to sensitive confidential information that is important to the Company's business. You are responsible for keeping this information confidential, including after you end your work for the Company.
"Confidential Information" includes non-public technical details about our products or services, financial information, business strategies and forecasts, customer data, or any other information, data or know-how that is valuable to the Company because it is not publicly known.
The Company's Confidential Information is sensitive and we expect that you'll treat it as such. You agree to only use the Company's Confidential Information for the purpose of performing your contribution and for the benefit of the Company. You will do your best to keep Confidential Information secret. If you are not sure if something is Confidential Information, you should assume that it is, until you can confirm otherwise.
+42
View File
@@ -0,0 +1,42 @@
COPYRIGHT NOTICE
© Copyright 2018 Advanced Algos LTD.
LICENSE NOTICE
Advanced Algos LTD. is a startup, currently at a very early stage. Because certain aspects of
the business are still not clearly defined, we have chosen to --temporarily-- grant a
restrictive license for the use of this repository, until those business aspects are clarified
and a proper open source license can be granted.
Advanced Algos LTD. is publishing the code of this software for several reasons. However,
it shall not be considered free software yet. Advanced Algos LTD. is a for-profit company
in the crypto space and this module is still proprietary software.
The reasons for opening up the code of this module at this stage are the following:
* We believe that transparency is paramount to achieving our goals, so we want everyone
to be able to understand what this module does and how. Opening up the code of this module
allows anyone to take a close look.
* We welcome contributions from the community. Contributions are regarded as voluntary work.
There may be incentives in place for certain kinds of contributions. Contact us to learn more.
Contributors agree to provide an express grant of patent rights for their contributions.
LICENSE WORDING
Advanced Algos LTD. grants a limited license for the following uses:
1. CODE REVIEW AND AUDITS. You are granted permission to clone this repository to analyze,
review or audit the code.
2. COLLABORATING WITH ADVANCED ALGOS LTD. You are granted permission to fork this repository
with the sole purpose of correcting bugs and developing functionality in agreement with
Advanced Algos LTD. By contributing to this repository you explicitely agree to the terms
detailed in CONTRIBUTING.MD.
PLEASE SEE CONTRIBUTING.MD FOR MORE DETAILS ON THE IMPLICATIONS SURROUNDING YOUR CONTRIBUTIONS TO THIS REPOSITORY.
-47
View File
@@ -1,47 +0,0 @@
/* This module imports */
const globals = require('./globals')
const sessions = require('./sessions')
const express = require('express')
const graphqlHTTP = require('express-graphql')
const schema = require('./schema/schema')
const mongoose = require('mongoose')
const mongodbConfig = require('./models/MongoDB')
const checkJwt = require('./auth/middleware/jwt')
const cors = require('cors')
const app = express()
// Allow crosss-origin requests
app.use(cors())
// Connect to the database
mongoose.connect(mongodbConfig.connectionString, { useNewUrlParser: true })
mongoose.connection.once('open', () => {
console.log('Connected to Mongo')
})
/* Here we bind all requests to this endpoint to be procecced by the GraphQL Library. */
app.get('/graphql', graphqlHTTP({
schema,
graphiql: true
}))
app.post('/graphql', graphqlHTTP({
schema,
graphiql: false,
context: req => ({ ...req })
}))
app.post('/graphql', checkJwt, (err, req, res, next) => {
console.log(req)
if (err) return res.status(401).send(`[Authenticate Token Error] ${err.message}`)
next()
})
app.listen(4000, () => {
console.log('Now listening for requests on port 4000')
})
-91
View File
@@ -1,91 +0,0 @@
const MODULE_NAME = "token-decoder";
/*
JSON Web Token (JWT) is a compact, URL-safe means of representing
claims to be transferred between two parties. The claims in a JWT
are encoded as a JSON object that is used as the payload of a JSON
Web Signature (JWS) structure or as the plaintext of a JSON Web
Encryption (JWE) structure, enabling the claims to be digitally
signed or integrity protected with a Message Authentication Code
(MAC) and/or encrypted.
*/
const JSONWebToken = require('jsonwebtoken'); // A library to deal with JSON Web Tokens.
const webTokenLibrary = require('jwks-rsa'); // A library to retrieve RSA signing keys from a JWKS (JSON Web Key Set) endpoint.
const AUTH_CONFIG = require('./Auth0'); // Config where we have our secrets.
const decoder = webTokenLibrary({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 1,
jwksUri: `https://${AUTH_CONFIG.domain}/.well-known/jwks.json`
})
function decodeToken (token, callBackFunction) {
try{
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> decodeToken -> Entering function."); }
const decoded = JSONWebToken.decode(token, { complete: true });
const header = decoded.header;
const payload = decoded.payload;
if (
header === null ||
header.kid === null ||
payload === null
) {
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> Invalid Token. "); }
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> token = " + token); }
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
decoder.getSigningKey(header.kid, onKeyReady);
function onKeyReady(err, key) {
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> Entering function."); }
if (err) {
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> Error getting the key. "); }
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> key = " + key); }
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> err = " + err); }
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
JSONWebToken.verify(
token,
key.publicKey,
{ algorithms: ['RS256'] },
onVerified);
function onVerified(err, decoded) {
if (global.INFO_LOG === true) { console.log("[INFO] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> onVerified -> Entering function."); }
if (err) {
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> onVerified -> Error verifying. "); }
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> onVerified -> decoded = " + decoded); }
if (global.ERROR_LOG === true) { console.log ("[ERROR] " + MODULE_NAME + " -> decodeToken -> onKeyReady -> onVerified -> err = " + err); }
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
return;
}
callBackFunction(global.DEFAULT_OK_RESPONSE, decoded);
}
}
} catch(err) {
if (global.ERROR_LOG === true) { console.log("[ERROR] " + MODULE_NAME + " -> decodeToken -> err = " + err); }
callBackFunction(global.DEFAULT_FAIL_RESPONSE);
}
}
module.exports = decodeToken;
-1162
View File
File diff suppressed because it is too large. Load diff
+12 -3
View File
@@ -1,15 +1,23 @@
{
"name": "server",
"version": "1.0.0",
"description": "",
"main": "index.js",
"description": "Advanced Algos Users backend API",
"main": "src/index.js",
"scripts": {
"start": "nodemon --exec babel-node --presets env,stage-2 src/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-cli": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-stage-2": "^6.24.1",
"nodemon": "^1.18.4"
},
"dependencies": {
"cors": "^2.8.4",
"dotenv": "^6.0.0",
"express": "^4.16.3",
"express-graphql": "^0.6.12",
"express-jwt": "^5.3.1",
@@ -17,6 +25,7 @@
"jsonwebtoken": "^8.3.0",
"jwks-rsa": "^1.3.0",
"lodash": "^4.17.10",
"mongoose": "^5.2.12"
"mongoose": "^5.2.12",
"winston": "^3.1.0"
}
}
@@ -1,6 +1,7 @@
const jwt = require('express-jwt');
const jwksRsa = require('jwks-rsa');
const AUTH_CONFIG = require('../Auth0');
const jwt = require('express-jwt')
const jwksRsa = require('jwks-rsa')
// Authentication middleware. When used, the
// if the access token exists, it be verified against
// the Auth0 JSON Web Key Set
@@ -12,14 +13,14 @@ const checkJwt = jwt({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 1,
jwksUri: `https://${AUTH_CONFIG.domain}/.well-known/jwks.json`
jwksUri: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`
}),
// Validate the audience and the issuer.
credentialsRequired: false,
audience: AUTH_CONFIG.api_audience,
issuer: AUTH_CONFIG.issuer,
audience: process.env.AUTH0_AUDIENCE,
issuer: process.env.AUTH0_ISSUER,
algorithms: [`RS256`]
});
})
module.exports = checkJwt ;
module.exports = checkJwt
+81
View File
@@ -0,0 +1,81 @@
const MODULE_NAME = 'token-decoder'
/*
JSON Web Token (JWT) is a compact, URL-safe means of representing
claims to be transferred between two parties. The claims in a JWT
are encoded as a JSON object that is used as the payload of a JSON
Web Signature (JWS) structure or as the plaintext of a JSON Web
Encryption (JWE) structure, enabling the claims to be digitally
signed or integrity protected with a Message Authentication Code
(MAC) and/or encrypted.
*/
const JSONWebToken = require('jsonwebtoken') // A library to deal with JSON Web Tokens.
const webTokenLibrary = require('jwks-rsa') // A library to retrieve RSA signing keys from a JWKS (JSON Web Key Set) endpoint.
const decoder = webTokenLibrary({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 1,
jwksUri: `https://${process.env.AUTH0_DOMAIN}/.well-known/jwks.json`
})
function decodeToken (token, callBackFunction) {
try {
if (global.INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> decodeToken -> Entering function.') }
const decoded = JSONWebToken.decode(token, { complete: true })
const header = decoded.header
const payload = decoded.payload
if (
header === null ||
header.kid === null ||
payload === null
) {
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> decodeToken -> Invalid Token. ') }
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> decodeToken -> token = ' + token) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
return
}
decoder.getSigningKey(header.kid, onKeyReady)
function onKeyReady (err, key) {
if (global.INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> decodeToken -> onKeyReady -> Entering function.') }
if (err) {
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> decodeToken -> onKeyReady -> Error getting the key. ') }
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> decodeToken -> onKeyReady -> key = ' + key) }
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> decodeToken -> onKeyReady -> err = ' + err) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
return
}
JSONWebToken.verify(
token,
key.publicKey,
{ algorithms: ['RS256'] },
onVerified)
function onVerified (err, decoded) {
if (global.INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> decodeToken -> onKeyReady -> onVerified -> Entering function.') }
if (err) {
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> decodeToken -> onKeyReady -> onVerified -> Error verifying. ') }
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> decodeToken -> onKeyReady -> onVerified -> decoded = ' + decoded) }
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> decodeToken -> onKeyReady -> onVerified -> err = ' + err) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
return
}
callBackFunction(global.DEFAULT_OK_RESPONSE, decoded)
}
}
} catch (err) {
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> decodeToken -> err = ' + err) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE)
}
}
module.exports = decodeToken
+8
View File
@@ -0,0 +1,8 @@
{
"errors": [
{
"code": 401,
"message": "Wait, you're not supposed to be here, go through the gate as everyone else"
}
]
}
File renamed without changes.
+65
View File
@@ -0,0 +1,65 @@
/* This module imports */
import 'dotenv/config'
import './globals'
import logger from './logger'
import express from 'express'
import graphqlHTTP from 'express-graphql'
import schema from './schema/schema'
import mongoose from 'mongoose'
import checkJwt from './auth/jwt'
import wrongPreshared from './errors/notAllowed.json'
import cors from 'cors'
require('dotenv').config()
const app = express()
// Checking preshared key
app.post('/graphql', (req, res, next) => {
if (req.headers.preshared === process.env.USERS_API_PRESHARED) {
next()
} else {
logger.error('Wrong Pre-Shared Received', req.headers.preshared)
res.send(wrongPreshared)
}
})
// Allow crosss-origin requests
app.use(cors())
// Database Connection
mongoose.connect(`mongodb://${process.env.DB_USERNAME}:${process.env.DB_PASSWORD}@${process.env.DB_DOMAIN}`, { useNewUrlParser: true })
mongoose.connection.once('open', () => {
logger.info('Connected to the DB.')
})
/* Here we bind all requests to this endpoint to be procecced by the GraphQL Library. */
app.get('/graphql', graphqlHTTP({
schema,
graphiql: true
}))
app.post('/graphql', graphqlHTTP(req => {
return {
schema,
graphiql: false,
context: {
user: req.user,
userId: req.headers.userid
}
}
}))
app.post('/graphql', checkJwt, (err, req, res, next) => {
if (err) return res.status(401).send(`[Authenticate Token Error] ${err.message}`)
next()
})
app.listen(4000, () => {
logger.info('Now listening for requests on port 4000')
})
+41
View File
@@ -0,0 +1,41 @@
import { createLogger, format, transports } from 'winston'
const { combine, timestamp, simple } = format
import { inspect } from 'util'
const options = {
file: {
level: 'info',
filename: '../logs/app.log',
handleExceptions: true,
json: true,
maxsize: 5242880, // 5MB
maxFiles: 5,
colorize: false,
timestamp: true
},
console: {
level: 'debug',
handleExceptions: true,
json: false,
colorize: true,
timestamp: true
}
}
const logger = createLogger({
level: 'info',
format: format.combine(
format.colorize(),
format.timestamp({ format: 'YY/MM/DD HH:mm' }),
format.printf(
info => `${info.timestamp} - ${info.level}: ${JSON.parse(JSON.stringify(inspect(info.message)))}`
)
),
transports: [
new transports.File(options.file),
new transports.Console(options.console)
],
exitOnError: false // do not exit on handled exceptions
})
export default logger
@@ -7,7 +7,7 @@ const Schema = mongoose.Schema
const userSchema = new Schema({
authId: String,
referrerId: String,
creationDate: String,
creationDate: Number,
alias: String,
firstName: String,
middleName: String,
@@ -1,10 +1,11 @@
const MODULE_NAME = 'schema'
const graphql = require('graphql')
const _ = require('lodash')
const User = require('../models/user')
import logger from '../logger'
import _ from 'lodash'
import User from '../models/user'
import tokenDecoder from '../auth/token-decoder'
const tokenDecoder = require('../auth/token-decoder')
const graphql = require('graphql')
const {
GraphQLObjectType,
@@ -104,22 +105,22 @@ const RootQuery = new GraphQLObjectType({
resolve (parent, args) {
// Code to get data from data source.
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> RootQuery -> userByAuthId -> resolve -> Entering function.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> RootQuery -> userByAuthId -> resolve -> Entering function.') }
/* In order to be able to wait for asyc calls to the database, we need to return a promise to GraphQL. */
const promiseToGraphQL = new Promise((resolve, reject) => {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> RootQuery -> userByAuthId -> resolve -> Promise -> Entering function.') }
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> RootQuery -> userByAuthId -> resolve -> Promise -> args.authId = ' + args.authId) }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> RootQuery -> userByAuthId -> resolve -> Promise -> Entering function.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> RootQuery -> userByAuthId -> resolve -> Promise -> args.authId = ' + args.authId) }
findUserByAuthId(args.authId, onUserFound)
function onUserFound (err, responseToGraphQL) {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> RootQuery -> userByAuthId -> resolve -> Promise -> onUserFound -> Entering function.') }
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> RootQuery -> userByAuthId -> resolve -> Promise -> onUserFound -> responseToGraphQL = ' + JSON.stringify(responseToGraphQL)) }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> RootQuery -> userByAuthId -> resolve -> Promise -> onUserFound -> Entering function.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> RootQuery -> userByAuthId -> resolve -> Promise -> onUserFound -> responseToGraphQL = ' + JSON.stringify(responseToGraphQL)) }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> RootQuery -> userByAuthId -> resolve -> Promise -> onUserFound -> err.message = ' + err.message) }
if (global.ERROR_LOG === true) { logger.error('[ERROR] ' + MODULE_NAME + ' -> RootQuery -> userByAuthId -> resolve -> Promise -> onUserFound -> err.message = ' + err.message) }
reject(responseToGraphQL)
} else {
resolve(responseToGraphQL)
@@ -154,7 +155,7 @@ const RootQuery = new GraphQLObjectType({
type: new GraphQLList(UserType),
args: {alias: {type: GraphQLString}, firstName: {type: GraphQLString}, middleName: {type: GraphQLString}, lastName: {type: GraphQLString}},
resolve (parent, args) {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> RootQuery -> usersSearch -> resolve -> Entering function.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> RootQuery -> usersSearch -> resolve -> Entering function.') }
let mongoQuery = { $or: [] }
@@ -172,7 +173,7 @@ const RootQuery = new GraphQLObjectType({
type: new GraphQLList(DescendentType),
args: {id: {type: GraphQLString}},
resolve (parent, args) {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> RootQuery -> descendents -> resolve -> Entering function.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> RootQuery -> descendents -> resolve -> Entering function.') }
return User.find({referrerId: args.id})
}
@@ -191,20 +192,20 @@ const Mutation = new GraphQLObjectType({
idToken: {type: new GraphQLNonNull(GraphQLString)}
},
resolve (parent, args) {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> Mutation -> authenticate -> resolve -> Entering function.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> Mutation -> authenticate -> resolve -> Entering function.') }
/* In order to be able to wait for asyc calls to the database, and authorization authority, we need to return a promise to GraphQL. */
const promiseToGraphQL = new Promise((resolve, reject) => {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> Mutation -> authenticate -> resolve -> Promise -> Entering function.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> Mutation -> authenticate -> resolve -> Promise -> Entering function.') }
authenticate(args.idToken, onAuthenticated)
function onAuthenticated (err, responseToGraphQL) {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> Mutation -> authenticate -> resolve -> Promise -> onAuthenticated -> Entering function.') }
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> Mutation -> authenticate -> resolve -> Promise -> onAuthenticated -> responseToGraphQL = ' + JSON.stringify(responseToGraphQL)) }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> Mutation -> authenticate -> resolve -> Promise -> onAuthenticated -> Entering function.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> Mutation -> authenticate -> resolve -> Promise -> onAuthenticated -> responseToGraphQL = ' + JSON.stringify(responseToGraphQL)) }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> Mutation -> authenticate -> resolve -> Promise -> onAuthenticated -> err.message = ' + err.message) }
if (global.ERROR_LOG === true) { logger.error('[ERROR] ' + MODULE_NAME + ' -> Mutation -> authenticate -> resolve -> Promise -> onAuthenticated -> err.message = ' + err.message) }
reject(responseToGraphQL)
} else {
resolve(responseToGraphQL)
@@ -218,7 +219,6 @@ const Mutation = new GraphQLObjectType({
updateUser: {
type: UserType,
args: {
id: {type: new GraphQLNonNull(GraphQLID)},
firstName: {type: GraphQLString},
middleName: {type: GraphQLString},
lastName: {type: GraphQLString},
@@ -228,9 +228,9 @@ const Mutation = new GraphQLObjectType({
isDataAnalyst: {type: GraphQLInt},
roleId: {type: new GraphQLNonNull(GraphQLString)}
},
resolve (parent, args) {
resolve (parent, args, context) {
let key = {
_id: args.id
_id: context.userId
}
let updatedUser = {
@@ -247,35 +247,14 @@ const Mutation = new GraphQLObjectType({
return User.update(key, updatedUser)
}
},
updateUserImages: {
type: UserType,
args: {
id: {type: new GraphQLNonNull(GraphQLID)},
avatarHandle: {type: GraphQLString},
avatarChangeDate: {type: GraphQLString}
},
resolve (parent, args) {
let key = {
_id: args.id
}
let updatedUser = {
avatarHandle: args.avatarHandle,
avatarChangeDate: args.avatarChangeDate
}
return User.update(key, updatedUser)
}
},
updateUserReferrer: {
type: UserType,
args: {
id: {type: new GraphQLNonNull(GraphQLID)},
referrerId: {type: GraphQLString}
},
resolve (parent, args) {
resolve (parent, args, context) {
let key = {
_id: args.id,
_id: context.userId,
referrerId: null
}
@@ -283,6 +262,24 @@ const Mutation = new GraphQLObjectType({
referrerId: args.referrerId
}
return User.update(key, updatedUser)
}
},
updateSessionToken: {
type: UserType,
args: {
userId: {type: GraphQLString},
sessionToken: {type: GraphQLString}
},
resolve (parent, args) {
let key = {
_id: decodeURI(args.userId)
}
let updatedUser = {
sessionToken: args.sessionToken
}
return User.update(key, updatedUser)
}
}
@@ -291,12 +288,12 @@ const Mutation = new GraphQLObjectType({
function findUserByAuthId (authId, callBackFunction) {
try {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> Entering function.') }
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> authId = ' + authId) }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> Entering function.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> authId = ' + authId) }
if (authId === null || authId === undefined) {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> User requested not specified.') }
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> args.authId = ' + authId) }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> User requested not specified.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> args.authId = ' + authId) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: 'Bad Request' })
return
@@ -306,13 +303,13 @@ function findUserByAuthId (authId, callBackFunction) {
function onUserReceived (err, user) {
if (err) {
if (ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> Database Error.') }
if (ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> err = ' + err) }
if (ERROR_LOG === true) { logger.error('[ERROR] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> Database Error.') }
if (ERROR_LOG === true) { logger.error('[ERROR] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> err = ' + err) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err })
} else {
if (user === null) {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> User not found at Database.') }
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> args.authId = ' + authId) }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> User not found at Database.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> args.authId = ' + authId) }
let customResponse = {
result: global.CUSTOM_OK_RESPONSE.result,
@@ -324,15 +321,15 @@ function findUserByAuthId (authId, callBackFunction) {
}
if (user.authId === authId && user.authId !== undefined) {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> User found at Database.') }
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> args.authId = ' + authId) }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> User found at Database.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> args.authId = ' + authId) }
callBackFunction(global.DEFAULT_OK_RESPONSE, user)
return
} else {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> User found at Database is not the user requested.') }
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> args.authId = ' + authId) }
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> user.authId = ' + user.authId) }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> User found at Database is not the user requested.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> args.authId = ' + authId) }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> findUserByAuthId -> onUserReceived -> user.authId = ' + user.authId) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err })
return
@@ -340,14 +337,14 @@ function findUserByAuthId (authId, callBackFunction) {
}
}
} catch (err) {
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> findUserByAuthId -> err.message = ' + err.message) }
if (global.ERROR_LOG === true) { logger.error('[ERROR] ' + MODULE_NAME + ' -> findUserByAuthId -> err.message = ' + err.message) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err })
}
}
function authenticate (encodedToken, callBackFunction) {
try {
if (INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> authenticate -> Entering function.') }
if (INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> authenticate -> Entering function.') }
let authId = ''
let alias = ''
@@ -357,10 +354,10 @@ function authenticate (encodedToken, callBackFunction) {
tokenDecoder(encodedToken, onValidated)
function onValidated (err, decodedToken) {
if (global.INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> Entering function.') }
if (global.INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> Entering function.') }
if (err.result !== global.DEFAULT_OK_RESPONSE.result) {
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> authenticate -> onValidated -> err.message = ' + err.message) }
if (global.ERROR_LOG === true) { logger.error('[ERROR] ' + MODULE_NAME + ' -> authenticate -> onValidated -> err.message = ' + err.message) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err })
return
}
@@ -380,18 +377,18 @@ function authenticate (encodedToken, callBackFunction) {
findUserByAuthId(authId, onUserFound)
function onUserFound (err, user) {
if (global.INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> Entering function.') }
if (global.INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> Entering function.') }
if (err.result === global.DEFAULT_FAIL_RESPONSE.result) {
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> err.message = ' + err.message) }
if (global.ERROR_LOG === true) { logger.error('[ERROR] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> err.message = ' + err.message) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err })
return
}
if (err.result === global.DEFAULT_OK_RESPONSE.result) {
if (global.INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> User already exists at database') }
if (global.INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> User already exists at database') }
if (global.INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> Existing User: ' + JSON.stringify(user)) }
if (global.INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> Existing User: ' + JSON.stringify(user)) }
/*
@@ -410,7 +407,7 @@ function authenticate (encodedToken, callBackFunction) {
err.result === global.CUSTOM_OK_RESPONSE.result &&
err.message === 'User Not Found'
) {
if (global.INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> User does not exist at database') }
if (global.INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> User does not exist at database') }
/*
@@ -429,47 +426,39 @@ function authenticate (encodedToken, callBackFunction) {
socialAccountProvider !== 'github' &&
socialAccountProvider !== 'auth0'
) {
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> Social Account Provider not Supoorted. ') }
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> socialAccountProvider = ' + socialAccountProvider) }
if (global.ERROR_LOG === true) { logger.error('[ERROR] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> Social Account Provider not Supoorted. ') }
if (global.ERROR_LOG === true) { logger.error('[ERROR] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> socialAccountProvider = ' + socialAccountProvider) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err })
return
}
let localDate = new Date()
let creationDate = new Date(Date.UTC(
localDate.getUTCFullYear(),
localDate.getUTCMonth(),
localDate.getUTCDate(),
localDate.getUTCHours(),
localDate.getUTCMinutes(),
localDate.getUTCSeconds(),
localDate.getUTCMilliseconds())
)
let creationDate = localDate.valueOf()
let newUser = new User({
alias: alias,
authId: authId,
creationDate: creationDate.toISOString(),
creationDate: creationDate,
email: email,
emailVerified: emailVerified,
roleId: '1'
})
if (global.INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> ' + alias + ' being added to the database') }
if (global.INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> ' + alias + ' being added to the database') }
newUser.save(onSaved)
function onSaved (err, savedUser) {
if (global.INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> onSaved -> Entering function.') }
if (global.INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> onSaved -> Entering function.') }
if (err) {
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> onSaved -> err = ' + err) }
if (global.ERROR_LOG === true) { logger.error('[ERROR] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> onSaved -> err = ' + err) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err })
return
}
if (global.INFO_LOG === true) { console.log('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> onSaved -> Saved User: ' + JSON.stringify(savedUser)) }
if (global.INFO_LOG === true) { logger.debug('[INFO] ' + MODULE_NAME + ' -> authenticate -> onValidated -> onUserFound -> onSaved -> Saved User: ' + JSON.stringify(savedUser)) }
/*
@@ -486,7 +475,7 @@ function authenticate (encodedToken, callBackFunction) {
}
}
} catch (err) {
if (global.ERROR_LOG === true) { console.log('[ERROR] ' + MODULE_NAME + ' -> authenticate -> err.message = ' + err.message) }
if (global.ERROR_LOG === true) { logger.error('[ERROR] ' + MODULE_NAME + ' -> authenticate -> err.message = ' + err.message) }
callBackFunction(global.DEFAULT_FAIL_RESPONSE, { error: err })
}
}
+9
View File
@@ -0,0 +1,9 @@
const getItem = async name => window.localStorage.getItem(name)
const setItem = async (name, value) => window.localStorage.setItem(name, value)
const removeItem = async name => window.localStorage.removeItem(name)
export {
getItem,
setItem,
removeItem
}