5 Commits
main ... demo

Author SHA1 Message Date
Riccardo
5368f40b04 Progress 2021-08-29 10:39:39 +02:00
Riccardo
2f119e43bd Changes 2021-08-16 11:06:02 +02:00
Riccardo
78db95aa5f Some cleaning 2021-08-16 10:08:43 +02:00
Riccardo
959c6dbc33 Fix 2021-08-16 09:06:16 +02:00
Riccardo
93169095c0 gesJav-wocxo3-vedgyg 2021-08-16 08:54:17 +02:00
21 changed files with 6469 additions and 6326 deletions

View File

@@ -5,8 +5,8 @@ import AppointmentList from './appointment/AppointmentList';
import CreateAppointment from './appointment/CreateAppointment'; import CreateAppointment from './appointment/CreateAppointment';
import UpdateAppointemnt from './appointment/UpdateAppointment'; import UpdateAppointemnt from './appointment/UpdateAppointment';
import Calendar from './Calendar'; import Calendar from './Calendar';
import Search from './Search';
import { Switch, Route } from 'react-router-dom'; import { Switch, Route } from 'react-router-dom';
// import ProductList from './ProductList';
const App = () => { const App = () => {
return ( return (
@@ -14,12 +14,12 @@ const App = () => {
<Header /> <Header />
<div className="ph3 pv1 background-gray"> <div className="ph3 pv1 background-gray">
<Switch> <Switch>
{/* <Route exact path="/" component={ProductList} /> */}
<Route exact path="/" component={AppointmentList} /> <Route exact path="/" component={AppointmentList} />
<Route exact path="/create" component={CreateAppointment} /> <Route exact path="/create" component={CreateAppointment} />
<Route exact path="/update/:_id" component={UpdateAppointemnt} /> <Route exact path="/update/:_id" component={UpdateAppointemnt} />
<Route exact path="/login" component={Login} /> <Route exact path="/login" component={Login} />
<Route exact path="/calendar" component={Calendar} /> <Route exact path="/calendar" component={Calendar} />
<Route exact path="/search" component={Search} />
</Switch> </Switch>
</div> </div>
</div> </div>

View File

@@ -1,14 +0,0 @@
import React from 'react';
const Product = (props) => {
const { product } = props;
return (
<div>
<div>
<b>{product.title}</b>: only {product.qty}!
</div>
</div>
);
};
export default Product;

View File

@@ -1,40 +0,0 @@
import React from 'react';
import Product from './Product';
import { useQuery, gql } from '@apollo/client';
const FEED_QUERY = gql`
{
allProducts{
title
qty
}
}
`;
const ProductList = () => {
const { data } = useQuery(FEED_QUERY);
console.log("Data:", data);
if (data !== undefined) {
return (
<div>
{
data.allProducts.map((product) => (
<Product key={product.id} product={product} />
))
}
</div>
);
} else {
return (
<div>
Rendering...
</div>
)
}
};
export default ProductList;

View File

@@ -1,63 +1,39 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useMutation } from '@apollo/client';
import { useLazyQuery } from '@apollo/client'; import { useLazyQuery } from '@apollo/client';
import gql from 'graphql-tag'; import gql from 'graphql-tag';
import Appointment from './Appointment'; import Appointment from './appointment/Appointment';
import { Link } from 'react-router-dom';
const FEED_SEARCH_QUERY = gql` const FEED_SEARCH_QUERY = gql`
query FeedSearchQuery($filter: String!) { query FeedSearchQuery($filter: String!) {
feed(filter: $filter) { feed(filter: $filter) {
id id
links { appointments {
id _id
title title
description description
type
createdBy {
id
username
}
# follows {
# id
# user {
# id
# }
# }
} }
} }
} }
`; `;
const Search = () => { const Search = () => {
const [searchFilter, setSearchFilter] = useState(''); const [searchFilter, setSearchFilter] = useState('');
const [executeSearch, { data }] = useLazyQuery( const [executeSearch, { data }] = useLazyQuery(
FEED_SEARCH_QUERY FEED_SEARCH_QUERY
); );
return ( return (
<> <>
<div> <div>
Search Search
<input <input type="text" onChange={(e) => setSearchFilter(e.target.value)}/>
type="text" <button onClick={() => executeSearch({ variables: { filter: searchFilter } })}>OK</button>
onChange={(e) => setSearchFilter(e.target.value)} </div>
/> {data &&
<button data.feed.appointments.map((appointment, index) => (
onClick={() => <Appointment key={appointment.id} appointment={appointment} index={index} />
executeSearch({ ))}
variables: { filter: searchFilter } </>
}) );
}
>
OK
</button>
</div>
{/* {data &&
data.feed.appointments.map((appointment, index) => (
<Link key={appointment.id} link={appointment} index={index} />
))} */}
</>
);
}; };
export default Search; export default Search;

View File

@@ -21,15 +21,16 @@ const Appointment = (props) => {
onCompleted: () => history.push('/') onCompleted: () => history.push('/')
}) })
const updateAppointment = () => { // const updateAppointment = () => {
let path = `/update/${appointment._id}`; // let path = `/update/${appointment._id}`;
history.push(path); // history.push(path);
} // }
return ( return (
<div> <div>
<div> <div>
<b>{appointment.title}</b> starts at {appointment.start}, ends at {appointment.end}. It is described as "{appointment.description}"<button onClick={deleteAppointment}>DELETE</button><button onClick={updateAppointment}>EDIT</button> <b>{appointment.title}</b> starts at {appointment.start}, ends at {appointment.end}. It is described as "{appointment.description}"<button onClick={deleteAppointment}>DELETE</button>
{/* <button onClick={updateAppointment}>EDIT</button> */}
</div> </div>
</div> </div>
); );

View File

@@ -16,7 +16,7 @@ export const APPOINTMENTS_QUERY = gql`
const AppointmentList = () => { const AppointmentList = () => {
const { data, loading } = useQuery(APPOINTMENTS_QUERY); const { data } = useQuery(APPOINTMENTS_QUERY);
if (data !== undefined) { if (data !== undefined) {
return ( return (

View File

@@ -43,34 +43,34 @@ const CreateAppointment = () => {
start: formState.start, start: formState.start,
end: formState.end end: formState.end
}, },
// update: (cache, { data: { createAppointment } }) => { update: (cache, { data: { createAppointment } }) => {
// const take = APPOINTMENTS_PER_PAGE; const take = APPOINTMENTS_PER_PAGE;
// const skip = 0; const skip = 0;
// const orderBy = { createdAt: 'desc' }; const orderBy = { createdAt: 'desc' };
// const data = cache.readQuery({ const data = cache.readQuery({
// query: APPOINTMENTS_QUERY, query: APPOINTMENTS_QUERY,
// variables: { variables: {
// take, take,
// skip, skip,
// orderBy orderBy
// } }
// }); });
// cache.writeQuery({ cache.writeQuery({
// query: APPOINTMENTS_QUERY, query: APPOINTMENTS_QUERY,
// data: { data: {
// allAppointments: { allAppointments: {
// appointments: [createAppointment, ...data.allAppointments] appointments: [createAppointment, ...data.allAppointments]
// } }
// }, },
// variables: { variables: {
// take, take,
// skip, skip,
// orderBy orderBy
// } }
// }); });
// }, },
onCompleted: () => history.push('/') onCompleted: () => history.push('/')
}); });

View File

@@ -1,8 +1,8 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import { useMutation, gql, useQuery } from '@apollo/client'; import { useMutation, gql, useQuery } from '@apollo/client';
import { APPOINTMENTS_PER_PAGE } from '../../constants'; // import { APPOINTMENTS_PER_PAGE } from '../../constants';
import { APPOINTMENTS_QUERY } from './AppointmentList'; // import { APPOINTMENTS_QUERY } from './AppointmentList';
import Datetime from 'react-datetime'; import Datetime from 'react-datetime';
import "react-datetime/css/react-datetime.css"; import "react-datetime/css/react-datetime.css";

View File

@@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { useHistory } from 'react-router'; import { useHistory } from 'react-router';
import { Link, withRouter } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { AUTH_TOKEN } from '../../constants'; import { AUTH_TOKEN } from '../../constants';
const Header = () => { const Header = () => {
@@ -17,6 +17,9 @@ const Header = () => {
<div className="flex flex-fixed"> <div className="flex flex-fixed">
<Link to="/create" className="ml1 no-underline black">New</Link> <Link to="/create" className="ml1 no-underline black">New</Link>
</div> </div>
{/* <div className="flex flex-fixed">
<Link to="/search" className="ml1 no-underline black">Search</Link>
</div> */}
<div className="flex flex-fixed"> <div className="flex flex-fixed">
{authToken ? ( {authToken ? (
<div className="ml1 pointer black" <div className="ml1 pointer black"

View File

@@ -15,7 +15,7 @@ import {
} from '@apollo/client'; } from '@apollo/client';
const httpLink = createHttpLink({ const httpLink = createHttpLink({
uri: 'http://localhost:4000/djhb58fytkh476dk45yh49' uri: 'http://localhost:4000/graphql'
}); });
const authLink = setContext((_, { headers }) => { const authLink = setContext((_, { headers }) => {

View File

@@ -23,14 +23,14 @@
"dotenv": "^8.2.0", "dotenv": "^8.2.0",
"esm": "^3.2.25", "esm": "^3.2.25",
"express": "^4.17.1", "express": "^4.17.1",
"express-graphql": "^0.12.0", "express-graphql": "*",
"graphql": "^15.4.0", "graphql": "*",
"graphql-compose": "^7.23.0", "graphql-compose": "*",
"graphql-compose-connection": "^8.0.1", "graphql-compose-connection": "*",
"graphql-compose-mongoose": "^9.0.0", "graphql-compose-mongoose": "*",
"graphql-depth-limit": "^1.1.0", "graphql-depth-limit": "*",
"graphql-middleware": "^6.0.0", "graphql-middleware": "*",
"graphql-tools": "^7.0.2", "graphql-tools": "*",
"jsonwebtoken": "8.5.1", "jsonwebtoken": "8.5.1",
"migrate": "^1.7.0", "migrate": "^1.7.0",
"mocha": "^8.2.1", "mocha": "^8.2.1",

View File

@@ -9,14 +9,17 @@ import './utils/db.js';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import cors from 'cors'; import cors from 'cors';
// import getUserId from './utils';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
const APP_SECRET = 'GraphQL-is-aw3some';
const moduleURL = new URL(import.meta.url);
const __dirname = path.dirname(moduleURL.pathname);
const app = express();
const pubsub = new PubSub();
dotenv.config();
function getTokenPayload(token) { function getTokenPayload(token) {
return jwt.verify(token, APP_SECRET); return jwt.verify(token, process.env.APP_SECRET);
} }
function getUserId(req, authToken) { function getUserId(req, authToken) {
@@ -38,19 +41,10 @@ function getUserId(req, authToken) {
throw new Error('Not authenticated'); throw new Error('Not authenticated');
} }
const moduleURL = new URL(import.meta.url);
const __dirname = path.dirname(moduleURL.pathname);
const app = express();
const pubsub = new PubSub();
dotenv.config();
app.use(cors()); app.use(cors());
app.use('/djhb58fytkh476dk45yh49', graphqlHTTP({ app.use('/graphql', graphqlHTTP({
schema: schema, schema,
validationRules: [depthLimit(3)], validationRules: [depthLimit(3)],
graphiql: true graphiql: true
})); }));
@@ -63,17 +57,7 @@ const server = new ApolloServer({
// schema, // schema,
cors: true, cors: true,
playground: process.env.NODE_ENV === 'development' ? true : false, playground: process.env.NODE_ENV === 'development' ? true : false,
context: ({ req }) => { context: ({ req }) => ({
// if (!db) {
// try {
// if (!dbClient.isConnected()) await dbClient.connect()
// mongo = dbClient.db('Calendar') // database name
// console.log(db);
// } catch (e) {
// console.log('--->error while connecting with graphql context (db)', e)
// }
return {
...req, ...req,
mongoose, mongoose,
pubsub, pubsub,
@@ -81,25 +65,24 @@ const server = new ApolloServer({
req && req.headers.authorization req && req.headers.authorization
? getUserId(req) ? getUserId(req)
: null : null
}),
subscriptions: {
onConnect: (connectionParams) => {
if (connectionParams.authToken) {
return {
mongoose,
userId: getUserId(
null,
connectionParams.authToken
)
};
} else {
return {
mongoose
};
}
} }
}, },
// subscriptions: {
// onConnect: (connectionParams) => {
// if (connectionParams.authToken) {
// return {
// mongoose,
// userId: getUserId(
// null,
// connectionParams.authToken
// )
// };
// } else {
// return {
// mongoose
// };
// }
// }
// },
introspection: true, introspection: true,
tracing: true, tracing: true,
path: '/', path: '/',
@@ -121,39 +104,5 @@ server.applyMiddleware({
}); });
app.listen({ port: process.env.PORT }, () => { app.listen({ port: process.env.PORT }, () => {
console.log(`🚀 Server listening on port ${process.env.PORT}`); console.log(`Server listening on port ${process.env.PORT}`);
console.log(`😷 Health checks available at ${process.env.HEALTH_ENDPOINT}`);
}); });
// const { graphqlHTTP } = require('express-graphql');
// const mongoose = require("mongoose");
// const graphqlSchema = require("./graphql/schema/schema")
// const appointmentResolvers = require("./graphql/resolvers/appointment")
// const userResolvers = require("./graphql/resolvers/user")
// var MongoClient = require('mongodb', { useUnifiedTopology: true }).MongoClient;
// // import { MongoClient } from 'mongodb'
// const Query = require('./resolvers/Query');
// const Mutation = require('./resolvers/Mutation');
// const Subscription = require('./resolvers/Subscription');
// const User = require('./resolvers/User');
// const Appointment = require('./resolvers/Appointment');
// const Follow = require('./resolvers/Follow');
// const fs = require('fs');
// const path = require('path');
// const { getUserId } = require('./utils');
// const graphqlResolvers = {
// appointmentResolvers,
// userResolvers
// };
// // const resolvers = {
// // Query,
// // Mutation,
// // Subscription,
// // User,
// // Appointment,
// // Follow
// // };

View File

@@ -24,6 +24,11 @@ const AppointmentSchema = new Schema({
deleted: { deleted: {
type: Boolean, type: Boolean,
required: false required: false
},
user: {
type: mongoose.Schema.Types.ObjectId,
ref: "user",
required: false
} }
}); });
export default mongoose.model('appointment', AppointmentSchema); export default mongoose.model('appointment', AppointmentSchema);

View File

@@ -1,12 +0,0 @@
import mongoose from 'mongoose';
const Schema = mongoose.Schema;
const ProductSchema = new Schema({
title: {
type: String,
required: true
},
qty: {
type: Number
}
});
export default mongoose.model('product', ProductSchema);

View File

@@ -1,33 +1,25 @@
// import Appointment from '../../client/src/components/Appointment.js';
import Product from './models/product.js';
import Appointment from './models/appointment.js'; import Appointment from './models/appointment.js';
import User from './models/user.js' import User from './models/user.js';
// import { createAppointment } from './resolvers/Mutation.js';
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import dotenv from 'dotenv'; import { createAppointment } from './resolvers/Mutation';
export const resolvers = { export const resolvers = {
Query: { Query: {
async allAppointments() { async allAppointments() {
return await Appointment.find({ deleted: false }) return await Appointment.find({ deleted: false });
// return await Appointment.find();
}, },
async oneAppointment(root, args, context, info) { async oneAppointment(root, args) {
return await Appointment.findOne({ return await Appointment.findOne({
_id: args._id _id: args._id
}); });
}, },
async allProducts() {
return await Product.find();
},
async allUsers() { async allUsers() {
return await User.find(); return await User.find();
}, },
}, },
Mutation: { Mutation: {
async signup(root, args, context, info) { async signup(root, args) {
var user = await User.create(args); const user = await User.create(args);
user.password = user.generateHash(args.password); user.password = user.generateHash(args.password);
user.save(); user.save();
@@ -39,11 +31,7 @@ export const resolvers = {
}; };
}, },
async login(parent, args, context, info) { async login(parent, args) {
console.log(context);
const { userId } = context;
console.log(userId);
const user = await User.findOne({ const user = await User.findOne({
email: args.email email: args.email
}); });
@@ -63,47 +51,15 @@ export const resolvers = {
}; };
}, },
async createAppointment(parent, args, context, info) { async createAppointment(parent, args, context) {
console.log(context); return await createAppointment(parent, args, context);
const { userId } = context;
console.log("userID", userId);
args.deleted = false;
args.createdBy = userId;
return await Appointment.create(args);
}, },
async updateAppointment(parent, args, context, info) { async updateAppointment(parent, args) {
console.log(args);
return await Appointment.findOneAndUpdate({ return await Appointment.findOneAndUpdate({
args args
}, args, { }, args, {
new: true new: true
})
},
async deleteAppointment(parent, args, context, info) {
return await Appointment.findOneAndUpdate({ _id: args._id }, { deleted: true })
// return await Appointment.deleteOne({ _id: args._id });
},
async createProduct(root, {
input
}) {
return await Product.create(input);
},
async updateProduct(root, {
_id,
input
}) {
return await Product.findOneAndUpdate({
_id
}, input, {
new: true
})
},
async deleteProduct(root, {
_id
}) {
return await Product.findOneAndRemove({
_id
}); });
}, }
} }
}; };

View File

@@ -1,28 +1,25 @@
const bcrypt = require('bcryptjs'); const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken');
const { APP_SECRET } = require('../utils'); import dotenv from 'dotenv';
import appointment from '../models/appointment';
function createAppointment(parent, args, context, info) { dotenv.config();
async function createAppointment(parent, args, context) {
const { userId } = context; const { userId } = context;
args.deleted = false;
const newAppointment = context.mongo.appointment.create({ args.createdBy = userId;
data: { console.log(parent, args, context);
title: args.title, return await appointment.create(args);
description: args.description,
createdBy: { connect: { id: userId } }
}
});
return newAppointment;
} }
async function signup(parent, args, context, info) { async function signup(parent, args, context) {
const password = await bcrypt.hash(args.password, 10); const password = await bcrypt.hash(args.password, 10);
const user = await context.mongo.user.create({ const user = await context.mongo.user.create({
data: { ...args, password } data: { ...args, password }
}); });
const token = jwt.sign({ userId: user.id }, APP_SECRET); const token = jwt.sign({ userId: user.id }, process.env.APP_SECRET);
return { return {
token, token,
@@ -30,7 +27,7 @@ async function signup(parent, args, context, info) {
}; };
} }
async function login(parent, args, context, info) { async function login(parent, args, context) {
const user = await context.mongo.user.findUnique({ const user = await context.mongo.user.findUnique({
where: { email: args.email } where: { email: args.email }
}); });
@@ -46,7 +43,7 @@ async function login(parent, args, context, info) {
throw new Error('Invalid password'); throw new Error('Invalid password');
} }
const token = jwt.sign({ userId: user.id }, APP_SECRET); const token = jwt.sign({ userId: user.id }, process.env.APP_SECRET);
return { return {
token, token,
@@ -54,18 +51,18 @@ async function login(parent, args, context, info) {
}; };
} }
async function follow(parent, args, context, info) { async function follow(parent, args, context) {
const { userId } = context; const { userId } = context;
const follow = await context.mongo.follow.findUnique({ const follow = await context.mongo.follow.findUnique({
where: { where: {
linkId_userId: { linkId_userId: {
linkId: Number(args.linkId), linkId: Number(args.linkId),
userId: userId userId
} }
} }
}); });
if (Boolean(follow)) { if (follow) {
throw new Error( throw new Error(
`Already followed the appointment: ${args.linkId}` `Already followed the appointment: ${args.linkId}`
); );

View File

@@ -1,4 +1,4 @@
async function feed(parent, args, context, info) { async function feed(parent, args, context) {
const where = args.filter const where = args.filter
? { ? {

View File

@@ -1,26 +1,22 @@
function newLinkSubscribe(parent, args, context, info) { function newAppointmentSubscribe(parent, args, context) {
return context.pubsub.asyncIterator("NEW_LINK") return context.pubsub.asyncIterator("NEW_APPOINTMENT");
} }
const newAppointment = { const newAppointment = {
subscribe: newLinkSubscribe, subscribe: newAppointmentSubscribe,
resolve: payload => { resolve: payload => payload,
return payload };
},
}
function newFollowSubscribe(parent, args, context, info) { function newFollowSubscribe(parent, args, context) {
return context.pubsub.asyncIterator("NEW_FOLLOW") return context.pubsub.asyncIterator("NEW_FOLLOW");
} }
const newFollow = { const newFollow = {
subscribe: newFollowSubscribe, subscribe: newFollowSubscribe,
resolve: payload => { resolve: payload => payload,
return payload };
},
}
module.exports = { module.exports = {
newAppointment, newAppointment,
newFollow newFollow
} };

View File

@@ -6,11 +6,8 @@ type Query {
take: Int take: Int
orderBy: AppointmentOrderByInput orderBy: AppointmentOrderByInput
): Feed! ): Feed!
allProducts: [Product]
allAppointments: [Appointment] allAppointments: [Appointment]
oneAppointment( oneAppointment(_id: ID!): Appointment
_id: ID!
): Appointment
allUsers: [User] allUsers: [User]
users: [User!]! users: [User!]!
} }
@@ -31,7 +28,7 @@ type Mutation {
deleted: Boolean deleted: Boolean
): Appointment! ): Appointment!
updateAppointment( updateAppointment(
_id: ID!, _id: ID!
title: String! title: String!
description: String description: String
type: String! type: String!
@@ -39,31 +36,10 @@ type Mutation {
end: DateTime! end: DateTime!
deleted: Boolean deleted: Boolean
): Appointment ): Appointment
deleteAppointment( deleteAppointment(_id: ID!): Appointment
_id: ID! signup(email: String!, password: String!, username: String!): AuthPayload
) : Appointment login(email: String!, password: String!): AuthPayload
createProduct( follow(appointmentId: ID!): Follow
input: ProductInput
) : Product
updateProduct(
_id: ID!,
input: ProductInput
): Product
deleteProduct(
_id: ID!
) : Product
signup(
email: String!
password: String!
username: String!
): AuthPayload
login(
email: String!,
password: String!
): AuthPayload
follow(
appointmentId: ID!
): Follow
} }
type Subscription { type Subscription {
@@ -77,13 +53,13 @@ type User {
username: String! username: String!
email: String! email: String!
password: String! password: String!
# appointments: [Appointment!]! appointments: [Appointment!]!
} }
input UserInput{ input UserInput {
username: String! username: String!
email: String! email: String!
password: String! password: String!
# appointments: [Appointment!]! appointments: [AppointmentInput!]!
} }
type AuthPayload { type AuthPayload {
token: String token: String
@@ -101,7 +77,6 @@ type Appointment {
deleted: Boolean deleted: Boolean
createdBy: User createdBy: User
# follows: [Follow!]! # follows: [Follow!]!
# createdAt: DateTime!
} }
input AppointmentInput { input AppointmentInput {
title: String! title: String!
@@ -110,24 +85,12 @@ input AppointmentInput {
start: DateTime! start: DateTime!
end: DateTime! end: DateTime!
deleted: Boolean deleted: Boolean
} }
input AppointmentOrderByInput { input AppointmentOrderByInput {
title: Sort title: Sort
desc: Sort desc: Sort
# createdAt: Sort
} }
# Product schemas
type Product {
_id: ID!
title: String!
qty: Int
}
input ProductInput {
title: String!
qty: Int
}
# Follow schemas # Follow schemas
type Follow { type Follow {
_id: ID! _id: ID!

View File

@@ -1,8 +1,10 @@
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
const APP_SECRET = 'GraphQL-is-aw3some'; import dotenv from 'dotenv';
dotenv.config();
function getTokenPayload(token) { function getTokenPayload(token) {
return jwt.verify(token, APP_SECRET); return jwt.verify(token, process.env.APP_SECRET);
} }
function getUserId(req, authToken) { function getUserId(req, authToken) {
@@ -25,6 +27,5 @@ function getUserId(req, authToken) {
} }
module.exports = { module.exports = {
APP_SECRET,
getUserId getUserId
}; };

File diff suppressed because it is too large Load Diff