merging request succes
continuous-integration/drone/push Build is passing Details

pull/9/head
David D'ALMEIDA 2 years ago
commit 7bef39baf9

@ -11,9 +11,11 @@
"author": "", "author": "",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@types/bcrypt": "^5.0.0",
"@types/cors": "^2.8.13", "@types/cors": "^2.8.13",
"@types/debug": "^4.1.7", "@types/debug": "^4.1.7",
"@types/express": "^4.17.16", "@types/express": "^4.17.16",
"@types/jsonwebtoken": "^9.0.1",
"@types/morgan": "^1.9.4", "@types/morgan": "^1.9.4",
"nodemon": "^2.0.20", "nodemon": "^2.0.20",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
@ -24,8 +26,11 @@
"@types/mongoose": "^5.11.97", "@types/mongoose": "^5.11.97",
"@types/request": "^2.48.8", "@types/request": "^2.48.8",
"axios": "^1.2.6", "axios": "^1.2.6",
"bcrypt": "^5.1.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"express-winston": "^4.2.0", "express-winston": "^4.2.0",
"joi": "^17.8.1",
"jsonwebtoken": "^9.0.0",
"mongodb": "^5.0.0", "mongodb": "^5.0.0",
"mongoose": "^6.9.0", "mongoose": "^6.9.0",
"morgan": "^1.10.0", "morgan": "^1.10.0",

@ -6,6 +6,7 @@ import cors from 'cors';
import Controller from './controller/Icontroller'; import Controller from './controller/Icontroller';
// import ErrorMiddleware from './middleware/error.middleware'; // import ErrorMiddleware from './middleware/error.middleware';
import bodyParser from 'body-parser'; import bodyParser from 'body-parser';
import mongoose from 'mongoose';
// to secure // to secure
// import helmet from 'helmet'; // import helmet from 'helmet';
@ -24,7 +25,7 @@ class App {
this.port = port; this.port = port;
this.dataBase = null; this.dataBase = null;
// this.initialiseDatabase(); this.initialiseDatabase();
this.initialiseMiddleware(); this.initialiseMiddleware();
this.initialiseControllers(controllers); this.initialiseControllers(controllers);
@ -62,6 +63,13 @@ class App {
}); });
} }
private initialiseDatabase(): void {
const { MONGO_USER, MONGO_PASSWORD, MONGO_PATH } = process.env;
const uri = "mongodb+srv://fladDevDb:ZslYlNRWIOUU7i6o@fladcluster.b29tytu.mongodb.net/?retryWrites=true&w=majority"
mongoose.connect(uri)
.then(() => console.log("Connect to MongoDB database successfully"))
.catch(err => console.log("Error connecting : "+ err ));
}
} }

@ -23,6 +23,8 @@ class SpotifyController implements Controller {
this.router.get(`${this.path}/callback`,this.getAccessToken); this.router.get(`${this.path}/callback`,this.getAccessToken);
// this.router.post(`${this.path}/refresh`,this.getRefreshToken); // this.router.post(`${this.path}/refresh`,this.getRefreshToken);
this.router.get(`${this.path}/play/:musicId`, this.getMusic); this.router.get(`${this.path}/play/:musicId`, this.getMusic);
this.router.get(`${this.path}/spot`, this.getSpot);
} }
// need to put in ENvironement file // need to put in ENvironement file
@ -134,85 +136,49 @@ class SpotifyController implements Controller {
} }
} }
// };
public getMusic(){ public getMusic(){
return null; return null;
} }
// private spotifyRequest = (params : AuthReqBody) => { public getSpot = async (
// return new Promise<any>(() => {
// console.log("============ on est laaaa sa mer");
// var code = req.query.code || null;
// var state = req.query.state || null;
// axios.post(this.API_URL, {
// form: params,
// headers: {
// "Authorization": "Basic " + new Buffer(this.CLIENT_ID + ":" + this.CLIENT_SECRET).toString('base64')
// },
// json: true
// });
// }).then(resp => {
// if (resp.statusCode != 200) {
// return Promise.reject({
// statusCode: resp.statusCode,
// body: resp.body
// });
// }
// return Promise.resolve(resp.body);
// })
// .catch(err => {
// return Promise.reject({
// statusCode: 500,
// body: err.stringify({})
// });
// });
// };
private getAccessToken = async (
req: Request, req: Request,
res: Response, res: Response,
next: NextFunction next: NextFunction
): Promise<Response | void> => { ): Promise<Response | void> => {
const spots = [
{
name: "blue",
sourceUrl: "https://cdns-images.dzcdn.net/images/artist/399e7e760d8fedf3cc2891e9c0c41658/200x200-000000-80-0-0.jpg",
index: 3
},
{
name: "strange history",
sourceUrl: "https://images.genius.com/339dfe2a7c0adf9a5d08febf29a845f4.1000x1000x1.jpg",
index: 7
},
{
name: "oboy album",
sourceUrl: "https://i.pinimg.com/originals/ad/cc/d5/adccd58a0d0ff516a6114703cd05810e.jpg",
index: 1
}
];
try {
res.send(spots);
// console.log("heheh"); } catch (error) {
// try { console.log('heuuuuuuuuuuuuuuuuuuuuubizzzaaarrreeee');
// var code = req.query.code; console.log(error);
// var state = req.query.state; next(new HttpException(400, 'On peut pas avoir darray mec'));
// console.log("================================================================================================================================"); } }
// console.log(req);
// console.log("================================================================================================================================");
// if (state === null) {
// next(new HttpException(400, 'Cannot create twerk'));
// } else {
// const resp : any = await axios.post('https://accounts.spotify.com/api/token',{
// form: {
// code: code,
// redirect_uri: this.CALLBACK_URL,
// // code_verifier : this.ENCRYPTION_SECRET.stringCrypt,
// grant_type: 'authorization_code'
// },
// headers: {
// 'Authorization': 'Basic ' + (new Buffer(this.CLIENT_ID + ':' + this.CLIENT_SECRET).toString('base64')),
// },json: true}
// );
// if (resp.statusCode != 200) {
// console.log(resp.statusCode, resp.body);
// }
// else{
// console.log("error");
// console.log(resp.statusCode, resp.body);
// }
// } private getAccessToken = async (
// // }); req: Request,
// } catch (error) { res: Response,
// console.log(error); next: NextFunction
// next(new HttpException(400, 'Cannot create spot')); ): Promise<Response | void> => {
// }
var code = req.query.code; var code = req.query.code;
var state = req.query.state || null; var state = req.query.state || null;
@ -249,39 +215,9 @@ class SpotifyController implements Controller {
} }
// axios({
// method: 'post',
// url: 'https://accounts.spotify.com/api/token',
// data: {
// firstName: 'Fred',
// lastName: 'Flintstone'
// },
// headers: {
// 'Authorization': 'Basic ' + ( Buffer.from(this.CLIENT_ID + ':' + this.CLIENT_SECRET).toString('base64')),
// 'Content-Type' : 'application/x-www-form-urlencoded'
// },
// });
// request.post(authOptions, function(error, response, body) {
// if (!error && response.statusCode === 200) {
// var access_token = body.access_token;
// console.log(access_token);
// res.redirect(200, '/')
// }
// console.log(error);
// });
}; };
private encrypt(text :any){
return CryptoJS.AES.encrypt(text, this.ENCRYPTION_SECRET.stringCrypt).toString();
};
private decrypt(text: any) {
console.log("errer");
var bytes = CryptoJS.AES.decrypt(text, this.ENCRYPTION_SECRET.stringCrypt);
return bytes.toString(CryptoJS.enc.Utf8);
};
} }
export default SpotifyController; export default SpotifyController;

@ -1,11 +1,15 @@
import { Router, Request, Response, NextFunction, RequestHandler } from 'express'; import { Router, Request, Response, NextFunction, RequestHandler } from 'express';
import Controller from '../Icontroller'; import Controller from '../Icontroller';
import HttpException from '../../middleware/exeption/httpExeption'; import HttpException from '../../middleware/exeption/httpExeption';
// import LocationService from '../../service/LocationService';
import IUser from '../../database/schema/User/UserInterface';
import UserService from '../../service/UserService';
import validator from '../../database/schema/User/UserValidation'
import validationMiddleware from '../../middleware/validation/ValidatorMiddleware';
import authenticator from '../../middleware/authMiddleware'
import LocationService from '../../service/LocationService'; import LocationService from '../../service/LocationService';
class UserController implements Controller {
public path = '/users';
class TaskController implements Controller {
public path = '/task';
public router = Router(); public router = Router();
private userService = new UserService(); private userService = new UserService();
private locationService = new LocationService(); private locationService = new LocationService();
@ -15,131 +19,193 @@ class TaskController implements Controller {
} }
private initialiseRoutes(): void { private initialiseRoutes(): void {
//create this.router.post(
this.router.post(`${this.path}`,this.createUser); `${this.path}/register`,
validationMiddleware(validator.register),
this.register
);
this.router.post(
`${this.path}/login`,
validationMiddleware(validator.login),
this.login
);
this.router.get(`${this.path}`, authenticator, this.getUser);
this.router.get(`${this.path}/nextTo`, authenticator, this.getUserNext);
// // get One
this.router.get (`${this.path}/:userId`, this.getUserById);
// // get All
this.router.get (`${this.path}`, this.getAllUsers);
//update One // //create
this.router.put (`${this.path}/:userId`, this.updateUser); // this.router.post(`${this.path}`,this.createUser);
//Delete One // // // get One
this.router.delete (`${this.path}/:userId`, this.deleteUser); // this.router.get (`${this.path}/:userId`, this.getUserById);
// // // get All
// this.router.get (`${this.path}`, this.getAllUsers);
// //update One
// this.router.put (`${this.path}/:userId`, this.updateUser);
// //Delete One
// this.router.delete (`${this.path}/:userId`, this.deleteUser);
} }
private createUser = async ( // private createUser = async (
// req: Request,
// res: Response,
// next: NextFunction
// ): Promise<Response | void> => {
// try {
// console.log(req.body);
// const reqBody:CreateTaskReqBody = Object.assign({}, req.body);
// checkIfIsValidCreateTaskReqBody(reqBody);
// await this.userService.createUserById(reqBody.fin
// );
// res.status(200).send({ status: "Success", msg: "Success add" });
// } catch (error) {
// next(new HttpException(400, 'Cannot create post'));
// }
// };
// private readonly getUserById: RequestHandler = async (
// req: Request,
// res: Response,
// next: NextFunction
// ): Promise<Response | void> => {
// try {
// const id = req.params.taskId;
// const userId = req.params.userId;
// const data = await this.userService.getUserById(id, userId);
// res.status(201).send(data);
// }
// catch(error){
// next(new HttpException(400, 'Cannot create post'));
// }
// }
// private readonly getAllUsers: RequestHandler = async (
// req: Request,
// res: Response,
// next: NextFunction
// ): Promise<Response | void> => {
// try {
// const userId = req.params.userId;
// const tasks = await this.userService.getUsers(userId);
// const responseList = tasks.map(task => new TaskResumedRes(task));
// res.status(201).send(responseList);
// }
// catch(error){
// next(new HttpException(400, 'Cannot get user task'));
// }
// }
// private deleteUser = async (
// req: Request,
// res: Response,
// next: NextFunction
// ): Promise<Response | void> => {
// try {
// const id = req.params.taskId;
// const userId = req.params.userId;
// await this.userService.DeleteUser(id, userId);
// return res.status(200).send({ status: "Success", msg: "Data Removed" });
// } catch (error) {
// next(new HttpException(400, 'Cannot create post'));
// }
// };
// private updateUser = async (
// req: Request,
// res: Response,
// next: NextFunction
// ): Promise<Response | void> => {
// try {
// const taskId = req.params.taskId;
// const userId = req.params.userId;
// const reqBody:CreateTaskReqBody = Object.assign({}, req.body);
// const updatedTask = await this.userService.UpdateTask(
// // req.auth!.uid,
// taskId,
// userId,
// // firebase.auth().currentUser.getIdToken()
// reqBody.nom,
// reqBody.description,
// reqBody.logo,
// reqBody.duration,
// reqBody.done,
// // reqBody.tags,
// reqBody.repepat,
// reqBody.deb,
// reqBody.fin
// );
// // res.send('Success add');
// // res.status(201).json({ task });
// res.status(204).send(`Update a new contact: ${updatedTask}`);
// } catch (error) {
// console.log(error);
// next(new HttpException(403, 'Cannot create post'));
// }
// };
private register = async (
req: Request, req: Request,
res: Response, res: Response,
next: NextFunction next: NextFunction
): Promise<Response | void> => { ): Promise<Response | void> => {
try { try {
// the FladId should be created by the Userservice
console.log(req.body); const { name, email, password,idFlad, idSpotify } = req.body;
const reqBody:CreateTaskReqBody = Object.assign({}, req.body);
checkIfIsValidCreateTaskReqBody(reqBody); const token = await this.userService.register(
await this.userService.createUserById(reqBody.fin name,
email,
password,
idFlad,
idSpotify
); );
res.status(200).send({ status: "Success", msg: "Success add" }); res.status(201).json({ token });
} catch (error : any) {
next(new HttpException(400, error.message));
} catch (error) {
next(new HttpException(400, 'Cannot create post'));
} }
}; };
private readonly getUserById: RequestHandler = async (
req: Request,
res: Response,
next: NextFunction
): Promise<Response | void> => {
try {
const id = req.params.taskId;
const userId = req.params.userId;
const data = await this.userService.getUserById(id, userId);
res.status(201).send(data);
}
catch(error){
next(new HttpException(400, 'Cannot create post'));
}
} private login = async (
private readonly getAllUsers: RequestHandler = async (
req: Request, req: Request,
res: Response, res: Response,
next: NextFunction next: NextFunction
): Promise<Response | void> => { ): Promise<Response | void> => {
try { try {
const userId = req.params.userId; const { email, password } = req.body;
const tasks = await this.userService.getUsers(userId);
const responseList = tasks.map(task => new TaskResumedRes(task));
res.status(201).send(responseList);
} const token = await this.userService.login(email, password);
catch(error){
next(new HttpException(400, 'Cannot get user task'));
}
} res.status(200).json({ token });
} catch (error : any) {
private deleteUser = async ( next(new HttpException(400, error.message));
req: Request,
res: Response,
next: NextFunction
): Promise<Response | void> => {
try {
const id = req.params.taskId;
const userId = req.params.userId;
await this.userService.DeleteUser(id, userId);
return res.status(200).send({ status: "Success", msg: "Data Removed" });
} catch (error) {
next(new HttpException(400, 'Cannot create post'));
} }
}; };
private updateUser = async ( private getUser = (
req: Request, req: Request,
res: Response, res: Response,
next: NextFunction next: NextFunction
): Promise<Response | void> => { ): Response | void => {
try { if (!req.user) {
return next(new HttpException(404, 'No logged in user'));
const taskId = req.params.taskId;
const userId = req.params.userId;
const reqBody:CreateTaskReqBody = Object.assign({}, req.body);
const updatedTask = await this.userService.UpdateTask(
// req.auth!.uid,
taskId,
userId,
// firebase.auth().currentUser.getIdToken()
reqBody.nom,
reqBody.description,
reqBody.logo,
reqBody.duration,
reqBody.done,
// reqBody.tags,
reqBody.repepat,
reqBody.deb,
reqBody.fin
);
// res.send('Success add');
// res.status(201).json({ task });
res.status(204).send(`Update a new contact: ${updatedTask}`);
} catch (error) {
console.log(error);
next(new HttpException(403, 'Cannot create post'));
} }
};
res.status(200).send({ data: req.user });
};
private getUserNext: RequestHandler = async ( private getUserNext = async (
req: Request, req: Request,
res: Response, res: Response,
next: NextFunction next: NextFunction
@ -152,18 +218,29 @@ class TaskController implements Controller {
console.log('Impossible de convertir la chaîne en nombre'); console.log('Impossible de convertir la chaîne en nombre');
} }
//} //}
const userId = req.body.userId; const userId = req.user.idFlad;
const data = await this.locationService.getNearUser(userId,latitude,longitude); const data = await this.locationService.getNearUser(userId,latitude,longitude);
console.log(data); console.log(data);
res.status(201).send(data); res.status(201).send(data);
} }
catch(error){ catch(error : any){
next(new HttpException(400, 'Cannot create post')); next(new HttpException(400, 'Cannot create get netUser'));
} }
} }
} }
export default TaskController; export default UserController;
declare global {
namespace Express {
export interface Request {
user: IUser;
}
}
}

@ -1,3 +1,4 @@
const uri = "mongodb+srv://fladDevDb:ZslYlNRWIOUU7i6o@fladcluster.b29tytu.mongodb.net/?retryWrites=true&w=majority"
export default db = new MongoClient(uri); // export default db = new MongoClient(uri);

@ -0,0 +1,36 @@
import { Schema, model } from 'mongoose';
const locationSchema = new Schema(
{
idFlad: {
type: String,
required: true,
unique: true,
},
latitude: {
type: Number,
required: true,
},
longitude: {
type: Number,
required: true,
},
},
{ timestamps: true }
);
// fladDevDb
// ZslYlNRWIOUU7i6o
export default model<ILocation>('Location', locationSchema);
export interface ILocation extends Document {
idFlad: string;
latitude : number;
longitude: number;
}

@ -1,6 +1,8 @@
const notificationSchema = new mongoose.Schema({ import { Schema, model } from 'mongoose';
const notificationSchema = new Schema({
type: {type: String, required: true}, type: {type: String, required: true},
content: {type: String, required: true} content: {type: String, required: true}
}); });
export default {Annonce: mongoose.model("nofitication", notificationSchema)} export default {Notification: model("nofitication", notificationSchema)}

@ -0,0 +1,8 @@
import { Schema } from 'mongoose';
interface IToken extends Object {
id: Schema.Types.ObjectId;
expiresIn: number;
}
export default IToken;

@ -0,0 +1,11 @@
import { Document } from 'mongoose';
export default interface IUser extends Document {
email: string;
name: string;
password: string;
idFlad : string;
idSpotify : string;
isValidPassword(password: string): Promise<Error | boolean>;
}

@ -0,0 +1,79 @@
// maye this file should me the UserModel like we had in php cause it's here we verrify the password
import IUser from "./UserInterface";
import { Schema, model } from 'mongoose';
import bcrypt from 'bcrypt';
// const userSchema: Schema = new Schema<IUser>({
// pseudo: {type: String, index: { unique: true }},
// email: {type: String},
// idDafl: {type: String, index: { unique: true }},
// idSpotify: {type: String},
// password: {type: String},
// prenom: {type: String, default: ""},
// description: {type: String, default: ""},
// nom: {type: String, default: ""},
// ville: {type: String, default: ""},
// profilPic: {type: String},
// noteList: [],
// notifications: [],
// friends: {type: [String] },
// favoris: [],
// conversations: {type: [String] }
// });
const userSchema = new Schema(
{
idFlad: {
type: String,
required: true,
unique: true,
},
idSpotify: {
type: String,
required: true,
unique: true,
},
name: {
type: String,
required: true,
},
email: {
type: String,
required: true,
// this mean that we identify user by email
unique: true,
// delete the whitespace
trim: true,
},
password: {
type: String,
},
},
{ timestamps: true }
);
// this means that we hash the user password before saving it to the database
userSchema.pre<IUser>('save', async function (next) {
if (!this.isModified('password')) {
//just had that to be sure that the api still going
return next();
}
const hash = await bcrypt.hash(this.password, 8);
this.password = hash;
next();
});
userSchema.methods.isValidPassword = async function (
password: string
): Promise< boolean | Error> {
return await bcrypt.compare(password, this.password);
};
// fladDevDb
// ZslYlNRWIOUU7i6o
export default model<IUser>('User', userSchema);
// export const User: Model<IUser> = model('User', userSchema);

@ -0,0 +1,18 @@
import Joi from 'joi';
const register = Joi.object({
name: Joi.string().max(30).required(),
email: Joi.string().email().required(),
password: Joi.string().min(6).required(),
// can add an field like confimPassword and cheked that the password is equal to the confirmPassword
});
const login = Joi.object({
email: Joi.string().email().required(),
password: Joi.string().required(),
});
export default { register, login };

@ -1,21 +0,0 @@
const userSchema: Schema = new mongoose.Schema<IUser>({
pseudo: {type: String, index: { unique: true }},
email: {type: String},
idDafl: {type: String, index: { unique: true }},
idSpotify: {type: String},
password: {type: String},
prenom: {type: String, default: ""},
description: {type: String, default: ""},
nom: {type: String, default: ""},
ville: {type: String, default: ""},
profilPic: {type: String},
noteList: [],
notifications: [],
friends: {type: [String] },
favoris: [],
conversations: {type: [String] }
});
// fladDevDb
// ZslYlNRWIOUU7i6o
export const User: Model<IUser> = model('User', userSchema);

@ -0,0 +1,45 @@
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';
import IToken from '../database/schema/Token/IToken';
import UserSchema from '../database/schema/User/UserSchema';
import token from '../model/token';
import HttpException from './exeption/httpExeption';
async function authenticatedMiddleware(
req: Request,
res: Response,
next: NextFunction
): Promise<Response | void> {
const bearer = req.headers.authorization;
if (!bearer || !bearer.startsWith('Bearer ')) {
return next(new HttpException(401, 'Unauthorised'));
}
const accessToken = bearer.split('Bearer ')[1].trim();
try {
const payload: IToken | jwt.JsonWebTokenError = await token.verifyToken(
accessToken
);
if (payload instanceof jwt.JsonWebTokenError) {
return next(new HttpException(401, 'Unauthorised'));
}
const user = await UserSchema.findById(payload.id)
.select('-password')
.exec();
if (!user) {
return next(new HttpException(401, 'Unauthorised'));
}
req.user = user;
return next();
} catch (error) {
return next(new HttpException(401, 'Unauthorised'));
}
}
export default authenticatedMiddleware;

@ -0,0 +1,33 @@
import { Request, Response, NextFunction, RequestHandler } from 'express';
import Joi from 'joi';
function validationMiddleware(schema: Joi.Schema): RequestHandler {
return async (
req: Request,
res: Response,
next: NextFunction
): Promise<void> => {
const validationOptions = {
abortEarly: false,
allowUnknown: true,
stripUnknown: true,
};
try {
const value = await schema.validateAsync(
req.body,
validationOptions
);
req.body = value;
next();
} catch (e: any) {
const errors: string[] = [];
e.details.forEach((error: Joi.ValidationErrorItem) => {
errors.push(error.message);
});
res.status(400).send({ errors: errors });
}
};
}
export default validationMiddleware;

@ -0,0 +1,27 @@
import jwt from 'jsonwebtoken';
import IUser from '../database/schema/User/UserInterface';
import IToken from '../database/schema/Token/IToken';
export const createToken = (user: IUser): string => {
return jwt.sign({ id: user._id }, "foo" as jwt.Secret, {
expiresIn: '100d',
});
};
export const verifyToken = async (
token: string
): Promise<jwt.VerifyErrors | IToken> => {
return new Promise((resolve, reject) => {
jwt.verify(
token,
"foo" as jwt.Secret,
(err, payload) => {
if (err) return reject(err);
resolve(payload as IToken);
}
);
});
};
export default { createToken, verifyToken };

@ -1,9 +1,10 @@
import App from "./app"; import App from "./app";
import SpotifyController from "./controller/spotify-controller/spotifyCtrl"; import SpotifyController from "./controller/spotify-controller/spotifyCtrl";
import PingController from "./controller/TestCtrl"; import PingController from "./controller/TestCtrl";
import UserController from "./controller/user-controller/userCtrl";
const app = new App( const app = new App(
[new PingController(), new SpotifyController()], [new PingController(), new SpotifyController(), new UserController()],
Number(8080) Number(8080)
// Number(process.env.PORT) // Number(process.env.PORT)

@ -1,45 +1,48 @@
// import db from '../database'; // import db from '../database';
import { Place, PlacePosition, Position, UserLocation } from '../model/locationModel'; import { Place, PlacePosition, Position, UserLocation } from '../model/locationModel';
import axios from 'axios'; import axios from 'axios';
import LocationSchema from "../database/schema/LocationSchema";
class LocationService { class LocationService {
private API_KEY : string = "AIzaSyBFCEAtmhZ8jvw84UTQvX3Aqpr66GVqB_A"; private locationCollection = LocationSchema;
public async getNearUser(uuid : string, latitude : number, longitude : number) // private API_KEY : string = "AIzaSyBFCEAtmhZ8jvw84UTQvX3Aqpr66GVqB_A";
public async getNearUser(idFlad : string, latitude : number, longitude : number)
{ {
const UserCollectionref = db.collection('UserPosition'); await this.locationCollection.findOneAndUpdate(
db.collection('UserPosition').doc(uuid).set({uuid : uuid, latitude : latitude, longitude : longitude}); { idFlad },
// const newPosition = { { idFlad, latitude, longitude },
// name: 'Los Angeles', { upsert: true }
// state: 'CA', );
// country: 'USA'
// }; const snapshot = await this.locationCollection.find({ idFlad: { $ne: idFlad } });
const snapshot = await UserCollectionref.where("uuid", "!=", uuid).get(); if (snapshot.length === 0) {
if (snapshot.empty) {
console.log('No matching documents.'); console.log('No matching documents.');
return; return;
} }
let dbUsersList:UserLocation[] = []; let dbUsersList:UserLocation[] = [];
snapshot.forEach(doc => { snapshot.forEach(doc => {
dbUsersList.push(new UserLocation(doc.data().uuid,doc.data().latitude,doc.data().longitude)); dbUsersList.push(new UserLocation(doc.idFlad,doc.latitude,doc.longitude));
console.log(doc.id, '=>', doc.data()); console.log(doc.idFlad, '=>', doc);
}); });
// missing the curent music
let listUser: string[] = []; //Set the listUser to an empty list let listUser: string[] = [];
dbUsersList.forEach(user => { dbUsersList.forEach(user => {
console.log(user); console.log(user);
const dist = this.distanceBetween(latitude , longitude , user.latitude, user.longitude); //With the function meters, determinate the distance between the current user and the user who is in the actual row const dist = this.distanceBetween(latitude , longitude , user.latitude, user.longitude);
console.log(user.uuid,dist); console.log(user.uuid,dist);
if (dist <= 5) { //If the user in the actual row is less than 100 meters away of the current user if (dist <= 100) {
listUser.push(user.uuid); //Add the username and the ID of the song that user who is in the actual row is listening listUser.push(user.uuid);
} }
}); });
return listUser; //Return an array
// $listUser[] = ['user' => $userID, 'music' => $idMusic]; //Add the username and the ID of the song that user who is in the actual row is listening
return listUser;
// $listUser[] = {userID,idMusic};
} }

@ -0,0 +1,63 @@
import UserSchema from "../database/schema/User/UserSchema";
import token from "../model/token";
class UserService {
private user = UserSchema;
/**
* Register a new user
*/
public async register(
name: string,
email: string,
password: string,
idFlad : string,
idSpotify : string
): Promise<string | Error> {
try {
const user = await this.user.create({
name,
email,
password,
idFlad,
idSpotify
});
const accessToken = token.createToken(user);
return accessToken;
} catch (error : any) {
throw new Error(error.message);
}
}
/**
* Attempt to login a user
*/
public async login(
email: string,
password: string
): Promise<string | Error> {
try {
// should maybe creat a method base on id and other information for better security
// need to view with Emre
const user = await this.user.findOne({ email });
// const user = await this.user.findById(idFlad);
if (!user) {
throw new Error('Unable to find user with that email address');
}
if (await user.isValidPassword(password)) {
return token.createToken(user);
} else {
throw new Error('Wrong credentials given');
}
} catch (error) {
throw new Error('Unable to create user');
}
}
}
export default UserService;

@ -1,4 +1,4 @@
class Music { export default class Music {
private id : string; private id : string;
private name : string; private name : string;
private artist : string; private artist : string;
@ -10,4 +10,5 @@ class Music {
this.artist = artist; this.artist = artist;
this.linkCover = linkCover; this.linkCover = linkCover;
} }
} }

@ -1,6 +1,7 @@
class Spot { class Spot {
private userId : string; private userId : string;
public music : Music;; public music : Music;
constructor(userId : string, music : Music){ constructor(userId : string, music : Music){
this.userId = userId; this.userId = userId;
this.music = music; this.music = music;

@ -1,6 +1,6 @@
class User { class User {
//attributes from DAFL //attributes from DAFL
private idDafl : any;; private idFlad : any;;
private idSpotify : any; private idSpotify : any;
//constructors //constructors
constructor(){ constructor(){

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@ -14,23 +14,17 @@ const SCREEN_WIDTH = Dimensions.get('window').width
interface CardProps { interface CardProps {
title: string; title: string;
image: any; image: any;
onSwipe: (direction: "left" | "right") => void;
} }
type ContextType = { type ContextType = {
translateX: number; translateX: number;
translateY: number; translateY: number;
}; };
const Card = ({ title, image, onSwipe} : CardProps) => { const Card : React.FC<CardProps> = ({ title, image} : CardProps) => {
const translateX = useSharedValue(0); const translateX = useSharedValue(0);
const translateY = useSharedValue(0); const translateY = useSharedValue(0);
const hapti = (() => {
// Haptics.NotificationFeedbackType.Success
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium)
});
const onGestureEvent = useAnimatedGestureHandler< const onGestureEvent = useAnimatedGestureHandler<
PanGestureHandlerGestureEvent, PanGestureHandlerGestureEvent,
ContextType ContextType
@ -47,10 +41,9 @@ const Card = ({ title, image, onSwipe} : CardProps) => {
// translateX.value = withSpring(0); // translateX.value = withSpring(0);
// translateY.value = withSpring(snapPoint(translateY.value,velocityY, snapPoints )) // translateY.value = withSpring(snapPoint(translateY.value,velocityY, snapPoints ))
if (translateX.value > 160) { if (translateX.value > 160) {
hapti() // onSwipe("right");
onSwipe("right");
} else if (translateX.value < -160) { } else if (translateX.value < -160) {
onSwipe("left"); // onSwipe("left");
} else { } else {
translateX.value = withSpring(0); translateX.value = withSpring(0);
translateY.value = withSpring(0); translateY.value = withSpring(0);
@ -75,8 +68,6 @@ const Card = ({ title, image, onSwipe} : CardProps) => {
( translateX.value, ( translateX.value,
[-SCREEN_WIDTH / 4, 0, SCREEN_WIDTH / 2], [-SCREEN_WIDTH / 4, 0, SCREEN_WIDTH / 2],
[1, 0, 0]); [1, 0, 0]);
return { return {
opacity : opacityl, opacity : opacityl,
}; };
@ -86,7 +77,7 @@ const Card = ({ title, image, onSwipe} : CardProps) => {
const opacityl = interpolate const opacityl = interpolate
( translateX.value, ( translateX.value,
[-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 4], [-SCREEN_WIDTH / 2, 0, SCREEN_WIDTH / 4],
[0.85, 1, 1]); [0.75, 1, 0.75]);
return { return {
opacity : opacityl, opacity : opacityl,
@ -95,7 +86,7 @@ const Card = ({ title, image, onSwipe} : CardProps) => {
const opacDStyle = useAnimatedStyle(() => { const opacDStyle = useAnimatedStyle(() => {
const opacityl = interpolate const opacityl = interpolate
( translateY.value, ( translateY.value,
[-SCREEN_HEIGHT / 4, 0, SCREEN_HEIGHT / 4], [-SCREEN_HEIGHT / 4, 0, SCREEN_HEIGHT / 2],
[0, 0, 1]); [0, 0, 1]);
return { return {
opacity : opacityl, opacity : opacityl,
@ -133,9 +124,7 @@ const Card = ({ title, image, onSwipe} : CardProps) => {
return ( return (
<View> <View>
<PanGestureHandler onGestureEvent={onGestureEvent}> <PanGestureHandler onGestureEvent={onGestureEvent}>
<Animated.View style={[ rStyle, styles.card,opacCStyle ]}>
<Animated.View style={[ rStyle, styles.card,opacCStyle, ]} >
<Animated.View <Animated.View
style={[{ style={[{
// transform: [{ rotate: "30deg" }], // transform: [{ rotate: "30deg" }],
@ -144,7 +133,7 @@ const Card = ({ title, image, onSwipe} : CardProps) => {
},opacRStyle]} },opacRStyle]}
> >
<Image style={[{alignSelf : "center"}]} <Image style={[{alignSelf : "center"}]}
source={require('../assets/icons/icon_dislike.png')} source={require('../assets/icons/icons/icon_dislike.png')}
/> />
</Animated.View> </Animated.View>
<Animated.View <Animated.View
@ -156,7 +145,7 @@ const Card = ({ title, image, onSwipe} : CardProps) => {
},opacLStyle]} },opacLStyle]}
> >
<Image style={[{alignSelf : "center"}]} <Image style={[{alignSelf : "center"}]}
source={require('../assets/icons/icon_like.png')} source={require('../assets/icons/icons/icon_like.png')}
/> />
</Animated.View> </Animated.View>
@ -171,7 +160,7 @@ const Card = ({ title, image, onSwipe} : CardProps) => {
> >
<Image style={[{alignSelf : "center",width: 126.27, <Image style={[{alignSelf : "center",width: 126.27,
height: 118.64, }]} height: 118.64, }]}
source={require('../assets/icons/icon_discovery.png')} source={require('../assets/icons/icons/icon_discovery.png')}
/> />
</Animated.View> </Animated.View>
@ -187,8 +176,7 @@ const styles = StyleSheet.create({
card : { card : {
justifyContent : 'center', justifyContent : 'center',
alignItems : 'center', alignItems : 'center',
borderColor : 'red',
borderWidth : 3,
}, },
image : { image : {
borderRadius : 24, borderRadius : 24,
@ -202,6 +190,3 @@ const styles = StyleSheet.create({
export default Card; export default Card;

@ -4,7 +4,7 @@ import Animated,{ Extrapolate, interpolate, useAnimatedGestureHandler, useAnimat
import { PanGestureHandler, PanGestureHandlerGestureEvent } from 'react-native-gesture-handler'; import { PanGestureHandler, PanGestureHandlerGestureEvent } from 'react-native-gesture-handler';
import * as Haptics from 'expo-haptics'; import * as Haptics from 'expo-haptics';
import Icons from '../../assets/icons/icon'; import Icons from '../../assets/icons/icons/icon';
import Rive, { Fit, RiveRef } from 'rive-react-native'; import Rive, { Fit, RiveRef } from 'rive-react-native';
const {width : wWidht} = Dimensions.get("window"); const {width : wWidht} = Dimensions.get("window");

@ -1,12 +1,12 @@
export const cards = [{ export const cards = [{
name : "blue", name : "blue",
sourceUrl : "https://cdns-images.dzcdn.net/images/artist/399e7e760d8fedf3cc2891e9c0c41658/200x200-000000-80-0-0.jpg", sourceUrl : "https://i.ebayimg.com/images/g/rY0AAOSw97djEo2C/s-l500.jpg",
index : 3 index : 3
}, },
{ {
name : "her", name : "her",
sourceUrl : "https://images.unsplash.com/photo-1484589065579-248aad0d8b13?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1359&q=80", sourceUrl : "https://i.ebayimg.com/images/g/rY0AAOSw97djEo2C/s-l500.jpg",
index : 3 index : 3
} }
] ]

@ -17,6 +17,8 @@
"expo": "~47.0.12", "expo": "~47.0.12",
"expo-auth-session": "~3.8.0", "expo-auth-session": "~3.8.0",
"expo-cli": "^6.3.0", "expo-cli": "^6.3.0",
"@reduxjs/toolkit": "^1.9.2",
"@types/react-redux": "^7.1.25",
"expo-haptics": "~12.0.1", "expo-haptics": "~12.0.1",
"expo-linear-gradient": "~12.0.1", "expo-linear-gradient": "~12.0.1",
"expo-location": "~15.0.1", "expo-location": "~15.0.1",

@ -6,7 +6,7 @@ import * as AuthSession from 'expo-auth-session';
import Card from '../components/Card'; import Card from '../components/Card';
import axios from 'axios'; import axios from 'axios';
import { cards as cardArray } from '../FakeData/data' import { cards as cardArray } from '../data/data'
import FladButton from '../components/button/button'; import FladButton from '../components/button/button';
import * as WebBrowser from 'expo-web-browser'; import * as WebBrowser from 'expo-web-browser';
import { makeRedirectUri, useAuthRequest } from 'expo-auth-session'; import { makeRedirectUri, useAuthRequest } from 'expo-auth-session';

@ -5,7 +5,7 @@ import * as Haptics from 'expo-haptics';
import Card from '../components/Card'; import Card from '../components/Card';
import { cards as cardArray } from '../FakeData/data' import { cards as cardArray } from '../data/data'
import FladButton from '../components/button/button'; import FladButton from '../components/button/button';
import axios from 'axios'; import axios from 'axios';
@ -89,69 +89,65 @@ export default function Spot() {
const onSwipe = (index: number, direction: 'left' | 'right') => { const onSwipe = (index: number, direction: 'left' | 'right') => {
if (direction === 'right') { if (direction === 'right') {
// Swiped right // Swiped right
console.log("===================")
} else if (direction === 'left') { } else if (direction === 'left') {
// Swiped left // Swiped left
} }
// update the state of the cards state when it remove thisy // update the state of the cards state when it remove thisy
setCards(cards.filter((_, i) => i !== index)); setCards(cards.filter((_, i) => i !== index));
setcurrentCard(cards[cards.length -1]);
}; };
const hapti = (() => { // const hapti = (() => {
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy) // Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Heavy)
getValueFor(MY_SECURE_AUTH_STATE_KEY) // getValueFor(MY_SECURE_AUTH_STATE_KEY)
.then(key => { (key != null) ? getUserData(key) :console.log("error key is nullll") } ) ; // .then(key => { (key != null) ? getUserData(key) :console.log("error key is nullll") } ) ;
// Haptics.NotificationFeedbackType.Success // // Haptics.NotificationFeedbackType.Success
}); // });
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
const [locationData, setLocationData] = useState<LocationData>(); // const [locationData, setLocationData] = useState<LocationData>();
const [prevLocationData, setPrevLocationData] = useState<LocationData>(); // const [prevLocationData, setPrevLocationData] = useState<LocationData>();
const [nearbyUsers, setNearbyUsers] = useState<NearbyUser[]>([]); // const [nearbyUsers, setNearbyUsers] = useState<NearbyUser[]>([]);
const [currentMusic, setCurrentMusic] = useState<string>(""); // const [currentMusic, setCurrentMusic] = useState<string>("");
async function getLocation() { // async function getLocation() {
var { status } = await Location.requestForegroundPermissionsAsync(); // var { status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') { // if (status !== 'granted') {
console.log('Permission to access location was denied'); // console.log('Permission to access location was denied');
return; // return;
} // }
let currentLocation = await Location.getCurrentPositionAsync({}); // let currentLocation = await Location.getCurrentPositionAsync({});
setLocationData({ // setLocationData({
latitude: currentLocation.coords.latitude, // latitude: currentLocation.coords.latitude,
longitude: currentLocation.coords.longitude, // longitude: currentLocation.coords.longitude,
timestamp: currentLocation.timestamp // timestamp: currentLocation.timestamp
}); // });
}; // };
async function sendLocationToServer() { // async function sendLocationToServer() {
getLocation(); // getLocation();
if (!locationData) return; // if (!locationData) return;
if (prevLocationData && locationData.latitude === prevLocationData.latitude && locationData.longitude === prevLocationData.longitude) { // if (prevLocationData && locationData.latitude === prevLocationData.latitude && locationData.longitude === prevLocationData.longitude) {
return; // return;
} // }
try { // try {
const response = await axios.post( // const response = await axios.post(
'http://localhost/api/users/david/nextToMe', // 'http://localhost/api/users/david/nextToMe',
locationData // locationData
); // );
if (response.status !== 200) { // if (response.status !== 200) {
throw new Error('Failed to send location to server'); // throw new Error('Failed to send location to server');
} // }
setPrevLocationData(locationData); // setPrevLocationData(locationData);
setNearbyUsers(response.data); // setNearbyUsers(response.data);
} catch (error) { // } catch (error) {
console.error(error); // console.error(error);
} // }
}; // };
setInterval(sendLocationToServer, 30000) // setInterval(sendLocationToServer, 30000)
return ( return (
<View style={styles.spot}> <View style={styles.spot}>
<ImageBackground blurRadius={20} <ImageBackground blurRadius={20}
style={{ style={{
@ -173,12 +169,11 @@ export default function Spot() {
<View key={card.name} style = {{ position:'absolute' <View key={card.name} style = {{ position:'absolute'
}} > }} >
<Pressable onLongPress={hapti}> <Pressable >
<Card <Card
title={card.name} title={card.name}
image={card.sourceUrl} image={card.sourceUrl}
onSwipe={(direction) => onSwipe(index, direction)}
/> />
</Pressable> </Pressable>
{/* <Button {/* <Button
@ -210,6 +205,7 @@ export default function Spot() {
flex: 1, flex: 1,
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
backgroundColor : '#000'
} }
}) })

Loading…
Cancel
Save