fix detail page navigation and music play
continuous-integration/drone/push Build is passing Details

master
David D'ALMEIDA 2 years ago
commit 2ae912d64c

@ -37,7 +37,6 @@ steps:
ADMINS: emrekartal,davidd_almeida, ADMINS: emrekartal,davidd_almeida,
depends_on: [ docker-build-and-push ] depends_on: [ docker-build-and-push ]
- name: code-analysis - name: code-analysis
image: node:latest image: node:latest
environment: environment:

@ -0,0 +1,62 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
// import compression from 'compression';
const cors_1 = __importDefault(require("cors"));
// import ErrorMiddleware from './middleware/error.middleware';
const body_parser_1 = __importDefault(require("body-parser"));
const mongoose_1 = __importDefault(require("mongoose"));
const cookie_parser_1 = __importDefault(require("cookie-parser"));
class App {
constructor(controllers, port) {
this.express = (0, express_1.default)();
this.port = port;
this.dataBase = null;
this.initialiseDatabase();
this.initialiseMiddleware();
this.initialiseControllers(controllers);
// this.initialiseErrorHandling();
}
initialiseMiddleware() {
// this.express.use(helmet());
this.express.use((0, cors_1.default)());
this.express.use((0, cookie_parser_1.default)());
// this.express.use(morgan('dev'));
this.express.use(express_1.default.json());
this.express.use(express_1.default.urlencoded({ extended: false }));
// this.express.use(compression());
// mine
this.express.use(body_parser_1.default.json());
this.express.use(body_parser_1.default.urlencoded({
extended: true
}));
}
initialiseControllers(controllers) {
controllers.forEach((controller) => {
this.express.use('/api', controller.router);
this.express.get('/toto', (req, res) => {
res.send('Hello World!');
});
});
}
// private initialiseErrorHandling(): void {
// this.express.use(ErrorMiddleware);
// }
listen() {
const server = this.express.listen(this.port, () => {
console.log(`⚡️[server] : App listening on the port ${this.port}`);
});
}
initialiseDatabase() {
const { MONGO_USER, MONGO_PASSWORD, MONGO_PATH } = process.env;
const uri = "mongodb+srv://fladDevDb:ZslYlNRWIOUU7i6o@fladcluster.b29tytu.mongodb.net/?retryWrites=true&w=majority";
mongoose_1.default.connect(uri)
.then(() => console.log("Connect to MongoDB database successfully"))
.catch(err => console.log("Error connecting : " + err));
}
}
exports.default = App;
//# sourceMappingURL=app.js.map

@ -0,0 +1 @@
{"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":";;;;;AAAA,sDAA+C;AAC/C,yCAAyC;AACzC,gDAAwB;AAIxB,+DAA+D;AAC/D,8DAAqC;AACrC,wDAAgC;AAMhC,kEAAyC;AAEzC,MAAM,GAAG;IAOL,YAAY,WAAyB,EAAE,IAAY;QAC/C,IAAI,CAAC,OAAO,GAAG,IAAA,iBAAO,GAAE,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAC1B,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC;QAExC,kCAAkC;IACtC,CAAC;IAEO,oBAAoB;QACxB,8BAA8B;QAC9B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAA,cAAI,GAAE,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAA,uBAAY,GAAE,CAAC,CAAC;QAGjC,mCAAmC;QACnC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAO,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAC1D,mCAAmC;QACnC,OAAO;QACP,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAU,CAAC,IAAI,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAU,CAAC,UAAU,CAAC;YACnC,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC,CAAC;IAEV,CAAC;IAEO,qBAAqB,CAAC,WAAyB;QACnD,WAAW,CAAC,OAAO,CAAC,CAAC,UAAsB,EAAE,EAAE;YAC3C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC;YAC5C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;gBACnC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAC3B,CAAC,CAAC,CAAA;QACR,CAAC,CAAC,CAAC;IACP,CAAC;IAED,4CAA4C;IAC5C,yCAAyC;IACzC,IAAI;IAEG,MAAM;QACT,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE;YAC/C,OAAO,CAAC,GAAG,CAAC,0CAA0C,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;IACP,CAAC;IAEO,kBAAkB;QACtB,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;QAC/D,MAAM,GAAG,GAAG,uGAAuG,CAAA;QACnH,kBAAQ,CAAC,OAAO,CAAC,GAAG,CAAC;aACpB,IAAI,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;aACnE,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,GAAE,GAAG,CAAE,CAAC,CAAC;IAC5D,CAAC;CAEJ;AAED,kBAAe,GAAG,CAAC"}

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=Icontroller.js.map

@ -0,0 +1 @@
{"version":3,"file":"Icontroller.js","sourceRoot":"","sources":["../../src/controller/Icontroller.ts"],"names":[],"mappings":""}

@ -0,0 +1,34 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
class PingController {
constructor() {
this.path = '/ping';
this.router = (0, express_1.Router)();
this.initialiseRoutes();
}
initialiseRoutes() {
this.router.get("/ping", (_req, res) => __awaiter(this, void 0, void 0, function* () {
const response = yield this.getMessage();
return res.send(response);
}));
}
getMessage() {
return __awaiter(this, void 0, void 0, function* () {
return {
message: "pong",
};
});
}
}
exports.default = PingController;
//# sourceMappingURL=TestCtrl.js.map

@ -0,0 +1 @@
{"version":3,"file":"TestCtrl.js","sourceRoot":"","sources":["../../src/controller/TestCtrl.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,qCAAiC;AAOjC,MAAqB,cAAc;IAI/B;QAHO,SAAI,GAAG,OAAO,CAAC;QACf,WAAM,GAAG,IAAA,gBAAM,GAAE,CAAC;QAGrB,IAAI,CAAC,gBAAgB,EAAE,CAAC;IAC5B,CAAC;IAEO,gBAAgB;QACpB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,CAAO,IAAI,EAAE,GAAG,EAAE,EAAE;YACzC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;YACzC,OAAO,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC,CAAA,CAAC,CAAC;IACT,CAAC;IACK,UAAU;;YACZ,OAAO;gBACP,OAAO,EAAE,MAAM;aACd,CAAC;QACN,CAAC;KAAA;CACJ;AAnBD,iCAmBC"}

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class CryptString {
constructor(length) {
this.stringCrypt = this.generateRandomString(length);
}
generateRandomString(length) {
var text = '';
var possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
}
exports.default = CryptString;
//# sourceMappingURL=crypt.js.map

@ -0,0 +1 @@
{"version":3,"file":"crypt.js","sourceRoot":"","sources":["../../../src/controller/spotify-controller/crypt.ts"],"names":[],"mappings":";;AAAA,MAAqB,WAAW;IAI5B,YAAY,MAAe;QACvB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;IACzD,CAAC;IACD,oBAAoB,CAAE,MAAe;QACjC,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,QAAQ,GAAG,gEAAgE,CAAC;QAEhF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE;YAC/B,IAAI,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;SACtE;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;CACJ;AAhBD,8BAgBC"}

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=authReqBody.js.map

@ -0,0 +1 @@
{"version":3,"file":"authReqBody.js","sourceRoot":"","sources":["../../../../src/controller/spotify-controller/request/authReqBody.ts"],"names":[],"mappings":""}

@ -0,0 +1,218 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
const httpExeption_1 = __importDefault(require("../../middleware/exeption/httpExeption"));
const axios_1 = __importDefault(require("axios"));
const crypt_1 = __importDefault(require("./crypt"));
const qs_1 = __importDefault(require("qs"));
class SpotifyController {
constructor() {
this.path = '/spotify';
this.router = (0, express_1.Router)();
// need to put in ENvironement file
// private readonly CLIENT_CALLBACK_URL = "http://localhost:8080/callback";
this.API_URL = "https://accounts.spotify.com/api/token";
this.CLIENT_ID = "1f1e34e4b6ba48b388469dba80202b10";
this.CLIENT_SECRET = "779371c6d4994a68b8dd6e84b0873c82";
// private readonly CLIENT_CALLBACK_URL = "https://auth.expo.io/@thed47/FLAD//callback";
this.CALLBACK_2 = 'https://flad-api-production.up.railway.app/api/spotify/callback';
this.SCOPES = 'user-read-private user-read-email user-read-playback-state user-read-currently-playing user-read-recently-played playlist-modify-public ugc-image-upload user-modify-playback-state';
this.ENCRYPTION_SECRET = new crypt_1.default(16);
this.clientRedirect = 'spotify_final_redirect-uri-key';
this.login = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
console.log("useeeee== login");
try {
// const params = req.body;
// if (!params.refresh_token) {
// return res.json({
// "error": "Parameter missing"
// });
// }
// this.spotifyRequest({
// grant_type: "authorization_code",
// redirect_uri: this.CLIENT_CALLBACK_2,
// // code: params.code
// })
const redirectResponse = req.query.redirectUrl ? req.query.redirectUrl : req.headers.referer;
res.cookie(this.clientRedirect, redirectResponse);
console.log("aloorrr si c'est niquuuuuuuuuuuueeee" + this.CALLBACK_2 + "gennnnnnnnnrree vraiiiiiiiment ");
res.redirect('https://accounts.spotify.com/authorize?' +
qs_1.default.stringify({
response_type: 'code',
client_id: this.CLIENT_ID,
scope: this.SCOPES,
redirect_uri: this.CALLBACK_2,
// state: this.ENCRYPTION_SECRET.stringCrypt
}));
// '?response_type=code' +
// '&client_id=' +
// "1f1e34e4b6ba48b388469dba80202b10" +
// (this.SCOPES ? '&scope=' + encodeURIComponent(this.SCOPES) : '') +
// '&redirect_uri=' +
// encodeURIComponent(this.CALLBACK_2)
// );
// .then(session => {
// let result = {
// "access_token": session.access_token,
// "expires_in": session.expires_in,
// "refresh_token": this.encrypt(session.refresh_token)
// };
// return res.send(result);
// })
// .catch(response => {
// return res.json(response);
// });
}
catch (error) {
next(new httpExeption_1.default(400, 'Cannot create spot'));
}
});
this.getRefreshToken = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
console.log('UUse2');
try {
const params = req.query.refresh_token;
if (!req.query.refresh_token) {
return res.json({
"error": "Parameter refresh_token missing"
});
}
var authOptions = {
method: 'POST',
url: 'https://accounts.spotify.com/api/token',
data: qs_1.default.stringify({
grant_type: 'refresh_token',
refresh_token: params
}),
headers: {
'Authorization': 'Basic ' + (Buffer.from(this.CLIENT_ID + ':' + this.CLIENT_SECRET).toString('base64')),
'Content-Type': 'application/x-www-form-urlencoded'
},
json: true
};
// request.post(authOptions, function(error, response, body) {
// if (!error && response.statusCode === 200) {
// var access_token = body.access_token;
// res.send({
// 'access_token': access_token
// });
// }
// });
(0, axios_1.default)(authOptions)
.then(session => {
if (session.status === 200) {
console.log('### Information : responce ###' + JSON.stringify(session.data));
console.log('### Information : refresh_token ###' + session.data.refresh_token);
res.send({
"access_token": session.data.access_token,
"refresh_token": session.data.refresh_token,
"expires_in": session.data.expires_in
});
}
});
console.log("goood");
}
catch (error) {
console.log("errur");
next(new httpExeption_1.default(400, 'Cannot create post'));
}
});
this.getSpot = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
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);
}
catch (error) {
console.log('heuuuuuuuuuuuuuuuuuuuuubizzzaaarrreeee');
console.log(error);
next(new httpExeption_1.default(400, 'On peut pas avoir darray mec'));
}
});
this.getAccessToken = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
console.log("useeeee== accesToken");
var code = req.query.code;
var state = req.query.state || null;
var storedredirectUri = req.cookies ? req.cookies[this.clientRedirect] : null;
// var storedState = req.cookies ? req.cookies[stateKey] : null;
var authOptions = {
method: 'POST',
url: 'https://accounts.spotify.com/api/token',
data: qs_1.default.stringify({
code: code,
redirect_uri: this.CALLBACK_2,
grant_type: 'authorization_code'
}),
headers: {
'Authorization': 'Basic ' + (Buffer.from(this.CLIENT_ID + ':' + this.CLIENT_SECRET).toString('base64')),
'Content-Type': 'application/x-www-form-urlencoded'
},
json: true
};
try {
var resp = yield (0, axios_1.default)(authOptions);
if (resp.status === 200) {
console.log('oon esttt laaa');
var access_token = resp.data.access_token;
var expiration = resp.data.expires_in;
var refresh = resp.data.refresh_token;
console.log(access_token);
// res.send({
// "access_token": access_token,
// "expires_in": expiration,
// "refresh" : refresh
// });
res.clearCookie(this.clientRedirect);
res.redirect(`${storedredirectUri}?` +
qs_1.default.stringify({
"access_token": access_token,
"expires_in": expiration,
"refresh_token": refresh
}));
}
}
catch (error) {
console.log('heuuuuuuuuuuuuuuuuuuuuubizzzaaarrreeee');
console.log(error);
next(new httpExeption_1.default(400, 'On peut pas te connecter mec' + error.message));
}
});
console.log("useeeee");
this.initialiseRoutes();
}
initialiseRoutes() {
// this.router.post(`${this.path}`,this.createTask);
this.router.get(`${this.path}/exchange`, this.login);
this.router.get(`${this.path}/callback`, this.getAccessToken);
this.router.get(`${this.path}/refresh`, this.getRefreshToken);
this.router.get(`${this.path}/spot`, this.getSpot);
}
}
exports.default = SpotifyController;
//# sourceMappingURL=spotifyCtrl.js.map

File diff suppressed because one or more lines are too long

@ -0,0 +1,193 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = require("express");
const httpExeption_1 = __importDefault(require("../../middleware/exeption/httpExeption"));
const UserService_1 = __importDefault(require("../../service/UserService"));
const UserValidation_1 = __importDefault(require("../../database/schema/User/UserValidation"));
const ValidatorMiddleware_1 = __importDefault(require("../../middleware/validation/ValidatorMiddleware"));
const authMiddleware_1 = __importDefault(require("../../middleware/authMiddleware"));
const LocationService_1 = __importDefault(require("../../service/LocationService"));
class UserController {
constructor() {
this.path = '/users';
this.router = (0, express_1.Router)();
this.userService = new UserService_1.default();
this.locationService = new LocationService_1.default();
// 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'));
// }
// };
this.register = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
try {
// the FladId should be created by the Userservice
const { name, email, password, idFlad, idSpotify } = req.body;
console.log(name, email, password, idFlad, idSpotify);
const token = yield this.userService.register(name, email, password, idFlad, idSpotify);
res.status(201).json({ token });
}
catch (error) {
next(new httpExeption_1.default(400, error.message));
}
});
this.login = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
try {
const { email, password } = req.body;
const token = yield this.userService.login(email, password);
res.status(200).json({ token });
}
catch (error) {
next(new httpExeption_1.default(400, error.message));
}
});
this.getUser = (req, res, next) => {
if (!req.user) {
return next(new httpExeption_1.default(404, 'No logged in user'));
}
res.status(200).send({ data: req.user });
};
this.getUserNext = (req, res, next) => __awaiter(this, void 0, void 0, function* () {
try {
const longitude = Number(req.query.longitude);
const latitude = Number(req.query.latitude);
//verify::val_int(){
console.log('woooooooooooooo' + req);
if (isNaN(longitude) || isNaN(latitude)) {
console.log('============' + longitude);
console.log('============' + latitude);
console.log('Impossible de convertir la chaîne en nombre');
}
//}
const userId = req.user.idFlad;
const musicId = String(req.query.currentMusic);
console.log('============' + longitude);
console.log('============' + latitude);
console.log('daaaaaaaaaaaaaaaaaaaaaa' + musicId);
const data = yield this.locationService.getNearUser(userId, musicId, latitude, longitude);
console.log(data);
res.status(201).send(data);
}
catch (error) {
next(new httpExeption_1.default(400, 'Cannot create get netUser'));
}
});
this.initialiseRoutes();
}
initialiseRoutes() {
this.router.post(`${this.path}/register`, (0, ValidatorMiddleware_1.default)(UserValidation_1.default.register), this.register);
this.router.post(`${this.path}/login`, (0, ValidatorMiddleware_1.default)(UserValidation_1.default.login), this.login);
this.router.get(`${this.path}`, authMiddleware_1.default, this.getUser);
this.router.get(`${this.path}/nextTo`, authMiddleware_1.default, this.getUserNext);
// //create
// this.router.post(`${this.path}`,this.createUser);
// // // get One
// 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);
}
}
exports.default = UserController;
//# sourceMappingURL=userCtrl.js.map

@ -0,0 +1 @@
{"version":3,"file":"userCtrl.js","sourceRoot":"","sources":["../../../src/controller/user-controller/userCtrl.ts"],"names":[],"mappings":"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"}

@ -0,0 +1,2 @@
// export default db = new MongoClient(uri);
//# sourceMappingURL=MongoDataBase.js.map

@ -0,0 +1 @@
{"version":3,"file":"MongoDataBase.js","sourceRoot":"","sources":["../../src/database/MongoDataBase.ts"],"names":[],"mappings":"AACA,4CAA4C"}

@ -0,0 +1 @@
//# sourceMappingURL=StrategyDatabase.js.map

@ -0,0 +1 @@
{"version":3,"file":"StrategyDatabase.js","sourceRoot":"","sources":["../../src/database/StrategyDatabase.ts"],"names":[],"mappings":""}

@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const mongoose_1 = require("mongoose");
const locationSchema = new mongoose_1.Schema({
idFlad: {
type: String,
required: true,
unique: true,
},
musicId: {
type: String,
required: true,
},
latitude: {
type: Number,
required: true,
},
longitude: {
type: Number,
required: true,
},
}, { timestamps: true });
// fladDevDb
// ZslYlNRWIOUU7i6o
exports.default = (0, mongoose_1.model)('Location', locationSchema);
//# sourceMappingURL=LocationSchema.js.map

@ -0,0 +1 @@
{"version":3,"file":"LocationSchema.js","sourceRoot":"","sources":["../../../src/database/schema/LocationSchema.ts"],"names":[],"mappings":";;AAAA,uCAAkD;AAGlD,MAAM,cAAc,GAAG,IAAI,iBAAM,CAC7B;IAEI,MAAM,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI;KACf;IACD,OAAO,EAAE;QACL,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;KACjB;IACD,QAAQ,EAAE;QACN,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;KACjB;IACD,SAAS,EAAE;QACP,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;KACjB;CAGJ,EACD,EAAE,UAAU,EAAE,IAAI,EAAE,CACvB,CAAC;AAEF,YAAY;AACZ,mBAAmB;AACnB,kBAAe,IAAA,gBAAK,EAAY,UAAU,EAAE,cAAc,CAAC,CAAC"}

@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const mongoose_1 = require("mongoose");
const notificationSchema = new mongoose_1.Schema({
type: { type: String, required: true },
content: { type: String, required: true }
});
exports.default = { Notification: (0, mongoose_1.model)("nofitication", notificationSchema) };
//# sourceMappingURL=NotificationSchema.js.map

@ -0,0 +1 @@
{"version":3,"file":"NotificationSchema.js","sourceRoot":"","sources":["../../../src/database/schema/NotificationSchema.ts"],"names":[],"mappings":";;AAAA,uCAAyC;AAEzC,MAAM,kBAAkB,GAAG,IAAI,iBAAM,CAAC;IAClC,IAAI,EAAE,EAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAC;IACpC,OAAO,EAAE,EAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAC;CAC1C,CAAC,CAAC;AAEH,kBAAe,EAAC,YAAY,EAAE,IAAA,gBAAK,EAAC,cAAc,EAAE,kBAAkB,CAAC,EAAC,CAAA"}

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=IToken.js.map

@ -0,0 +1 @@
{"version":3,"file":"IToken.js","sourceRoot":"","sources":["../../../../src/database/schema/Token/IToken.ts"],"names":[],"mappings":""}

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=UserInterface.js.map

@ -0,0 +1 @@
{"version":3,"file":"UserInterface.js","sourceRoot":"","sources":["../../../../src/database/schema/User/UserInterface.ts"],"names":[],"mappings":""}

@ -0,0 +1,82 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const mongoose_1 = require("mongoose");
const bcrypt_1 = __importDefault(require("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 mongoose_1.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('save', function (next) {
return __awaiter(this, void 0, void 0, function* () {
if (!this.isModified('password')) {
//just had that to be sure that the api still going
return next();
}
const hash = yield bcrypt_1.default.hash(this.password, 8);
this.password = hash;
next();
});
});
userSchema.methods.isValidPassword = function (password) {
return __awaiter(this, void 0, void 0, function* () {
return yield bcrypt_1.default.compare(password, this.password);
});
};
// fladDevDb
// ZslYlNRWIOUU7i6o
exports.default = (0, mongoose_1.model)('User', userSchema);
// export const User: Model<IUser> = model('User', userSchema);
//# sourceMappingURL=UserSchema.js.map

@ -0,0 +1 @@
{"version":3,"file":"UserSchema.js","sourceRoot":"","sources":["../../../../src/database/schema/User/UserSchema.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAEA,uCAAyC;AACzC,oDAA4B;AAC5B,iDAAiD;AACjD,uDAAuD;AACvD,6BAA6B;AAC7B,uDAAuD;AACvD,iCAAiC;AACjC,gCAAgC;AAChC,2CAA2C;AAC3C,gDAAgD;AAChD,wCAAwC;AACxC,0CAA0C;AAC1C,iCAAiC;AACjC,oBAAoB;AACpB,yBAAyB;AACzB,kCAAkC;AAClC,mBAAmB;AACnB,uCAAuC;AACvC,MAAM;AAEN,MAAM,UAAU,GAAG,IAAI,iBAAM,CACzB;IAEI,MAAM,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI;KACf;IACD,SAAS,EAAE;QACP,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI;KACf;IACD,IAAI,EAAE;QACF,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;KACjB;IACD,KAAK,EAAE;QACH,IAAI,EAAE,MAAM;QACZ,QAAQ,EAAE,IAAI;QACd,2CAA2C;QAC3C,MAAM,EAAE,IAAI;QACZ,wBAAwB;QACxB,IAAI,EAAE,IAAI;KACb;IACD,QAAQ,EAAE;QACN,IAAI,EAAE,MAAM;KACf;CAEJ,EACD,EAAE,UAAU,EAAE,IAAI,EAAE,CACvB,CAAC;AAEF,6EAA6E;AAC7E,UAAU,CAAC,GAAG,CAAQ,MAAM,EAAE,UAAgB,IAAI;;QAC9C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;YAC9B,mDAAmD;YACnD,OAAO,IAAI,EAAE,CAAC;SACjB;QAED,MAAM,IAAI,GAAG,MAAM,gBAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAEjD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QAErB,IAAI,EAAE,CAAC;IACX,CAAC;CAAA,CAAC,CAAC;AAEH,UAAU,CAAC,OAAO,CAAC,eAAe,GAAG,UACjC,QAAgB;;QAEhB,OAAO,MAAM,gBAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzD,CAAC;CAAA,CAAC;AAEF,YAAY;AACZ,mBAAmB;AACnB,kBAAe,IAAA,gBAAK,EAAQ,MAAM,EAAE,UAAU,CAAC,CAAC;AAChD,+DAA+D"}

@ -0,0 +1,20 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const joi_1 = __importDefault(require("joi"));
const register = joi_1.default.object({
name: joi_1.default.string().max(30).required(),
email: joi_1.default.string().email().required(),
password: joi_1.default.string().min(6).required(),
// can add an field like confimPassword and cheked that the password is equal to the confirmPassword
idSpotify: joi_1.default.string(),
idFlad: joi_1.default.string(),
});
const login = joi_1.default.object({
email: joi_1.default.string().email().required(),
password: joi_1.default.string().required(),
});
exports.default = { register, login };
//# sourceMappingURL=UserValidation.js.map

@ -0,0 +1 @@
{"version":3,"file":"UserValidation.js","sourceRoot":"","sources":["../../../../src/database/schema/User/UserValidation.ts"],"names":[],"mappings":";;;;;AAAA,8CAAsB;AAEtB,MAAM,QAAQ,GAAG,aAAG,CAAC,MAAM,CAAC;IACxB,IAAI,EAAE,aAAG,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;IAErC,KAAK,EAAE,aAAG,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IAEtC,QAAQ,EAAE,aAAG,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE;IACxC,oGAAoG;IACpG,SAAS,EAAE,aAAG,CAAC,MAAM,EAAE;IACvB,MAAM,EAAG,aAAG,CAAC,MAAM,EAAE;CACxB,CAAC,CAAC;AAEH,MAAM,KAAK,GAAG,aAAG,CAAC,MAAM,CAAC;IACrB,KAAK,EAAE,aAAG,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;IACtC,QAAQ,EAAE,aAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAEH,kBAAe,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC"}

@ -0,0 +1,14 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const app_1 = __importDefault(require("./app"));
const spotifyCtrl_1 = __importDefault(require("./controller/spotify-controller/spotifyCtrl"));
const TestCtrl_1 = __importDefault(require("./controller/TestCtrl"));
const userCtrl_1 = __importDefault(require("./controller/user-controller/userCtrl"));
const dotenv_1 = __importDefault(require("dotenv"));
dotenv_1.default.config();
const app = new app_1.default([new TestCtrl_1.default(), new spotifyCtrl_1.default(), new userCtrl_1.default()], Number(process.env.PORT));
app.listen();
//# sourceMappingURL=index.js.map

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,gDAAwB;AACxB,8FAA4E;AAC5E,qEAAmD;AACnD,qFAAmE;AACnE,oDAA2B;AAC3B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAChB,MAAM,GAAG,GAAG,IAAI,aAAG,CACf,CAAC,IAAI,kBAAc,EAAE,EAAE,IAAI,qBAAiB,EAAE,EAAE,IAAI,kBAAc,EAAE,CAAC,EACrE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAE3B,CAAC;AAEF,GAAG,CAAC,MAAM,EAAE,CAAC"}

@ -0,0 +1,46 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
const UserSchema_1 = __importDefault(require("../database/schema/User/UserSchema"));
const token_1 = __importDefault(require("../model/token"));
const httpExeption_1 = __importDefault(require("./exeption/httpExeption"));
function authenticatedMiddleware(req, res, next) {
return __awaiter(this, void 0, void 0, function* () {
const bearer = req.headers.authorization;
if (!bearer || !bearer.startsWith('Bearer ')) {
return next(new httpExeption_1.default(401, 'Unauthorised'));
}
const accessToken = bearer.split('Bearer ')[1].trim();
try {
const payload = yield token_1.default.verifyToken(accessToken);
if (payload instanceof jsonwebtoken_1.default.JsonWebTokenError) {
return next(new httpExeption_1.default(401, 'Unauthorised'));
}
const user = yield UserSchema_1.default.findById(payload.id)
.select('-password')
.exec();
if (!user) {
return next(new httpExeption_1.default(401, 'Unauthorised'));
}
req.user = user;
return next();
}
catch (error) {
return next(new httpExeption_1.default(401, 'Unauthorised'));
}
});
}
exports.default = authenticatedMiddleware;
//# sourceMappingURL=authMiddleware.js.map

@ -0,0 +1 @@
{"version":3,"file":"authMiddleware.js","sourceRoot":"","sources":["../../src/middleware/authMiddleware.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AACA,gEAA+B;AAE/B,oFAA4D;AAC5D,2DAAmC;AACnC,2EAAoD;AAEpD,SAAe,uBAAuB,CAClC,GAAY,EACZ,GAAa,EACb,IAAkB;;QAElB,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAC;QAEzC,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;YAC1C,OAAO,IAAI,CAAC,IAAI,sBAAa,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;SACvD;QAED,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACtD,IAAI;YACA,MAAM,OAAO,GAAmC,MAAM,eAAK,CAAC,WAAW,CACnE,WAAW,CACd,CAAC;YAEF,IAAI,OAAO,YAAY,sBAAG,CAAC,iBAAiB,EAAE;gBAC1C,OAAO,IAAI,CAAC,IAAI,sBAAa,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;aACvD;YAED,MAAM,IAAI,GAAG,MAAM,oBAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;iBAC7C,MAAM,CAAC,WAAW,CAAC;iBACnB,IAAI,EAAE,CAAC;YAEZ,IAAI,CAAC,IAAI,EAAE;gBACP,OAAO,IAAI,CAAC,IAAI,sBAAa,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;aACvD;YAED,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;YAEhB,OAAO,IAAI,EAAE,CAAC;SACjB;QAAC,OAAO,KAAK,EAAE;YACZ,OAAO,IAAI,CAAC,IAAI,sBAAa,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC;SACvD;IACL,CAAC;CAAA;AAED,kBAAe,uBAAuB,CAAC"}

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class HttpException extends Error {
constructor(status, message) {
super(message);
this.status = status;
this.message = message;
}
}
// en fontion de l'exeption firebas,etc une bonne exeption
exports.default = HttpException;
//# sourceMappingURL=httpExeption.js.map

@ -0,0 +1 @@
{"version":3,"file":"httpExeption.js","sourceRoot":"","sources":["../../../src/middleware/exeption/httpExeption.ts"],"names":[],"mappings":";;AAAA,MAAM,aAAc,SAAQ,KAAK;IAI7B,YAAY,MAAc,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;CACJ;AACD,0DAA0D;AAE1D,kBAAe,aAAa,CAAC"}

@ -0,0 +1,34 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
function validationMiddleware(schema) {
return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
const validationOptions = {
abortEarly: false,
allowUnknown: true,
stripUnknown: true,
};
try {
const value = yield schema.validateAsync(req.body, validationOptions);
req.body = value;
next();
}
catch (e) {
const errors = [];
e.details.forEach((error) => {
errors.push(error.message);
});
res.status(400).send({ errors: errors });
}
});
}
exports.default = validationMiddleware;
//# sourceMappingURL=ValidatorMiddleware.js.map

@ -0,0 +1 @@
{"version":3,"file":"ValidatorMiddleware.js","sourceRoot":"","sources":["../../../src/middleware/validation/ValidatorMiddleware.ts"],"names":[],"mappings":";;;;;;;;;;;AAGA,SAAS,oBAAoB,CAAC,MAAkB;IAC5C,OAAO,CACH,GAAY,EACZ,GAAa,EACb,IAAkB,EACL,EAAE;QACf,MAAM,iBAAiB,GAAG;YACtB,UAAU,EAAE,KAAK;YACjB,YAAY,EAAE,IAAI;YAClB,YAAY,EAAE,IAAI;SACrB,CAAC;QAEF,IAAI;YACA,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,aAAa,CACpC,GAAG,CAAC,IAAI,EACR,iBAAiB,CACpB,CAAC;YACF,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC;YACjB,IAAI,EAAE,CAAC;SACV;QAAC,OAAO,CAAM,EAAE;YACb,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,KAA8B,EAAE,EAAE;gBACjD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;SAC5C;IACL,CAAC,CAAA,CAAC;AACN,CAAC;AAED,kBAAe,oBAAoB,CAAC"}

@ -0,0 +1,9 @@
// export const loggerOptions: expressWinston.LoggerOptions = {
// transports: [new winston.transports.Console()],
// format: winston.format.combine(
// winston.format.json(),
// winston.format.prettyPrint(),
// winston.format.colorize({ all: true })
// ),
// };
//# sourceMappingURL=winston.js.map

@ -0,0 +1 @@
{"version":3,"file":"winston.js","sourceRoot":"","sources":["../../src/middleware/winston.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,sDAAsD;AACtD,sCAAsC;AACtC,iCAAiC;AACjC,wCAAwC;AACxC,iDAAiD;AACjD,SAAS;AACT,KAAK"}

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=IUser.js.map

@ -0,0 +1 @@
{"version":3,"file":"IUser.js","sourceRoot":"","sources":["../../src/model/IUser.ts"],"names":[],"mappings":""}

@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Place = exports.UserLocation = exports.PlacePosition = void 0;
class PlacePosition {
constructor(timestamp, latitude, longitude) {
this.timestamp = timestamp;
this.coords = { latitude, longitude };
}
}
exports.PlacePosition = PlacePosition;
class UserLocation {
constructor(uuid, musicId, latitude, longitude) {
this.uuid = uuid;
this.musicId = musicId;
this.latitude = latitude;
this.longitude = longitude;
}
}
exports.UserLocation = UserLocation;
class Place {
constructor(address, position) {
this.position = position;
this.address = address;
}
}
exports.Place = Place;
//# sourceMappingURL=locationModel.js.map

@ -0,0 +1 @@
{"version":3,"file":"locationModel.js","sourceRoot":"","sources":["../../src/model/locationModel.ts"],"names":[],"mappings":";;;AAmBA,MAAa,aAAa;IAMtB,YAAY,SAAiB,EAAC,QAAiB,EAAE,SAAiB;QAC9D,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,EAAC,QAAQ,EAAE,SAAS,EAAC,CAAC;IACxC,CAAC;CACJ;AAVD,sCAUC;AACD,MAAa,YAAY;IAKrB,YAAY,IAAY,EAAE,OAAgB,EAAC,QAAgB,EAAE,SAAiB;QAC1E,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC/B,CAAC;CACJ;AAXD,oCAWC;AAED,MAAa,KAAK;IAGlB,YAAY,OAAgB,EAAC,QAAkB;QAC3C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;CACA;AAPD,sBAOC"}

@ -0,0 +1,34 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.verifyToken = exports.createToken = void 0;
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
const createToken = (user) => {
return jsonwebtoken_1.default.sign({ id: user._id }, "foo", {
expiresIn: '100d',
});
};
exports.createToken = createToken;
const verifyToken = (token) => __awaiter(void 0, void 0, void 0, function* () {
return new Promise((resolve, reject) => {
jsonwebtoken_1.default.verify(token, "foo", (err, payload) => {
if (err)
return reject(err);
resolve(payload);
});
});
});
exports.verifyToken = verifyToken;
exports.default = { createToken: exports.createToken, verifyToken: exports.verifyToken };
//# sourceMappingURL=token.js.map

@ -0,0 +1 @@
{"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/model/token.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,gEAA+B;AAIxB,MAAM,WAAW,GAAG,CAAC,IAAW,EAAU,EAAE;IAC/C,OAAO,sBAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,KAAmB,EAAE;QACnD,SAAS,EAAE,MAAM;KACpB,CAAC,CAAC;AACP,CAAC,CAAC;AAJW,QAAA,WAAW,eAItB;AAEK,MAAM,WAAW,GAAG,CACvB,KAAa,EACqB,EAAE;IACpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACnC,sBAAG,CAAC,MAAM,CACN,KAAK,EACL,KAAmB,EACnB,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE;YACb,IAAI,GAAG;gBAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;YAE5B,OAAO,CAAC,OAAiB,CAAC,CAAC;QAC/B,CAAC,CACJ,CAAC;IACN,CAAC,CAAC,CAAC;AACP,CAAC,CAAA,CAAC;AAdW,QAAA,WAAW,eActB;AAEF,kBAAe,EAAE,WAAW,EAAX,mBAAW,EAAE,WAAW,EAAX,mBAAW,EAAE,CAAC"}

@ -0,0 +1,116 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
// import db from '../database';
const locationModel_1 = require("../model/locationModel");
const LocationSchema_1 = __importDefault(require("../database/schema/LocationSchema"));
class LocationService {
constructor() {
this.locationCollection = LocationSchema_1.default;
this.toRad = (value) => (value * Math.PI) / 180;
this.toDeg = (value) => (value * 180) / Math.PI;
// getCenter(coords)
}
// private API_KEY : string = "AIzaSyBFCEAtmhZ8jvw84UTQvX3Aqpr66GVqB_A";
getNearUser(idFlad, musicId, latitude, longitude) {
return __awaiter(this, void 0, void 0, function* () {
yield this.locationCollection.findOneAndUpdate({ idFlad }, { idFlad, musicId, latitude, longitude }, { upsert: true });
const snapshot = yield this.locationCollection.find({ idFlad: { $ne: idFlad } });
if (snapshot.length === 0) {
console.log('No matching documents.');
return;
}
let dbUsersList = [];
snapshot.forEach(doc => {
dbUsersList.push(new locationModel_1.UserLocation(doc.idFlad, doc.musicId, doc.latitude, doc.longitude));
console.log(doc.idFlad, '=>', doc);
});
// missing the curent music
let listUser = [];
const listUser2 = {};
dbUsersList.forEach(user => {
console.log(user);
const dist = this.distanceBetween(latitude, longitude, user.latitude, user.longitude);
console.log(user.uuid, dist);
if (dist <= 100) {
listUser.push(user.uuid);
listUser2[user.uuid] = user.musicId;
}
});
return { listUser, listUser2 };
// $listUser[] = {userID,idMusic};
});
}
getCenter(points) {
if (Array.isArray(points) === false || points.length === 0) {
return false;
}
const numberOfPoints = points.length;
const sum = points.reduce((acc, point) => {
const pointLat = this.toRad(point.coords.latitude);
const pointLon = this.toRad(point.coords.longitude);
return {
X: acc.X + Math.cos(pointLat) * Math.cos(pointLon),
Y: acc.Y + Math.cos(pointLat) * Math.sin(pointLon),
Z: acc.Z + Math.sin(pointLat),
};
}, { X: 0, Y: 0, Z: 0 });
const X = sum.X / numberOfPoints;
const Y = sum.Y / numberOfPoints;
const Z = sum.Z / numberOfPoints;
return {
longitude: this.toDeg(Math.atan2(Y, X)),
latitude: this.toDeg(Math.atan2(Z, Math.sqrt(X * X + Y * Y))),
};
}
;
// sa c'est un utils du coup mettre dans une calss utils
// resulta en km
distanceBetween(lat1, lon1, lat2, lon2) {
if ((lat1 == lat2) && (lon1 == lon2)) {
return 0;
}
else {
var radlat1 = Math.PI * lat1 / 180;
var radlat2 = Math.PI * lat2 / 180;
var theta = lon1 - lon2;
var radtheta = Math.PI * theta / 180;
var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
if (dist > 1) {
dist = 1;
}
dist = Math.acos(dist);
dist = dist * 180 / Math.PI;
dist = dist * 60 * 1.1515;
dist = dist * 1.609344;
return dist;
}
}
distanceBetweenPosition(first, second) {
return this.distanceBetween(first.coords.latitude, first.coords.longitude, second.coords.latitude, second.coords.longitude);
}
// give a array of position sorted by distance and return the first
findNearest(main, list) {
this.orderByDistance(main, list)[0];
}
//distanceFn: DistanceFn = getDistance est param sa serrait cool de lui passer un fonction
orderByDistance(mainPos, coords) {
return coords
.slice()
.sort((a, b) => this.distanceBetweenPosition(mainPos, a) - this.distanceBetweenPosition(mainPos, b));
}
;
}
exports.default = LocationService;
//# sourceMappingURL=LocationService.js.map

@ -0,0 +1 @@
{"version":3,"file":"LocationService.js","sourceRoot":"","sources":["../../src/service/LocationService.ts"],"names":[],"mappings":"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"}

@ -0,0 +1,69 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const UserSchema_1 = __importDefault(require("../database/schema/User/UserSchema"));
const token_1 = __importDefault(require("../model/token"));
class UserService {
constructor() {
this.user = UserSchema_1.default;
}
/**
* Register a new user
*/
register(name, email, password, idFlad, idSpotify) {
return __awaiter(this, void 0, void 0, function* () {
try {
const user = yield this.user.create({
name,
email,
password,
idFlad,
idSpotify
});
const accessToken = token_1.default.createToken(user);
return accessToken;
}
catch (error) {
throw new Error(error.message);
}
});
}
/**
* Attempt to login a user
*/
login(email, password) {
return __awaiter(this, void 0, void 0, function* () {
try {
// should maybe creat a method base on id and other information for better security
// need to view with Emre
const user = yield 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 (yield user.isValidPassword(password)) {
return token_1.default.createToken(user);
}
else {
throw new Error('Wrong credentials given');
}
}
catch (error) {
throw new Error('Unable to create user');
}
});
}
}
exports.default = UserService;
//# sourceMappingURL=UserService.js.map

@ -0,0 +1 @@
{"version":3,"file":"UserService.js","sourceRoot":"","sources":["../../src/service/UserService.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAAA,oFAA4D;AAC5D,2DAAmC;AAGnC,MAAM,WAAW;IAAjB;QACY,SAAI,GAAG,oBAAU,CAAC;IAuD9B,CAAC;IArDG;;OAEG;IACU,QAAQ,CACjB,IAAY,EACZ,KAAa,EACb,QAAgB,EAChB,MAAe,EACf,SAAkB;;YAElB,IAAI;gBACA,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC;oBAChC,IAAI;oBACJ,KAAK;oBACL,QAAQ;oBACR,MAAM;oBACN,SAAS;iBACZ,CAAC,CAAC;gBAEH,MAAM,WAAW,GAAG,eAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;gBAE5C,OAAO,WAAW,CAAC;aACtB;YAAC,OAAO,KAAW,EAAE;gBAClB,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aAClC;QACL,CAAC;KAAA;IAED;;OAEG;IACU,KAAK,CACd,KAAa,EACb,QAAgB;;YAEhB,IAAI;gBACA,mFAAmF;gBACnF,yBAAyB;gBACzB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;gBAChD,iDAAiD;gBAEjD,IAAI,CAAC,IAAI,EAAE;oBACP,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;iBAClE;gBAED,IAAI,MAAM,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE;oBACtC,OAAO,eAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;iBAClC;qBAAM;oBACH,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;iBAC9C;aACJ;YAAC,OAAO,KAAK,EAAE;gBACZ,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;aAC5C;QACL,CAAC;KAAA;CACJ;AAED,kBAAe,WAAW,CAAC"}

@ -5,15 +5,11 @@
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
"build": "tsc", "build": "tsc",
"dave": "nodemon ./src/index.ts",
"dev": "tsc -w & nodemon .", "dev": "tsc -w & nodemon .",
"start": "tsc & node .", "start": "tsc & node .",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"pre-commit": [
"ts.check",
"build",
"add-build"
],
"keywords": [], "keywords": [],
"author": "", "author": "",
"license": "ISC", "license": "ISC",
@ -31,11 +27,13 @@
"typescript": "^4.9.5" "typescript": "^4.9.5"
}, },
"dependencies": { "dependencies": {
"@types/cookie-parser": "^1.4.3",
"@types/crypto-js": "^4.1.1", "@types/crypto-js": "^4.1.1",
"@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", "bcrypt": "^5.1.0",
"cookie-parser": "^1.4.6",
"cors": "^2.8.5", "cors": "^2.8.5",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"express-winston": "^4.2.0", "express-winston": "^4.2.0",

@ -12,6 +12,7 @@ import mongoose from 'mongoose';
// import helmet from 'helmet'; // import helmet from 'helmet';
import http from 'http'; import http from 'http';
import cookieParser from 'cookie-parser';
class App { class App {
public express: Application; public express: Application;
@ -35,6 +36,9 @@ class App {
private initialiseMiddleware(): void { private initialiseMiddleware(): void {
// this.express.use(helmet()); // this.express.use(helmet());
this.express.use(cors()); this.express.use(cors());
this.express.use(cookieParser());
// this.express.use(morgan('dev')); // this.express.use(morgan('dev'));
this.express.use(express.json()); this.express.use(express.json());
this.express.use(express.urlencoded({ extended: false })); this.express.use(express.urlencoded({ extended: false }));

@ -1,236 +0,0 @@
// import Controller from '../Icontroller';
// import { Router, Request, Response, NextFunction, RequestHandler } from 'express';
// import HttpException from '../../middleware/exeption/httpExeption';
// import axios from 'axios';
// import AES from 'crypto-js'
// import querystring from 'querystring';
// import qs from 'qs';
// class SpotifyController implements Controller {
// public path = '/spot';
// public router = Router();
// constructor() {
// console.log("useeeee");
// this.initialiseRoutes();
// }
// initialiseRoutes() {
// // this.router.post(`${this.path}`,this.createTask);
// this.router.get(`${this.path}/likes/{user}/{id-spot}`,this.like);
// this.router.get(`${this.path}/callback`,this.getAccessToken);
// this.router.post(`${this.path}/refresh`,this.getRefreshToken);
// this.router.get(`${this.path}/spot`, this.getSpot);
// }
// // need to put in ENvironement file
// // private readonly CLIENT_CALLBACK_URL = "http://localhost:8080/callback";
// private readonly API_URL = "https://accounts.spotify.com/api/token";
// private readonly CLIENT_ID = "1f1e34e4b6ba48b388469dba80202b10";
// private readonly CLIENT_SECRET = "779371c6d4994a68b8dd6e84b0873c82";
// // private readonly CLIENT_CALLBACK_URL = "https://auth.expo.io/@thed47/FLAD//callback";
// private readonly CALLBACK_2 = 'https://flad-api-production.up.railway.app/api/spotify/callback';
// private readonly SCOPES ='user-read-private user-read-email user-read-playback-state user-read-currently-playing user-read-recently-played playlist-modify-public ugc-image-upload user-modify-playback-state';
// private readonly ENCRYPTION_SECRET = new CryptString(16);
// private login = async (
// req: Request,
// res: Response,
// next: NextFunction
// ): Promise<Response | void> => {
// console.log("useeeee== login");
// try {
// // const params = req.body;
// // if (!params.refresh_token) {
// // return res.json({
// // "error": "Parameter missing"
// // });
// // }
// // this.spotifyRequest({
// // grant_type: "authorization_code",
// // redirect_uri: this.CLIENT_CALLBACK_2,
// // // code: params.code
// // })
// console.log("aloorrr si c'est niquuuuuuuuuuuueeee" +this.CALLBACK_2+ "gennnnnnnnnrree vraiiiiiiiment ");
// res.redirect('https://accounts.spotify.com/authorize?' +
// qs.stringify({
// response_type: 'code',
// client_id: this.CLIENT_ID,
// scope: this.SCOPES,
// redirect_uri: this.CALLBACK_2,
// // state: this.ENCRYPTION_SECRET.stringCrypt
// }));
// // '?response_type=code' +
// // '&client_id=' +
// // "1f1e34e4b6ba48b388469dba80202b10" +
// // (this.SCOPES ? '&scope=' + encodeURIComponent(this.SCOPES) : '') +
// // '&redirect_uri=' +
// // encodeURIComponent(this.CALLBACK_2)
// // );
// // .then(session => {
// // let result = {
// // "access_token": session.access_token,
// // "expires_in": session.expires_in,
// // "refresh_token": this.encrypt(session.refresh_token)
// // };
// // return res.send(result);
// // })
// // .catch(response => {
// // return res.json(response);
// // });
// } catch (error) {
// next(new HttpException(400, 'Cannot create spot'));
// }
// };
// private getRefreshToken = async (
// req: Request,
// res: Response,
// next: NextFunction
// ): Promise<Response | void> => {
// console.log('UUse2');
// try {
// const params = req.query.refresh_token;
// if (!req.query.refresh_token) {
// return res.json({
// "error": "Parameter refresh_token missing"
// });
// }
// var authOptions = {
// method: 'POST',
// url: 'https://accounts.spotify.com/api/token',
// data: qs.stringify({
// grant_type: 'refresh_token',
// refresh_token: params
// }),
// headers: {
// 'Authorization': 'Basic ' + ( Buffer.from(this.CLIENT_ID + ':' + this.CLIENT_SECRET).toString('base64')),
// 'Content-Type' : 'application/x-www-form-urlencoded'
// },
// json: true
// };
// // request.post(authOptions, function(error, response, body) {
// // if (!error && response.statusCode === 200) {
// // var access_token = body.access_token;
// // res.send({
// // 'access_token': access_token
// // });
// // }
// // });
// axios(authOptions)
// .then(session => {
// if(session.status === 200){
// res.send({
// "access_token": session.data.access_token,
// "expires_in": session.data.expires_in
// });
// }});
// console.log("goood");
// } catch (error) {
// console.log("errur");
// next(new HttpException(400, 'Cannot create post'));
// }
// }
// public getSpot = async (
// req: Request,
// res: Response,
// next: NextFunction
// ): 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);
// } catch (error) {
// console.log('heuuuuuuuuuuuuuuuuuuuuubizzzaaarrreeee');
// console.log(error);
// next(new HttpException(400, 'On peut pas avoir darray mec'));
// } }
// private getAccessToken = async (
// req: Request,
// res: Response,
// next: NextFunction
// ): Promise<Response | void> => {
// console.log("useeeee== accesToken");
// var code = req.query.code;
// var state = req.query.state || null;
// // var storedState = req.cookies ? req.cookies[stateKey] : null;
// var authOptions = {
// method: 'POST',
// url: 'https://accounts.spotify.com/api/token',
// data: qs.stringify({
// code: code,
// redirect_uri: this.CALLBACK_2,
// grant_type: 'authorization_code'
// }),
// headers: {
// 'Authorization': 'Basic ' + ( Buffer.from(this.CLIENT_ID + ':' + this.CLIENT_SECRET).toString('base64')),
// 'Content-Type' : 'application/x-www-form-urlencoded'
// },
// json: true
// };
// try {
// var resp = await axios(authOptions);
// if (resp.status === 200) {
// console.log('oon esttt laaa');
// var access_token = resp.data.access_token;
// var expiration =resp.data.expires_in;
// var refresh = resp.data.refresh_token
// console.log(access_token);
// // res.send({
// // "access_token": access_token,
// // "expires_in": expiration,
// // "refresh" : refresh
// // });
// res.redirect('/#'+
// qs.stringify({
// "access_token": access_token,
// "expires_in": expiration,
// "refreshuyjfguk" : refresh
// }));
// }
// } catch (error) {
// console.log('heuuuuuuuuuuuuuuuuuuuuubizzzaaarrreeee');
// console.log(error);
// next(new HttpException(400, 'On peut pas te connecter mec'+ error.message));
// }
// };
// }
// export default SpotifyController;

@ -7,6 +7,7 @@ import CryptString from './crypt';
import AES from 'crypto-js' import AES from 'crypto-js'
import querystring from 'querystring'; import querystring from 'querystring';
import qs from 'qs'; import qs from 'qs';
import cookieParser from 'cookie-parser';
class SpotifyController implements Controller { class SpotifyController implements Controller {
public path = '/spotify'; public path = '/spotify';
@ -21,7 +22,7 @@ class SpotifyController implements Controller {
// this.router.post(`${this.path}`,this.createTask); // this.router.post(`${this.path}`,this.createTask);
this.router.get(`${this.path}/exchange`,this.login); this.router.get(`${this.path}/exchange`,this.login);
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.get(`${this.path}/refresh`,this.getRefreshToken);
this.router.get(`${this.path}/spot`, this.getSpot); this.router.get(`${this.path}/spot`, this.getSpot);
} }
@ -35,6 +36,7 @@ class SpotifyController implements Controller {
private readonly CALLBACK_2 = 'https://flad-api-production.up.railway.app/api/spotify/callback'; private readonly CALLBACK_2 = 'https://flad-api-production.up.railway.app/api/spotify/callback';
private readonly SCOPES ='user-read-private user-read-email user-read-playback-state user-read-currently-playing user-read-recently-played playlist-modify-public ugc-image-upload user-modify-playback-state'; private readonly SCOPES ='user-read-private user-read-email user-read-playback-state user-read-currently-playing user-read-recently-played playlist-modify-public ugc-image-upload user-modify-playback-state';
private readonly ENCRYPTION_SECRET = new CryptString(16); private readonly ENCRYPTION_SECRET = new CryptString(16);
private readonly clientRedirect= 'spotify_final_redirect-uri-key';
private login = async ( private login = async (
req: Request, req: Request,
@ -56,6 +58,8 @@ class SpotifyController implements Controller {
// redirect_uri: this.CLIENT_CALLBACK_2, // redirect_uri: this.CLIENT_CALLBACK_2,
// // code: params.code // // code: params.code
// }) // })
const redirectResponse = req.query.redirectUrl ? req.query.redirectUrl : req.headers.referer;
res.cookie(this.clientRedirect, redirectResponse);
console.log("aloorrr si c'est niquuuuuuuuuuuueeee" +this.CALLBACK_2+ "gennnnnnnnnrree vraiiiiiiiment "); console.log("aloorrr si c'est niquuuuuuuuuuuueeee" +this.CALLBACK_2+ "gennnnnnnnnrree vraiiiiiiiment ");
res.redirect('https://accounts.spotify.com/authorize?' + res.redirect('https://accounts.spotify.com/authorize?' +
qs.stringify({ qs.stringify({
@ -101,6 +105,7 @@ class SpotifyController implements Controller {
try { try {
const params = req.query.refresh_token; const params = req.query.refresh_token;
if (!req.query.refresh_token) { if (!req.query.refresh_token) {
return res.json({ return res.json({
"error": "Parameter refresh_token missing" "error": "Parameter refresh_token missing"
@ -131,9 +136,12 @@ class SpotifyController implements Controller {
axios(authOptions) axios(authOptions)
.then(session => { .then(session => {
if(session.status === 200){ if(session.status === 200){
console.log('### Information : responce ###' + JSON.stringify( session.data) );
console.log('### Information : refresh_token ###' + session.data.refresh_token);
res.send({ res.send({
"access_token": session.data.access_token, "access_token": session.data.access_token,
"refresh_token": session.data.refresh_token,
"expires_in": session.data.expires_in "expires_in": session.data.expires_in
}); });
}}); }});
@ -185,8 +193,11 @@ class SpotifyController implements Controller {
next: NextFunction next: NextFunction
): Promise<Response | void> => { ): Promise<Response | void> => {
console.log("useeeee== accesToken"); console.log("useeeee== accesToken");
var code = req.query.code; var code = req.query.code;
var state = req.query.state || null; var state = req.query.state || null;
var storedredirectUri = req.cookies ? req.cookies[this.clientRedirect] : null;
// var storedState = req.cookies ? req.cookies[stateKey] : null; // var storedState = req.cookies ? req.cookies[stateKey] : null;
var authOptions = { var authOptions = {
method: 'POST', method: 'POST',
@ -216,11 +227,12 @@ class SpotifyController implements Controller {
// "refresh" : refresh // "refresh" : refresh
// }); // });
res.redirect('/#'+ res.clearCookie(this.clientRedirect);
res.redirect(`${storedredirectUri}?` +
qs.stringify({ qs.stringify({
"access_token": access_token, "access_token": access_token,
"expires_in": expiration, "expires_in": expiration,
"refreshuyjfguk" : refresh "refresh_token" : refresh
})); }));
} }
} catch (error) { } catch (error) {

@ -212,17 +212,22 @@ class UserController implements Controller {
next: NextFunction next: NextFunction
): Promise<Response | void> => { ): Promise<Response | void> => {
try { try {
const longitude = Number(req.params.longitude); const longitude = Number(req.query.longitude);
const latitude = Number(req.params.latitude); const latitude = Number(req.query.latitude);
//verify::val_int(){ //verify::val_int(){
console.log('woooooooooooooo' + req); console.log('woooooooooooooo' + req);
if (isNaN(longitude) || isNaN(latitude)) { if (isNaN(longitude) || isNaN(latitude)) {
console.log('============' + longitude)
console.log('============' + latitude)
console.log('Impossible de convertir la chaîne en nombre'); console.log('Impossible de convertir la chaîne en nombre');
} }
//} //}
const userId = req.user.idFlad; const userId = req.user.idFlad;
const musicId = req.params.currentMusic; const musicId = String(req.query.currentMusic);
const data = await this.locationService.getNearUser(userId,musicId,latitude,longitude,); console.log('============' + longitude)
console.log('============' + latitude)
console.log('daaaaaaaaaaaaaaaaaaaaaa' + musicId);
const data = await this.locationService.getNearUser(userId,musicId,latitude,longitude);
console.log(data); console.log(data);
res.status(201).send(data); res.status(201).send(data);

@ -4,12 +4,11 @@ import AuthNavigation from './navigation/AuthNavigation';
import * as SplashScreen from 'expo-splash-screen'; import * as SplashScreen from 'expo-splash-screen';
SplashScreen.preventAutoHideAsync(); SplashScreen.preventAutoHideAsync();
export default function App() { export default function App() {
return ( return (
<Provider store={store}> <Provider store={store}>
<AuthNavigation/> <AuthNavigation/>
</Provider> </Provider>
); );
} }

@ -1,34 +0,0 @@
import SpotifyService from "../services/spotify/spotify.service";
class Manager {
// injection de dépences
spotifyService = new SpotifyService();
userService = new userService();
// spotify methods
apiAuthorization(url: string) {
this.spotifyService.apiAuthorization(url);
}
getCompleteMusic = async (id: string): Promise<Music> => {
// Map info = await spotifyService.getTrackInfo(id);
// return Music(id, info['name'], info['artist'], info['cover']);
}
removeFromPlaylist(id: string) {
this.spotifyService.removeFromPlaylist(id);
}
addToPlaylist(id: string) {
this.spotifyService.addToPlaylist(id);
}
playTrack(id: string) {
this.spotifyService.playTrack(id);
}
}
export default Manager;

@ -1,14 +0,0 @@
// export default class Music {
// private id : string;
// private name : string;
// private artist : string;
// private linkCover : string; // Image.source
// constructor(id : string, name : string, artist : string, linkCover : string){
// this.id = id;
// this.name = name;
// this.artist = artist;
// this.linkCover = linkCover;
// }
// }

@ -1,5 +0,0 @@
class TokenSpotify {
_accessToken: string;
_refreshToken: string;
late DateTime _tokenEnd;
}

@ -5,7 +5,7 @@ export default class MusicFactory {
const music = new Music( const music = new Music(
jsonMusic.id, jsonMusic.id,
jsonMusic.name, jsonMusic.name,
"", jsonMusic.artists[0].name,
jsonMusic.album.images[0].url, jsonMusic.album.images[0].url,
jsonMusic.preview_url jsonMusic.preview_url
); );

@ -1,14 +1,13 @@
import { View, Text, StyleSheet, Image } from 'react-native'; import { View, Text, StyleSheet, Image } from 'react-native';
export interface RenderCellProps { export interface RenderCellProps {
image: string; data : any;
title: string;
} }
export const LittleCard = (props: RenderCellProps) => { export const LittleCard = (props: RenderCellProps) => {
return ( return (
<View style={styles.similarContainer}> <View style={styles.similarContainer}>
<Image source={{ uri: props.image }} style={styles.similarPoster}></Image> <Image source={{ uri: props.data.image }} style={styles.similarPoster}></Image>
<Text numberOfLines={2} style={styles.similarTitleFilm}>{props.title} <Text numberOfLines={2} style={styles.similarTitleFilm}>{props.data.title}
</Text> </Text>
</View> </View>
) )

@ -0,0 +1,7 @@
Object.defineProperty(exports, '__esModule', {value: true});
require('./mqttLib');
const storage = require('./storage');
function initialize() {
global.localStorage = storage;
}
exports.default = initialize;

File diff suppressed because it is too large Load Diff

@ -0,0 +1,10 @@
const storage = {
setItem: (key, item) => {
storage[key] = item;
},
getItem: key => storage[key],
removeItem: key => {
delete storage[key];
},
};
export default storage;

@ -8,8 +8,12 @@ import * as SplashScreen from 'expo-splash-screen';
import { ChangeMode, getRefreshToken } from '../redux/thunk/authThunk'; import { ChangeMode, getRefreshToken } from '../redux/thunk/authThunk';
import * as Location from 'expo-location'; import * as Location from 'expo-location';
import SpotifyService from '../services/spotify/spotify.service'; import SpotifyService from '../services/spotify/spotify.service';
import { getCurrentUserMusic } from '../redux/thunk/spotThunk'; import { getCurrentUserMusic, getSpotList } from '../redux/thunk/spotThunk';
import Music from '../Model/Music'; import Music from '../Model/Music';
import axios from 'axios';
import qs from 'qs';
import * as SecureStore from 'expo-secure-store';
import { MY_SECURE_AUTH_STATE_KEY } from '../screens/Register';
export default function AuthNavigation() { export default function AuthNavigation() {
//@ts-ignore //@ts-ignore
@ -18,6 +22,8 @@ export default function AuthNavigation() {
const isLogin: boolean = useSelector(state => state.userReducer.isLogedIn); const isLogin: boolean = useSelector(state => state.userReducer.isLogedIn);
//@ts-ignore //@ts-ignore
const currentMusic: Music = useSelector(state => state.appReducer.userCurrentMusic); const currentMusic: Music = useSelector(state => state.appReducer.userCurrentMusic);
//@ts-ignore
const tokenSend: string = useSelector(state => state.userReducer.userFladToken);
const [appIsReady, setAppIsReady] = useState(false); const [appIsReady, setAppIsReady] = useState(false);
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -45,38 +51,63 @@ export default function AuthNavigation() {
console.log(`Une erreur s'est produite lors de la mise à jour de la valeur booléenne pour la clé 'dark': `, error); console.log(`Une erreur s'est produite lors de la mise à jour de la valeur booléenne pour la clé 'dark': `, error);
} }
} }
const requestLocationPermission = async () => {
const { status } = await Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
console.log('Permission to access location was denied');
} else {
console.log('Permission to access location was granted');
}
}
useEffect(() => { useEffect(() => {
ChangeDarkMode(); ChangeDarkMode();
prepare(); prepare();
}, [appIsReady, tokenProcesed]); requestLocationPermission();
useEffect(() => {
const sendLocationUpdate = async () => { const sendLocationUpdate = async () => {
try { try {
let tmpKey: string = await SecureStore.getItemAsync(MY_SECURE_AUTH_STATE_KEY) ;
//@ts-ignore //@ts-ignore
await dispatch(getCurrentUserMusic(theService)) await dispatch(getCurrentUserMusic(new SpotifyService(tmpKey)))
let { status } = await Location.requestForegroundPermissionsAsync(); let { status } = await Location.requestForegroundPermissionsAsync();
if (status == 'granted') { if (status == 'granted') {
console.log(appIsReady) // should app is ready
if (true) {// should app is ready
const locationresp = await Location.getCurrentPositionAsync({}); const locationresp = await Location.getCurrentPositionAsync({});
setLocation(locationresp);
// send location to server // send location to server
console.log(locationresp); if(currentMusic){
console.log(location);
const body: Record<string, string | boolean | number | (string | boolean | number)[]> = { const body: Record<string, string | boolean | number | (string | boolean | number)[]> = {
longitude: locationresp.coords.longitude, longitude: locationresp.coords.longitude,
latitude: locationresp.coords.latitude, latitude: locationresp.coords.latitude,
currentMusic: currentMusic.id currentMusic: currentMusic.id
} }
const resp = await axios({
url: 'https://flad-api-production.up.railway.app/api/users/nextTo?' + qs.stringify(body),
method: 'GET',
headers: {
Authorization: `Bearer ${tokenSend}`,
},
});
const datat: Record<string, string> = resp.data.listUser2;
//@ts-ignore
dispatch(getSpotList(datat, new SpotifyService(tmpKey)))
} }
else{
return;
}
} }
else { else {
//@ts-ignore
let {status} = Location.requestForegroundPermissionsAsync();
if (status !== 'granted') {
setErrorMsg('Permission to access location was denied'); setErrorMsg('Permission to access location was denied');
return; return;
} }
return;
}
} catch (error) { } catch (error) {
console.log(error); console.log(error);
} }
@ -85,21 +116,21 @@ export default function AuthNavigation() {
return () => { return () => {
clearInterval(interval); clearInterval(interval);
}; };
}, []); }, [appIsReady, tokenProcesed, currentMusic]);
if (tokenProcesed == false) { if (tokenProcesed == false) {
return null; return null;
} }
return ( return (
<SafeAreaProvider onLayout={() => setAppIsReady(true)}> <SafeAreaProvider onLayout={() => setAppIsReady(true)}>
{isLogin ? ( {isLogin ? (
<Navigation /> <Navigation />
) : ) :
<Navigation /> <StartNavigation/>
} }
</SafeAreaProvider> </SafeAreaProvider>
) )
} }
const theService = new SpotifyService('BQC0rAGJvxTt4-24P-nda6qP9iXYCql2eApnUAoEbZZkKemJ11cU3Nx-I_tKVX0FwEgFbIbSIuaVvxOapRVJq2z1Htyy3XQ5jIYNsrhrnp3KTCfppamAjxgDTf6khBrNGTxe6CNKBsMhc5IRnphey5Td2zJPvGMwnFFfMQdCtVAVsCNK7kPKlCAaf_kRMAoPn30Qk4RD45XmwtZIwQg7X0J4beGuHSiBf0MRjhsnFEW89GxVm8YuIVwgrDbF3izfPR0AlqS4IMJT5m4pEA72lYEwp1JnSDVsafILzmksaqG-11H3WAsWIENrOIu_j7qNgbvYwmUWXOrYmeWBkQ');

@ -18,10 +18,6 @@ export default function MusicNavigation() {
component={MusicDetail} component={MusicDetail}
sharedElements={(route) => { return [route.params.music.id] }} sharedElements={(route) => { return [route.params.music.id] }}
/> />
<Stack.Screen
name="Genre"
component={CurrentMusic}
/>
</Stack.Navigator> </Stack.Navigator>
) )
} }

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { createStackNavigator } from '@react-navigation/stack'; import { createStackNavigator } from '@react-navigation/stack';
import SpotPage from '../screens/Spot' import SpotPage from '../screens/spot'
import MusicDetail from '../screens/MusicDetail'; import MusicDetail from '../screens/MusicDetail';

@ -49,7 +49,8 @@
"react-native-web": "~0.18.9", "react-native-web": "~0.18.9",
"react-navigation-shared-element": "^3.1.3", "react-navigation-shared-element": "^3.1.3",
"react-redux": "^8.0.5", "react-redux": "^8.0.5",
"redux": "^4.2.1" "redux": "^4.2.1",
"expo-linking": "~3.3.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.9", "@babel/core": "^7.12.9",

@ -9,6 +9,19 @@ export const setSpotList = (spotList: Spot[]) => {
payload: spotList, payload: spotList,
}; };
} }
export const removeFromSpotList = (spot: Spot) => {
return {
type: spotTypes.REMOVE_SPOT,
payload: spot
}
}
export const addSpotListMock = (spotList: Spot[]) => {
return {
type: spotTypes.ADD_SPOT_MOCK,
payload: spotList,
};
}
export const setUserCurrentMusic = (currentMusic: Music) => { export const setUserCurrentMusic = (currentMusic: Music) => {
return { return {

@ -5,15 +5,9 @@ import { favoritesTypes } from "../types/favoritesTypes";
import { spotifyTypes } from "../types/spotifyTypes"; import { spotifyTypes } from "../types/spotifyTypes";
import { spotTypes } from "../types/spotTypes"; import { spotTypes } from "../types/spotTypes";
let tmpMusic: Music[] = [
new Music("03o8WSqd2K5rkGvn9IsLy2", "Autobahn", "Sch", "https://images.genius.com/83b6c98680d38bde1571f6b4093244b5.1000x1000x1.jpg", "https://p.scdn.co/mp3-preview/c55f95de81b8c3d0df04148da1b03bd38db56e8f?cid=774b29d4f13844c495f206cafdad9c86"),
new Music("6DPrYPPGYK218iVIZDix3i", "Freeze Raël", "Freeze Corleone", "https://intrld.com/wp-content/uploads/2020/08/freeze-corleone-la-menace-fanto%CC%82me.png", "https://p.scdn.co/mp3-preview/a9f9cb19ac1fe6db0d06b67decf8edbb25895a33?cid=774b29d4f13844c495f206cafdad9c86"),
new Music("5GFHFEASZeJF0gyWuDDjGE", "Kratos", "PNL", "https://upload.wikimedia.org/wikipedia/en/a/a0/PNL_-_Dans_la_l%C3%A9gende.png", "https://p.scdn.co/mp3-preview/9e854f4905c1228482e390169eb76d8520076b8f?cid=774b29d4f13844c495f206cafdad9c86"),
];
const initialState = { const initialState = {
spot: [] as Spot[], spot: [] as Spot[],
favoriteMusic: tmpMusic, favoriteMusic: [] as Music[],
userCurrentMusic: null userCurrentMusic: null
} }
@ -26,7 +20,13 @@ const appReducer = (state = initialState, action: any) => {
case favoritesTypes.REMOVE_FAVORITE_MUSICS: case favoritesTypes.REMOVE_FAVORITE_MUSICS:
return { ...state, favoriteMusic: state.favoriteMusic }; return { ...state, favoriteMusic: state.favoriteMusic };
case spotTypes.FETCH_SPOT: case spotTypes.FETCH_SPOT:
return { ...state, spot: action.payload }; const uniqueSpots = action.payload.filter((spot) => {
return !state.spot.some((s) => s.userSpotifyId === spot.userSpotifyId && s.music.id === spot.music.id);
});
const updatedSpotList = [...uniqueSpots, ...state.spot];
return { ...state, spot: updatedSpotList };
case spotTypes.REMOVE_SPOT:
return { ...state, spot: state.spot.filter((spot) => spot.userSpotifyId !== action.payload.userSpotifyId && spot.music.id !== action.payload.music.id) };
case discoveriesTypes.FETCH_DISCOVERIES: case discoveriesTypes.FETCH_DISCOVERIES:
return; return;
case spotifyTypes.GET_USER_CURRENT_MUSIC: case spotifyTypes.GET_USER_CURRENT_MUSIC:

@ -1,6 +1,10 @@
import { configureStore } from '@reduxjs/toolkit' import { configureStore } from '@reduxjs/toolkit'
import appReducer from './reducers/appReducer'; import appReducer from './reducers/appReducer';
import userReducer from './reducers/userReducer'; import userReducer from './reducers/userReducer';
import { spotTypes } from './types/spotTypes';
import { userTypes } from './types/userTypes';
import { spotifyTypes } from './types/spotifyTypes';
import { favoritesTypes } from './types/favoritesTypes';
// Reference here all your application reducers // Reference here all your application reducers
const reducer = { const reducer = {
@ -10,6 +14,13 @@ const reducer = {
const store = configureStore({ const store = configureStore({
reducer: reducer, reducer: reducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
serializableCheck: {
ignoredActions: [spotTypes.FETCH_SPOT, spotifyTypes.GET_USER_CURRENT_MUSIC, favoritesTypes.ADD_FAVORITE_MUSICS, favoritesTypes.REMOVE_FAVORITE_MUSICS, spotTypes.REMOVE_SPOT ],
ignoredActionPaths: ['appReducer'],
ignoredPaths: ['appReducer', 'userReducer']
}
})
},); },);
export default store; export default store;

@ -10,13 +10,17 @@ export const registerUser = (resgisterCredential: CredentialsRegister) => {
//@ts-ignore //@ts-ignore
return async dispatch => { return async dispatch => {
try { try {
console.log("rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr")
console.log(resgisterCredential);
console.log("rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr")
const config = { const config = {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
} }
const resp = await axios.post( const resp = await axios.post(
`${API_URL}/api/users/register`, 'https://flad-api-production.up.railway.app/api/users/register',
resgisterCredential, resgisterCredential,
config config
) )
@ -37,6 +41,7 @@ export const registerUser = (resgisterCredential: CredentialsRegister) => {
} }
} catch (error) { } catch (error) {
console.log('Login Failed'+ error.message + "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
dispatch(ChangeErrorSignup()) dispatch(ChangeErrorSignup())
} }
} }

@ -12,26 +12,13 @@ export type CreateSpotReqBody = {
linkCover: string; linkCover: string;
user: string; user: string;
} }
export const getSpotList = (resuestHandler: SpotifyService) => { export const getSpotList = (spotsData : Record<string, string> , resuestHandler: SpotifyService) => {
//@ts-ignore //@ts-ignore
return async dispatch => { return async dispatch => {
try { try {
//@ts-ignore //@ts-ignore
const userToken: string = await SecureStore.getItemAsync(key); if (spotsData) {
const headers = {
'Authorization': 'Bearer ' + userToken
};
const data = await axios.get(
"https://flad-api-production.up.railway.app/api/users/nextTo",
{ headers }
)
if (data.data.token) {
const spotsData: { [userId: string]: string } = {};
for (const item of data.data) {
spotsData[item.user] = item.music;
}
const spots = await Promise.all( const spots = await Promise.all(
Object.entries(spotsData).map(async ([userId, value]) => { Object.entries(spotsData).map(async ([userId, value]) => {
const completeMusic = await resuestHandler.getMusicById(value); const completeMusic = await resuestHandler.getMusicById(value);
@ -64,6 +51,9 @@ export const getCurrentUserMusic = (resuestHandler: SpotifyService) => {
} }
} }
const completeMusic = await resuestHandler.getMusicById(currentTrackResponse); const completeMusic = await resuestHandler.getMusicById(currentTrackResponse);
if(!completeMusic){
return;
}
dispatch(setUserCurrentMusic(completeMusic)); dispatch(setUserCurrentMusic(completeMusic));
} }
catch (error) { catch (error) {

@ -1,3 +1,5 @@
export const spotTypes = { export const spotTypes = {
FETCH_SPOT: 'FETCH_SPOT', FETCH_SPOT: 'FETCH_SPOT',
ADD_SPOT_MOCK: 'ADD_SPOT_MOCK',
REMOVE_SPOT: 'REMOVE_SPOT',
} }

@ -104,12 +104,6 @@ export default function FavoritePage() {
<FladyComponent image={item.source} /> <FladyComponent image={item.source} />
)} )}
/> />
<TouchableOpacity
style={[styles.button, styles.shadow]}
// @ts-ignore
onPress={() => navigation.navigate('Genre')}>
<Image source={require("../assets/icons/icons/next.png")} style={styles.buttonImage} />
</TouchableOpacity>
</> </>
} }
nestedScrollEnabled={true} nestedScrollEnabled={true}

@ -13,6 +13,7 @@ import { Feather as Icon } from "@expo/vector-icons";
import { HorizontalFlatList } from "../components/HorizontalFlatList"; import { HorizontalFlatList } from "../components/HorizontalFlatList";
import { LittleCard } from "../components/littleCard"; import { LittleCard } from "../components/littleCard";
import * as SecureStore from 'expo-secure-store'; import * as SecureStore from 'expo-secure-store';
import { MY_SECURE_AUTH_STATE_KEY } from "./Register";
const halfPi = Math.PI / 2; const halfPi = Math.PI / 2;
@ -27,22 +28,15 @@ const MusicDetail = ({ route }) => {
const navigator = useNavigation(); const navigator = useNavigation();
const [testtoken, setTesttoken] = useState('')
const sheet = async () => {
SecureStore.getItemAsync('MySecureAuthStateKey').then(result => { setTesttoken(result) });
}
useEffect(() => { useEffect(() => {
sheet();
getSimilarTrack(); getSimilarTrack();
}, [testtoken]); }, []);
const getSimilarTrack = async () => { const getSimilarTrack = async () => {
try { try {
const service = new SpotifyService(testtoken); let token = await SecureStore.getItemAsync(MY_SECURE_AUTH_STATE_KEY);
const service = new SpotifyService(token);
const simularMusic = await service.getSimilarTrack(currentspot.id, 5, 'FR'); const simularMusic = await service.getSimilarTrack(currentspot.id, 5, 'FR');
console.log("suggesstd", simularMusic);
setSimularMusic(simularMusic); setSimularMusic(simularMusic);
} catch (error) { } catch (error) {
console.error('Error ================ in getSimilarTrack', error); console.error('Error ================ in getSimilarTrack', error);
@ -140,7 +134,8 @@ const MusicDetail = ({ route }) => {
<View> <View>
</View> </View>
<TouchableOpacity activeOpacity={0.5} style={{ <TouchableOpacity activeOpacity={0.5}onPressIn={handlePlaySound}
onPressOut={handleStopSound} style={{
backgroundColor: '#F80404', backgroundColor: '#F80404',
borderRadius: 100, borderRadius: 100,
padding: normalize(23) padding: normalize(23)
@ -170,20 +165,18 @@ const MusicDetail = ({ route }) => {
}}> }}>
<Icon name="share" size={24} color="#FFFF"></Icon> <Icon name="share" size={24} color="#FFFF"></Icon>
{/* <FontAwesome name="bookmark" size={24} color="#FF0000" ></FontAwesome> */} {/* <FontAwesome name="bookmark" size={24} color="#FF0000" ></FontAwesome> */}
<Text style={{ fontSize: normalize(16), fontWeight: "700", color: '#FFFFFF' }}>Partagedr cette music</Text> <Text style={{ fontSize: normalize(16), fontWeight: "700", color: '#FFFFFF' }}>Partager cette music</Text>
</TouchableOpacity> </TouchableOpacity>
{/* <Pressable style={{flexDirection : 'row', justifyContent : 'space-between', alignItems: 'center', height: "10%" , borderRadius: 8, opacity: 84 ,backgroundColor: 'rgba(29, 16, 16, 0.84)' }}>
<FontAwesome name="bookmark" size={16} color="#FF0000" ></FontAwesome>
<Text style={{ fontSize: 16, fontWeight:"700",lineHeight:12, color : '#FFFFFF' }}>Dans ma collection 2</Text>
</Pressable> */}
</View> </View>
{simularMusic.length !== 0 && ( {simularMusic.length !== 0 && (
<HorizontalFlatList title={'Similar'} data={simularMusic}> <HorizontalFlatList title={'Similar'} data={simularMusic}>
{(props) => ( {(props) => (
<Pressable <Pressable
onPress={() => {
// @ts-ignore // @ts-ignore
onLongPress={() => { navigator.navigate("MusicDetail", { "music": props }) }} > navigator.replace("DetailsSpot", { "music": props }) }} >
<LittleCard image={props.image} title={props.title} /> <LittleCard data={props} />
</Pressable> </Pressable>
)} )}
</HorizontalFlatList> </HorizontalFlatList>

@ -18,20 +18,15 @@ const DismissKeyboard = ({ children }) => (
</TouchableWithoutFeedback> </TouchableWithoutFeedback>
) )
export const MY_SECURE_AUTH_STATE_KEY = 'MySecureAuthStateKey'; export const MY_SECURE_AUTH_STATE_KEY = 'MySecureAuthStateKeySpotify';
export const MY_SECURE_AUTH_STATE_KEY_REFRESH = 'MySecureAuthStateKeySpotifyREFRESH';
WebBrowser.maybeCompleteAuthSession(); WebBrowser.maybeCompleteAuthSession();
// Endpoint
const discovery = {
authorizationEndpoint: 'https://accounts.spotify.com/authorize',
tokenEndpoint: 'https://accounts.spotify.com/api/token',
};
// save the spotifyToken // save the spotifyToken
async function save(key: string, value: string) { async function save(key: string, value: string) {
await SecureStore.setItemAsync(key, value); await SecureStore.setItemAsync(key, value);
} }
export default function InscriptionPage() { export default function InscriptionPage() {
const [sound, setSound] = useState<Audio.Sound>(); const [sound, setSound] = useState<Audio.Sound>();
const navigation = useNavigation(); const navigation = useNavigation();
@ -46,34 +41,10 @@ export default function InscriptionPage() {
setSound(sound); setSound(sound);
await sound.playAsync(); await sound.playAsync();
} }
const [username, setUsername] = useState(''); const [username, setUsername] = useState('');
const [email, setEmail] = useState(''); const [email, setEmail] = useState('');
const [password, setPassword] = useState(''); const [password, setPassword] = useState('');
//spotify auth
const [response] = useAuthRequest(
{
responseType: AuthSession.ResponseType.Token,
clientId: '1f1e34e4b6ba48b388469dba80202b10',
scopes: ['user-read-private', 'user-read-email', 'user-read-playback-state', 'user-read-currently-playing', 'user-read-recently-played', 'playlist-modify-public', 'ugc-image-upload', 'user-modify-playback-state'],
redirectUri: makeRedirectUri({
scheme: 'flad'
}),
},
discovery
);
useEffect(() => {
if (response && response.type === 'success') {
const auth = response.params.access_token;
const storageValue = JSON.stringify(auth);
if (Platform.OS !== 'web') {
// Securely store the auth on your device
save(MY_SECURE_AUTH_STATE_KEY, storageValue);
}
}
}, [response]);
const dispatch = useDispatch(); const dispatch = useDispatch();
@ -83,7 +54,7 @@ export default function InscriptionPage() {
password: password, password: password,
idSpotify: spotifyToken, idSpotify: spotifyToken,
name: username, name: username,
idFlad: "3030" idFlad: "9835698"
}; };
//@ts-ignore //@ts-ignore
dispatch(registerUser(credentials)) dispatch(registerUser(credentials))
@ -91,19 +62,24 @@ export default function InscriptionPage() {
} }
const getTokens2 = async () => { const getTokens2 = async () => {
try { try {
const response = await fetch('https://flad-api-production.up.railway.app/api/spotify/callback'); const redirectUri = AuthSession.makeRedirectUri();
const responseJson = await response.json(); const result = await AuthSession.startAsync({
authUrl: 'https://flad-api-production.up.railway.app/api/spotify/exchange?' + '&redirectUrl=' +
encodeURIComponent(redirectUri)
})
const { const {
access_token: accessToken, access_token: access_token,
} = responseJson; refresh_token: refresh_token,
} = result.params
await setSpotifyToken(accessToken); save(MY_SECURE_AUTH_STATE_KEY, access_token);
setSpotifyToken(access_token)
console.log(spotifyToken); save(MY_SECURE_AUTH_STATE_KEY_REFRESH, refresh_token);
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
} }
return ( return (
<DismissKeyboard> <DismissKeyboard>
<View style={styles.container}> <View style={styles.container}>

@ -332,7 +332,7 @@ export default function Setting() {
</View> </View>
<View style={styles.musicActually}> <View style={styles.musicActually}>
<CardMusic image="{currentMusic.image}" title="{currentMusic.title}" description="PNL" id='1' /> <CardMusic image={currentMusic.image} title={currentMusic.title} description={currentMusic.bio} id='1' />
<Image source={require("../assets/images/FladyShadow.png")} style={styles.mascot} /> <Image source={require("../assets/images/FladyShadow.png")} style={styles.mascot} />
</View> </View>

@ -6,8 +6,6 @@ import { makeRedirectUri, useAuthRequest } from 'expo-auth-session';
import { Buffer } from 'buffer'; import { Buffer } from 'buffer';
import * as SecureStore from 'expo-secure-store'; import * as SecureStore from 'expo-secure-store';
export const MY_SECURE_AUTH_STATE_KEY = 'MySecureAuthStateKey'
WebBrowser.maybeCompleteAuthSession() WebBrowser.maybeCompleteAuthSession()
const discovery = { const discovery = {

@ -1,5 +1,5 @@
import { View, Text, Dimensions, StyleSheet, ImageBackground, Image, Pressable, TouchableOpacity, SafeAreaView } from 'react-native' import { View, Text, Dimensions, StyleSheet, ImageBackground, Image, Pressable, TouchableOpacity, SafeAreaView } from 'react-native'
import React, { useCallback, useRef, useState } from 'react' import React, { useCallback,useEffect, useRef, useState } from 'react'
import { LinearGradient } from 'expo-linear-gradient'; import { LinearGradient } from 'expo-linear-gradient';
import * as Haptics from 'expo-haptics'; import * as Haptics from 'expo-haptics';
import Animated from 'react-native-reanimated'; import Animated from 'react-native-reanimated';
@ -13,30 +13,36 @@ import FladLoading from '../components/FladLoadingScreen';
import { useNavigation } from '@react-navigation/native'; import { useNavigation } from '@react-navigation/native';
import Music from '../Model/Music'; import Music from '../Model/Music';
import { addFavoritesMusic } from '../redux/actions/appActions'; import { addFavoritesMusic } from '../redux/actions/appActions';
import { useDispatch } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { Spot } from '../Model/Spot'; import { Spot } from '../Model/Spot';
import { removeFromSpotList, setSpotList } from '../redux/actions/spotActions';
export default function SpotPage() { export default function SpotPage() {
const [cards, setCards] = useState(spotArray2); //@ts-ignore
const spotReducer = useSelector(state => state.appReducer.spot)
const [cards, setCards] = useState<Spot[]>(spotReducer);
const [currentCard, setcurrentCard] = useState(cards[cards.length - 1]); const [currentCard, setcurrentCard] = useState(cards[cards.length - 1]);
const onSwipe = (index: number, direction: 'left' | 'right' | 'down') => { useEffect(() => {
setCards(spotReducer);
setcurrentCard(spotReducer[spotReducer.length - 1]);
}, [spotReducer]);
const onSwipe = (direction: 'left' | 'right' | 'down') => {
if (direction === 'right') { if (direction === 'right') {
// Swiped right // Swiped right
addLike(currentCard.music); addLike(currentCard);
} else if (direction === 'left') { } else if (direction === 'left') {
// Swiped left // Swiped left
console.log('Swiped left'); console.log('Swiped left');
removeSpots(currentCard);
} }
else if (direction === 'down') { else if (direction === 'down') {
// Swiped down // Swiped down
addMockSpots();
console.log('Swiped down'); console.log('Swiped down');
} }
// update the state of the cards state when it remove this
setTimeout(() => {
setCards(cards.filter((_, i) => i !== index));
setcurrentCard(cards[index - 1]);
}, 3);
}; };
const likeButtonref = useRef<LottieView>(null); const likeButtonref = useRef<LottieView>(null);
@ -48,11 +54,22 @@ export default function SpotPage() {
const dispatch = useDispatch(); const dispatch = useDispatch();
function addLike(music: Music) { function addLike(spot: Spot) {
onLike(); onLike();
dispatch(addFavoritesMusic(music)) dispatch(addFavoritesMusic(spot.music))
dispatch(removeFromSpotList(spot));
}
function removeSpots(spot: Spot) {
dispatch(removeFromSpotList(spot));
}
function addMockSpots() {
//@ts-ignore
dispatch(setSpotList(spotArray2))
} }
const navigator = useNavigation(); const navigator = useNavigation();
const { width: wWidht } = Dimensions.get("window"); const { width: wWidht } = Dimensions.get("window");
@ -105,14 +122,13 @@ export default function SpotPage() {
<View style={{ flex: 1.83, justifyContent: 'center', alignItems: 'center' }}> <View style={{ flex: 1.83, justifyContent: 'center', alignItems: 'center' }}>
{cards.map((card, index) => ( {cards.map((card) => (
<View key={card.userSpotifyId} style={{ position: 'absolute' }} > <View key={card.userSpotifyId} style={{ position: 'absolute' }} >
<Pressable onLongPress={() => { hapti(card) }} > <Pressable onLongPress={() => { hapti(card) }} >
<Card <Card
title={card.music.title} title={card.music.title}
image={card.music.image} image={card.music.image}
onSwipe={(direction) => { onSwipe(index, direction) }} onSwipe={(direction) => { onSwipe(direction) }}
/> />
</Pressable> </Pressable>
</View> </View>
@ -122,13 +138,13 @@ export default function SpotPage() {
<View style={{ flex: 1, flexDirection: 'row', alignItems: "flex-start", justifyContent: 'center' }}> <View style={{ flex: 1, flexDirection: 'row', alignItems: "flex-start", justifyContent: 'center' }}>
<Animated.View style={{ flexDirection: 'row', width: '92%', alignItems: "center", justifyContent: 'space-evenly' }}> <Animated.View style={{ flexDirection: 'row', width: '92%', alignItems: "center", justifyContent: 'space-evenly' }}>
<TouchableOpacity style={styles.button} onPress={onLike}> <TouchableOpacity style={styles.button} onPress={() => onSwipe('left')}>
<Image source={require("../assets/icons/icons/icon_dislike_no_text.png")} style={{width: '45%', height: '40%'}}/> <Image source={require("../assets/icons/icons/icon_dislike_no_text.png")} style={{width: '45%', height: '40%'}}/>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={onLike}> <TouchableOpacity style={styles.button} onPress={() => onSwipe('down')}>
<Image source={require("../assets/icons/icons/icon_discovery_no_text.png")} style={{width: '58%', height: '50%', marginLeft: '7%'}}/> <Image source={require("../assets/icons/icons/icon_discovery_no_text.png")} style={{width: '58%', height: '50%', marginLeft: '7%'}}/>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={styles.button} onPress={onLike}> <TouchableOpacity style={styles.button} onPress={() => onSwipe('right')}>
<LottieView autoPlay={false} loop={false} ref={likeButtonref} speed={2} source={Lotties.likeAnimation} style={styles.lottie} /> <LottieView autoPlay={false} loop={false} ref={likeButtonref} speed={2} source={Lotties.likeAnimation} style={styles.lottie} />
</TouchableOpacity> </TouchableOpacity>

@ -29,6 +29,8 @@ export default class SpotifyService implements IspotifyService {
if (respMusic.status != 200) { if (respMusic.status != 200) {
return null; return null;
} }
console.log(respMusic.data.artists[0].id);
return MusicFactory.mapFromSpotifyTrack(respMusic.data); return MusicFactory.mapFromSpotifyTrack(respMusic.data);
} }

@ -1,4 +1,6 @@
import axios, { AxiosResponse } from "axios"; import axios, { AxiosResponse } from "axios";
import { MY_SECURE_AUTH_STATE_KEY, MY_SECURE_AUTH_STATE_KEY_REFRESH } from "../../../screens/Register";
import * as SecureStore from 'expo-secure-store';
export type Methods = 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH'; export type Methods = 'GET' | 'POST' | 'DELETE' | 'PUT' | 'PATCH';
@ -32,10 +34,45 @@ export class RequestHandler {
}, },
data: options.body data: options.body
}); });
return resp; return resp;
} }
catch(error : any){} catch(error : any){
const errorMessage = error.response.data?.error?.message;
if (errorMessage === "Invalid access token" || errorMessage === "The access token expired" ) {
console.log('### Warning ! ### try refresh token Request Handler ' +error);
const newToken = await this.refreshToken();
console.log('### GOOD Warning ! ### new token Request Handler ' +newToken);
// Mettez à jour le token dans le store ou le reducer ici
return this.spotifyFetch(url, options, newToken);
}
else {
console.log('### Error ! ### while fetching Data in the SPotify Request Handler ' +error);
throw error;
} }
} }
}
private async refreshToken(): Promise<string> {
export class AuthHandler{} // Faites une demande à votre API pour obtenir un nouveau token Spotify
let refreshToken = await SecureStore.getItemAsync(MY_SECURE_AUTH_STATE_KEY_REFRESH);
console.log('refresh token : ' + refreshToken);
const response = await axios.get(`https://flad-api-production.up.railway.app/api/spotify/refresh?refresh_token=${refreshToken}`);
// Renvoie le nouveau token
const {
access_token : access_token,
refresh_token: refresh_token,
} = response.data as SpotifyAuthResponse
console.log('new access token : ' + access_token);
console.log('new refresh token : ' + refresh_token);
await SecureStore.setItemAsync(MY_SECURE_AUTH_STATE_KEY, access_token);
return access_token;
}
}
interface SpotifyAuthResponse {
access_token: string;
refresh_token: string;
}

@ -1,13 +1,5 @@
import { AuthentificationService } from "../Auth/authentificationService.service";
export class UserService { export class UserService {
constructor(private auth: AuthentificationService) { }
getUserProfile() {
const user = this.auth.currentUser;
const userDocRef = doc(this.firestore, `User/${user.uid}`);
return docData(userDocRef);
}
} }

@ -0,0 +1,80 @@
import initialize from '../lib';
initialize();
class MqttClient {
constructor() {
const clientId = 'ReactNativeMqtt';
this.client = new Paho.MQTT.Client('127.0.0.1', 9001, clientId);
this.client.onMessageArrived = this.onMessageArrived;
this.callbacks = {};
this.onSuccessHandler = undefined;
this.onConnectionLostHandler = undefined;
this.isConnected = false;
}
onConnect = (onSuccessHandler, onConnectionLostHandler) => {
this.onSuccessHandler = onSuccessHandler;
this.onConnectionLostHandler = onConnectionLostHandler;
this.client.onConnectionLost = () => {
this.isConnected = false;
onConnectionLostHandler();
};
this.client.connect({
timeout: 10,
onSuccess: () => {
this.isConnected = true;
onSuccessHandler();
},
useSSL: false,
onFailure: this.onError,
reconnect: true,
keepAliveInterval: 20,
cleanSession: true,
});
};
onError = ({errorMessage}) => {
console.log(errorMessage);
this.isConnected = false;
Alert.alert('Failed', 'Failed to connect to MQTT', [
{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel',
},
{
text: 'Try Again',
onPress: () =>
this.onConnect(
this.onSuccessHandler,
this.onConnectionLostHandler,
),
},
]);
};
onMessageArrived = message => {
const {payloadString, topic} = message;
console.log('onMessageArrived:', payloadString);
this.callbacks[topic](payloadString);
};
onPublish = (topic, message) => {
this.client.publish(topic, message);
};
onSubscribe = (topic, callback) => {
this.callbacks[topic] = callback;
this.client.subscribe(topic);
};
unsubscribe = topic => {
delete this.callbacks[topic];
this.client.unsubscribe(topic);
};
}
let client = new MqttClient();
export {client as MqttClient};

@ -0,0 +1,10 @@
FROM eclipse-mosquitto
# Copie de votre configuration Mosquitto personnalisée dans le conteneur
COPY mosquitto.conf /mosquitto/config/mosquitto.conf
# Exposez le port Mosquitto
EXPOSE 1883
# Démarrer Mosquitto
CMD ["/usr/sbin/mosquitto", "-c", "/mosquitto/config/mosquitto.conf"]

@ -0,0 +1,910 @@
# Config file for mosquitto
#
# See mosquitto.conf(5) for more information.
#
# Default values are shown, uncomment to change.
#
# Use the # character to indicate a comment, but only if it is the
# very first character on the line.
# =================================================================
# General configuration
# =================================================================
# Use per listener security settings.
#
# It is recommended this option be set before any other options.
#
# If this option is set to true, then all authentication and access control
# options are controlled on a per listener basis. The following options are
# affected:
#
# acl_file
# allow_anonymous
# allow_zero_length_clientid
# auto_id_prefix
# password_file
# plugin
# plugin_opt_*
# psk_file
#
# Note that if set to true, then a durable client (i.e. with clean session set
# to false) that has disconnected will use the ACL settings defined for the
# listener that it was most recently connected to.
#
# The default behaviour is for this to be set to false, which maintains the
# setting behaviour from previous versions of mosquitto.
#per_listener_settings false
# This option controls whether a client is allowed to connect with a zero
# length client id or not. This option only affects clients using MQTT v3.1.1
# and later. If set to false, clients connecting with a zero length client id
# are disconnected. If set to true, clients will be allocated a client id by
# the broker. This means it is only useful for clients with clean session set
# to true.
#allow_zero_length_clientid true
# If allow_zero_length_clientid is true, this option allows you to set a prefix
# to automatically generated client ids to aid visibility in logs.
# Defaults to 'auto-'
#auto_id_prefix auto-
# This option affects the scenario when a client subscribes to a topic that has
# retained messages. It is possible that the client that published the retained
# message to the topic had access at the time they published, but that access
# has been subsequently removed. If check_retain_source is set to true, the
# default, the source of a retained message will be checked for access rights
# before it is republished. When set to false, no check will be made and the
# retained message will always be published. This affects all listeners.
#check_retain_source true
# QoS 1 and 2 messages will be allowed inflight per client until this limit
# is exceeded. Defaults to 0. (No maximum)
# See also max_inflight_messages
#max_inflight_bytes 0
# The maximum number of QoS 1 and 2 messages currently inflight per
# client.
# This includes messages that are partway through handshakes and
# those that are being retried. Defaults to 20. Set to 0 for no
# maximum. Setting to 1 will guarantee in-order delivery of QoS 1
# and 2 messages.
#max_inflight_messages 20
# For MQTT v5 clients, it is possible to have the server send a "server
# keepalive" value that will override the keepalive value set by the client.
# This is intended to be used as a mechanism to say that the server will
# disconnect the client earlier than it anticipated, and that the client should
# use the new keepalive value. The max_keepalive option allows you to specify
# that clients may only connect with keepalive less than or equal to this
# value, otherwise they will be sent a server keepalive telling them to use
# max_keepalive. This only applies to MQTT v5 clients. The default, and maximum
# value allowable, is 65535.
#
# Set to 0 to allow clients to set keepalive = 0, which means no keepalive
# checks are made and the client will never be disconnected by the broker if no
# messages are received. You should be very sure this is the behaviour that you
# want.
#
# For MQTT v3.1.1 and v3.1 clients, there is no mechanism to tell the client
# what keepalive value they should use. If an MQTT v3.1.1 or v3.1 client
# specifies a keepalive time greater than max_keepalive they will be sent a
# CONNACK message with the "identifier rejected" reason code, and disconnected.
#
#max_keepalive 65535
# For MQTT v5 clients, it is possible to have the server send a "maximum packet
# size" value that will instruct the client it will not accept MQTT packets
# with size greater than max_packet_size bytes. This applies to the full MQTT
# packet, not just the payload. Setting this option to a positive value will
# set the maximum packet size to that number of bytes. If a client sends a
# packet which is larger than this value, it will be disconnected. This applies
# to all clients regardless of the protocol version they are using, but v3.1.1
# and earlier clients will of course not have received the maximum packet size
# information. Defaults to no limit. Setting below 20 bytes is forbidden
# because it is likely to interfere with ordinary client operation, even with
# very small payloads.
#max_packet_size 0
# QoS 1 and 2 messages above those currently in-flight will be queued per
# client until this limit is exceeded. Defaults to 0. (No maximum)
# See also max_queued_messages.
# If both max_queued_messages and max_queued_bytes are specified, packets will
# be queued until the first limit is reached.
#max_queued_bytes 0
# Set the maximum QoS supported. Clients publishing at a QoS higher than
# specified here will be disconnected.
#max_qos 2
# The maximum number of QoS 1 and 2 messages to hold in a queue per client
# above those that are currently in-flight. Defaults to 1000. Set
# to 0 for no maximum (not recommended).
# See also queue_qos0_messages.
# See also max_queued_bytes.
#max_queued_messages 1000
#
# This option sets the maximum number of heap memory bytes that the broker will
# allocate, and hence sets a hard limit on memory use by the broker. Memory
# requests that exceed this value will be denied. The effect will vary
# depending on what has been denied. If an incoming message is being processed,
# then the message will be dropped and the publishing client will be
# disconnected. If an outgoing message is being sent, then the individual
# message will be dropped and the receiving client will be disconnected.
# Defaults to no limit.
#memory_limit 0
# This option sets the maximum publish payload size that the broker will allow.
# Received messages that exceed this size will not be accepted by the broker.
# The default value is 0, which means that all valid MQTT messages are
# accepted. MQTT imposes a maximum payload size of 268435455 bytes.
#message_size_limit 0
# This option allows the session of persistent clients (those with clean
# session set to false) that are not currently connected to be removed if they
# do not reconnect within a certain time frame. This is a non-standard option
# in MQTT v3.1. MQTT v3.1.1 and v5.0 allow brokers to remove client sessions.
#
# Badly designed clients may set clean session to false whilst using a randomly
# generated client id. This leads to persistent clients that connect once and
# never reconnect. This option allows these clients to be removed. This option
# allows persistent clients (those with clean session set to false) to be
# removed if they do not reconnect within a certain time frame.
#
# The expiration period should be an integer followed by one of h d w m y for
# hour, day, week, month and year respectively. For example
#
# persistent_client_expiration 2m
# persistent_client_expiration 14d
# persistent_client_expiration 1y
#
# The default if not set is to never expire persistent clients.
#persistent_client_expiration
# Write process id to a file. Default is a blank string which means
# a pid file shouldn't be written.
# This should be set to /var/run/mosquitto/mosquitto.pid if mosquitto is
# being run automatically on boot with an init script and
# start-stop-daemon or similar.
#pid_file
# Set to true to queue messages with QoS 0 when a persistent client is
# disconnected. These messages are included in the limit imposed by
# max_queued_messages and max_queued_bytes
# Defaults to false.
# This is a non-standard option for the MQTT v3.1 spec but is allowed in
# v3.1.1.
#queue_qos0_messages false
# Set to false to disable retained message support. If a client publishes a
# message with the retain bit set, it will be disconnected if this is set to
# false.
#retain_available true
# Disable Nagle's algorithm on client sockets. This has the effect of reducing
# latency of individual messages at the potential cost of increasing the number
# of packets being sent.
#set_tcp_nodelay false
# Time in seconds between updates of the $SYS tree.
# Set to 0 to disable the publishing of the $SYS tree.
#sys_interval 10
# The MQTT specification requires that the QoS of a message delivered to a
# subscriber is never upgraded to match the QoS of the subscription. Enabling
# this option changes this behaviour. If upgrade_outgoing_qos is set true,
# messages sent to a subscriber will always match the QoS of its subscription.
# This is a non-standard option explicitly disallowed by the spec.
#upgrade_outgoing_qos false
# When run as root, drop privileges to this user and its primary
# group.
# Set to root to stay as root, but this is not recommended.
# If set to "mosquitto", or left unset, and the "mosquitto" user does not exist
# then it will drop privileges to the "nobody" user instead.
# If run as a non-root user, this setting has no effect.
# Note that on Windows this has no effect and so mosquitto should be started by
# the user you wish it to run as.
#user mosquitto
# =================================================================
# Listeners
# =================================================================
# Listen on a port/ip address combination. By using this variable
# multiple times, mosquitto can listen on more than one port. If
# this variable is used and neither bind_address nor port given,
# then the default listener will not be started.
# The port number to listen on must be given. Optionally, an ip
# address or host name may be supplied as a second argument. In
# this case, mosquitto will attempt to bind the listener to that
# address and so restrict access to the associated network and
# interface. By default, mosquitto will listen on all interfaces.
# Note that for a websockets listener it is not possible to bind to a host
# name.
#
# On systems that support Unix Domain Sockets, it is also possible
# to create a # Unix socket rather than opening a TCP socket. In
# this case, the port number should be set to 0 and a unix socket
# path must be provided, e.g.
# listener 0 /tmp/mosquitto.sock
#
# listener port-number [ip address/host name/unix socket path]
#listener
# By default, a listener will attempt to listen on all supported IP protocol
# versions. If you do not have an IPv4 or IPv6 interface you may wish to
# disable support for either of those protocol versions. In particular, note
# that due to the limitations of the websockets library, it will only ever
# attempt to open IPv6 sockets if IPv6 support is compiled in, and so will fail
# if IPv6 is not available.
#
# Set to `ipv4` to force the listener to only use IPv4, or set to `ipv6` to
# force the listener to only use IPv6. If you want support for both IPv4 and
# IPv6, then do not use the socket_domain option.
#
#socket_domain
# Bind the listener to a specific interface. This is similar to
# the [ip address/host name] part of the listener definition, but is useful
# when an interface has multiple addresses or the address may change. If used
# with the [ip address/host name] part of the listener definition, then the
# bind_interface option will take priority.
# Not available on Windows.
#
# Example: bind_interface eth0
#bind_interface
# When a listener is using the websockets protocol, it is possible to serve
# http data as well. Set http_dir to a directory which contains the files you
# wish to serve. If this option is not specified, then no normal http
# connections will be possible.
#http_dir
# The maximum number of client connections to allow. This is
# a per listener setting.
# Default is -1, which means unlimited connections.
# Note that other process limits mean that unlimited connections
# are not really possible. Typically the default maximum number of
# connections possible is around 1024.
#max_connections -1
# The listener can be restricted to operating within a topic hierarchy using
# the mount_point option. This is achieved be prefixing the mount_point string
# to all topics for any clients connected to this listener. This prefixing only
# happens internally to the broker; the client will not see the prefix.
#mount_point
# Choose the protocol to use when listening.
# This can be either mqtt or websockets.
# Certificate based TLS may be used with websockets, except that only the
# cafile, certfile, keyfile, ciphers, and ciphers_tls13 options are supported.
#protocol mqtt
# Set use_username_as_clientid to true to replace the clientid that a client
# connected with with its username. This allows authentication to be tied to
# the clientid, which means that it is possible to prevent one client
# disconnecting another by using the same clientid.
# If a client connects with no username it will be disconnected as not
# authorised when this option is set to true.
# Do not use in conjunction with clientid_prefixes.
# See also use_identity_as_username.
# This does not apply globally, but on a per-listener basis.
#use_username_as_clientid
# Change the websockets headers size. This is a global option, it is not
# possible to set per listener. This option sets the size of the buffer used in
# the libwebsockets library when reading HTTP headers. If you are passing large
# header data such as cookies then you may need to increase this value. If left
# unset, or set to 0, then the default of 1024 bytes will be used.
#websockets_headers_size
# -----------------------------------------------------------------
# Certificate based SSL/TLS support
# -----------------------------------------------------------------
# The following options can be used to enable certificate based SSL/TLS support
# for this listener. Note that the recommended port for MQTT over TLS is 8883,
# but this must be set manually.
#
# See also the mosquitto-tls man page and the "Pre-shared-key based SSL/TLS
# support" section. Only one of certificate or PSK encryption support can be
# enabled for any listener.
# Both of certfile and keyfile must be defined to enable certificate based
# TLS encryption.
# Path to the PEM encoded server certificate.
#certfile
# Path to the PEM encoded keyfile.
#keyfile
# If you wish to control which encryption ciphers are used, use the ciphers
# option. The list of available ciphers can be optained using the "openssl
# ciphers" command and should be provided in the same format as the output of
# that command. This applies to TLS 1.2 and earlier versions only. Use
# ciphers_tls1.3 for TLS v1.3.
#ciphers
# Choose which TLS v1.3 ciphersuites are used for this listener.
# Defaults to "TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256"
#ciphers_tls1.3
# If you have require_certificate set to true, you can create a certificate
# revocation list file to revoke access to particular client certificates. If
# you have done this, use crlfile to point to the PEM encoded revocation file.
#crlfile
# To allow the use of ephemeral DH key exchange, which provides forward
# security, the listener must load DH parameters. This can be specified with
# the dhparamfile option. The dhparamfile can be generated with the command
# e.g. "openssl dhparam -out dhparam.pem 2048"
#dhparamfile
# By default an TLS enabled listener will operate in a similar fashion to a
# https enabled web server, in that the server has a certificate signed by a CA
# and the client will verify that it is a trusted certificate. The overall aim
# is encryption of the network traffic. By setting require_certificate to true,
# the client must provide a valid certificate in order for the network
# connection to proceed. This allows access to the broker to be controlled
# outside of the mechanisms provided by MQTT.
#require_certificate false
# cafile and capath define methods of accessing the PEM encoded
# Certificate Authority certificates that will be considered trusted when
# checking incoming client certificates.
# cafile defines the path to a file containing the CA certificates.
# capath defines a directory that will be searched for files
# containing the CA certificates. For capath to work correctly, the
# certificate files must have ".crt" as the file ending and you must run
# "openssl rehash <path to capath>" each time you add/remove a certificate.
#cafile
#capath
# If require_certificate is true, you may set use_identity_as_username to true
# to use the CN value from the client certificate as a username. If this is
# true, the password_file option will not be used for this listener.
#use_identity_as_username false
# -----------------------------------------------------------------
# Pre-shared-key based SSL/TLS support
# -----------------------------------------------------------------
# The following options can be used to enable PSK based SSL/TLS support for
# this listener. Note that the recommended port for MQTT over TLS is 8883, but
# this must be set manually.
#
# See also the mosquitto-tls man page and the "Certificate based SSL/TLS
# support" section. Only one of certificate or PSK encryption support can be
# enabled for any listener.
# The psk_hint option enables pre-shared-key support for this listener and also
# acts as an identifier for this listener. The hint is sent to clients and may
# be used locally to aid authentication. The hint is a free form string that
# doesn't have much meaning in itself, so feel free to be creative.
# If this option is provided, see psk_file to define the pre-shared keys to be
# used or create a security plugin to handle them.
#psk_hint
# When using PSK, the encryption ciphers used will be chosen from the list of
# available PSK ciphers. If you want to control which ciphers are available,
# use the "ciphers" option. The list of available ciphers can be optained
# using the "openssl ciphers" command and should be provided in the same format
# as the output of that command.
#ciphers
# Set use_identity_as_username to have the psk identity sent by the client used
# as its username. Authentication will be carried out using the PSK rather than
# the MQTT username/password and so password_file will not be used for this
# listener.
#use_identity_as_username false
# =================================================================
# Persistence
# =================================================================
# If persistence is enabled, save the in-memory database to disk
# every autosave_interval seconds. If set to 0, the persistence
# database will only be written when mosquitto exits. See also
# autosave_on_changes.
# Note that writing of the persistence database can be forced by
# sending mosquitto a SIGUSR1 signal.
#autosave_interval 1800
# If true, mosquitto will count the number of subscription changes, retained
# messages received and queued messages and if the total exceeds
# autosave_interval then the in-memory database will be saved to disk.
# If false, mosquitto will save the in-memory database to disk by treating
# autosave_interval as a time in seconds.
#autosave_on_changes false
# Save persistent message data to disk (true/false).
# This saves information about all messages, including
# subscriptions, currently in-flight messages and retained
# messages.
# retained_persistence is a synonym for this option.
#persistence false
# The filename to use for the persistent database, not including
# the path.
#persistence_file mosquitto.db
# Location for persistent database.
# Default is an empty string (current directory).
# Set to e.g. /var/lib/mosquitto if running as a proper service on Linux or
# similar.
#persistence_location
# =================================================================
# Logging
# =================================================================
# Places to log to. Use multiple log_dest lines for multiple
# logging destinations.
# Possible destinations are: stdout stderr syslog topic file dlt
#
# stdout and stderr log to the console on the named output.
#
# syslog uses the userspace syslog facility which usually ends up
# in /var/log/messages or similar.
#
# topic logs to the broker topic '$SYS/broker/log/<severity>',
# where severity is one of D, E, W, N, I, M which are debug, error,
# warning, notice, information and message. Message type severity is used by
# the subscribe/unsubscribe log_types and publishes log messages to
# $SYS/broker/log/M/susbcribe or $SYS/broker/log/M/unsubscribe.
#
# The file destination requires an additional parameter which is the file to be
# logged to, e.g. "log_dest file /var/log/mosquitto.log". The file will be
# closed and reopened when the broker receives a HUP signal. Only a single file
# destination may be configured.
#
# The dlt destination is for the automotive `Diagnostic Log and Trace` tool.
# This requires that Mosquitto has been compiled with DLT support.
#
# Note that if the broker is running as a Windows service it will default to
# "log_dest none" and neither stdout nor stderr logging is available.
# Use "log_dest none" if you wish to disable logging.
#log_dest stderr
# Types of messages to log. Use multiple log_type lines for logging
# multiple types of messages.
# Possible types are: debug, error, warning, notice, information,
# none, subscribe, unsubscribe, websockets, all.
# Note that debug type messages are for decoding the incoming/outgoing
# network packets. They are not logged in "topics".
#log_type error
#log_type warning
#log_type notice
#log_type information
# If set to true, client connection and disconnection messages will be included
# in the log.
#connection_messages true
# If using syslog logging (not on Windows), messages will be logged to the
# "daemon" facility by default. Use the log_facility option to choose which of
# local0 to local7 to log to instead. The option value should be an integer
# value, e.g. "log_facility 5" to use local5.
#log_facility
# If set to true, add a timestamp value to each log message.
#log_timestamp true
# Set the format of the log timestamp. If left unset, this is the number of
# seconds since the Unix epoch.
# This is a free text string which will be passed to the strftime function. To
# get an ISO 8601 datetime, for example:
# log_timestamp_format %Y-%m-%dT%H:%M:%S
#log_timestamp_format
# Change the websockets logging level. This is a global option, it is not
# possible to set per listener. This is an integer that is interpreted by
# libwebsockets as a bit mask for its lws_log_levels enum. See the
# libwebsockets documentation for more details. "log_type websockets" must also
# be enabled.
#websockets_log_level 0
# =================================================================
# Security
# =================================================================
# If set, only clients that have a matching prefix on their
# clientid will be allowed to connect to the broker. By default,
# all clients may connect.
# For example, setting "secure-" here would mean a client "secure-
# client" could connect but another with clientid "mqtt" couldn't.
#clientid_prefixes
# Boolean value that determines whether clients that connect
# without providing a username are allowed to connect. If set to
# false then a password file should be created (see the
# password_file option) to control authenticated client access.
#
# Defaults to false, unless there are no listeners defined in the configuration
# file, in which case it is set to true, but connections are only allowed from
# the local machine.
#allow_anonymous false
# -----------------------------------------------------------------
# Default authentication and topic access control
# -----------------------------------------------------------------
# Control access to the broker using a password file. This file can be
# generated using the mosquitto_passwd utility. If TLS support is not compiled
# into mosquitto (it is recommended that TLS support should be included) then
# plain text passwords are used, in which case the file should be a text file
# with lines in the format:
# username:password
# The password (and colon) may be omitted if desired, although this
# offers very little in the way of security.
#
# See the TLS client require_certificate and use_identity_as_username options
# for alternative authentication options. If a plugin is used as well as
# password_file, the plugin check will be made first.
#password_file
# Access may also be controlled using a pre-shared-key file. This requires
# TLS-PSK support and a listener configured to use it. The file should be text
# lines in the format:
# identity:key
# The key should be in hexadecimal format without a leading "0x".
# If an plugin is used as well, the plugin check will be made first.
#psk_file
# Control access to topics on the broker using an access control list
# file. If this parameter is defined then only the topics listed will
# have access.
# If the first character of a line of the ACL file is a # it is treated as a
# comment.
# Topic access is added with lines of the format:
#
# topic [read|write|readwrite|deny] <topic>
#
# The access type is controlled using "read", "write", "readwrite" or "deny".
# This parameter is optional (unless <topic> contains a space character) - if
# not given then the access is read/write. <topic> can contain the + or #
# wildcards as in subscriptions.
#
# The "deny" option can used to explicity deny access to a topic that would
# otherwise be granted by a broader read/write/readwrite statement. Any "deny"
# topics are handled before topics that grant read/write access.
#
# The first set of topics are applied to anonymous clients, assuming
# allow_anonymous is true. User specific topic ACLs are added after a
# user line as follows:
#
# user <username>
#
# The username referred to here is the same as in password_file. It is
# not the clientid.
#
#
# If is also possible to define ACLs based on pattern substitution within the
# topic. The patterns available for substition are:
#
# %c to match the client id of the client
# %u to match the username of the client
#
# The substitution pattern must be the only text for that level of hierarchy.
#
# The form is the same as for the topic keyword, but using pattern as the
# keyword.
# Pattern ACLs apply to all users even if the "user" keyword has previously
# been given.
#
# If using bridges with usernames and ACLs, connection messages can be allowed
# with the following pattern:
# pattern write $SYS/broker/connection/%c/state
#
# pattern [read|write|readwrite] <topic>
#
# Example:
#
# pattern write sensor/%u/data
#
# If an plugin is used as well as acl_file, the plugin check will be
# made first.
#acl_file
# -----------------------------------------------------------------
# External authentication and topic access plugin options
# -----------------------------------------------------------------
# External authentication and access control can be supported with the
# plugin option. This is a path to a loadable plugin. See also the
# plugin_opt_* options described below.
#
# The plugin option can be specified multiple times to load multiple
# plugins. The plugins will be processed in the order that they are specified
# here. If the plugin option is specified alongside either of
# password_file or acl_file then the plugin checks will be made first.
#
# If the per_listener_settings option is false, the plugin will be apply to all
# listeners. If per_listener_settings is true, then the plugin will apply to
# the current listener being defined only.
#
# This option is also available as `auth_plugin`, but this use is deprecated
# and will be removed in the future.
#
#plugin
# If the plugin option above is used, define options to pass to the
# plugin here as described by the plugin instructions. All options named
# using the format plugin_opt_* will be passed to the plugin, for example:
#
# This option is also available as `auth_opt_*`, but this use is deprecated
# and will be removed in the future.
#
# plugin_opt_db_host
# plugin_opt_db_port
# plugin_opt_db_username
# plugin_opt_db_password
# =================================================================
# Bridges
# =================================================================
# A bridge is a way of connecting multiple MQTT brokers together.
# Create a new bridge using the "connection" option as described below. Set
# options for the bridges using the remaining parameters. You must specify the
# address and at least one topic to subscribe to.
#
# Each connection must have a unique name.
#
# The address line may have multiple host address and ports specified. See
# below in the round_robin description for more details on bridge behaviour if
# multiple addresses are used. Note that if you use an IPv6 address, then you
# are required to specify a port.
#
# The direction that the topic will be shared can be chosen by
# specifying out, in or both, where the default value is out.
# The QoS level of the bridged communication can be specified with the next
# topic option. The default QoS level is 0, to change the QoS the topic
# direction must also be given.
#
# The local and remote prefix options allow a topic to be remapped when it is
# bridged to/from the remote broker. This provides the ability to place a topic
# tree in an appropriate location.
#
# For more details see the mosquitto.conf man page.
#
# Multiple topics can be specified per connection, but be careful
# not to create any loops.
#
# If you are using bridges with cleansession set to false (the default), then
# you may get unexpected behaviour from incoming topics if you change what
# topics you are subscribing to. This is because the remote broker keeps the
# subscription for the old topic. If you have this problem, connect your bridge
# with cleansession set to true, then reconnect with cleansession set to false
# as normal.
#connection <name>
#address <host>[:<port>] [<host>[:<port>]]
#topic <topic> [[[out | in | both] qos-level] local-prefix remote-prefix]
# If you need to have the bridge connect over a particular network interface,
# use bridge_bind_address to tell the bridge which local IP address the socket
# should bind to, e.g. `bridge_bind_address 192.168.1.10`
#bridge_bind_address
# If a bridge has topics that have "out" direction, the default behaviour is to
# send an unsubscribe request to the remote broker on that topic. This means
# that changing a topic direction from "in" to "out" will not keep receiving
# incoming messages. Sending these unsubscribe requests is not always
# desirable, setting bridge_attempt_unsubscribe to false will disable sending
# the unsubscribe request.
#bridge_attempt_unsubscribe true
# Set the version of the MQTT protocol to use with for this bridge. Can be one
# of mqttv50, mqttv311 or mqttv31. Defaults to mqttv311.
#bridge_protocol_version mqttv311
# Set the clean session variable for this bridge.
# When set to true, when the bridge disconnects for any reason, all
# messages and subscriptions will be cleaned up on the remote
# broker. Note that with cleansession set to true, there may be a
# significant amount of retained messages sent when the bridge
# reconnects after losing its connection.
# When set to false, the subscriptions and messages are kept on the
# remote broker, and delivered when the bridge reconnects.
#cleansession false
# Set the amount of time a bridge using the lazy start type must be idle before
# it will be stopped. Defaults to 60 seconds.
#idle_timeout 60
# Set the keepalive interval for this bridge connection, in
# seconds.
#keepalive_interval 60
# Set the clientid to use on the local broker. If not defined, this defaults to
# 'local.<clientid>'. If you are bridging a broker to itself, it is important
# that local_clientid and clientid do not match.
#local_clientid
# If set to true, publish notification messages to the local and remote brokers
# giving information about the state of the bridge connection. Retained
# messages are published to the topic $SYS/broker/connection/<clientid>/state
# unless the notification_topic option is used.
# If the message is 1 then the connection is active, or 0 if the connection has
# failed.
# This uses the last will and testament feature.
#notifications true
# Choose the topic on which notification messages for this bridge are
# published. If not set, messages are published on the topic
# $SYS/broker/connection/<clientid>/state
#notification_topic
# Set the client id to use on the remote end of this bridge connection. If not
# defined, this defaults to 'name.hostname' where name is the connection name
# and hostname is the hostname of this computer.
# This replaces the old "clientid" option to avoid confusion. "clientid"
# remains valid for the time being.
#remote_clientid
# Set the password to use when connecting to a broker that requires
# authentication. This option is only used if remote_username is also set.
# This replaces the old "password" option to avoid confusion. "password"
# remains valid for the time being.
#remote_password
# Set the username to use when connecting to a broker that requires
# authentication.
# This replaces the old "username" option to avoid confusion. "username"
# remains valid for the time being.
#remote_username
# Set the amount of time a bridge using the automatic start type will wait
# until attempting to reconnect.
# This option can be configured to use a constant delay time in seconds, or to
# use a backoff mechanism based on "Decorrelated Jitter", which adds a degree
# of randomness to when the restart occurs.
#
# Set a constant timeout of 20 seconds:
# restart_timeout 20
#
# Set backoff with a base (start value) of 10 seconds and a cap (upper limit) of
# 60 seconds:
# restart_timeout 10 30
#
# Defaults to jitter with a base of 5 and cap of 30
#restart_timeout 5 30
# If the bridge has more than one address given in the address/addresses
# configuration, the round_robin option defines the behaviour of the bridge on
# a failure of the bridge connection. If round_robin is false, the default
# value, then the first address is treated as the main bridge connection. If
# the connection fails, the other secondary addresses will be attempted in
# turn. Whilst connected to a secondary bridge, the bridge will periodically
# attempt to reconnect to the main bridge until successful.
# If round_robin is true, then all addresses are treated as equals. If a
# connection fails, the next address will be tried and if successful will
# remain connected until it fails
#round_robin false
# Set the start type of the bridge. This controls how the bridge starts and
# can be one of three types: automatic, lazy and once. Note that RSMB provides
# a fourth start type "manual" which isn't currently supported by mosquitto.
#
# "automatic" is the default start type and means that the bridge connection
# will be started automatically when the broker starts and also restarted
# after a short delay (30 seconds) if the connection fails.
#
# Bridges using the "lazy" start type will be started automatically when the
# number of queued messages exceeds the number set with the "threshold"
# parameter. It will be stopped automatically after the time set by the
# "idle_timeout" parameter. Use this start type if you wish the connection to
# only be active when it is needed.
#
# A bridge using the "once" start type will be started automatically when the
# broker starts but will not be restarted if the connection fails.
#start_type automatic
# Set the number of messages that need to be queued for a bridge with lazy
# start type to be restarted. Defaults to 10 messages.
# Must be less than max_queued_messages.
#threshold 10
# If try_private is set to true, the bridge will attempt to indicate to the
# remote broker that it is a bridge not an ordinary client. If successful, this
# means that loop detection will be more effective and that retained messages
# will be propagated correctly. Not all brokers support this feature so it may
# be necessary to set try_private to false if your bridge does not connect
# properly.
#try_private true
# Some MQTT brokers do not allow retained messages. MQTT v5 gives a mechanism
# for brokers to tell clients that they do not support retained messages, but
# this is not possible for MQTT v3.1.1 or v3.1. If you need to bridge to a
# v3.1.1 or v3.1 broker that does not support retained messages, set the
# bridge_outgoing_retain option to false. This will remove the retain bit on
# all outgoing messages to that bridge, regardless of any other setting.
#bridge_outgoing_retain true
# If you wish to restrict the size of messages sent to a remote bridge, use the
# bridge_max_packet_size option. This sets the maximum number of bytes for
# the total message, including headers and payload.
# Note that MQTT v5 brokers may provide their own maximum-packet-size property.
# In this case, the smaller of the two limits will be used.
# Set to 0 for "unlimited".
#bridge_max_packet_size 0
# -----------------------------------------------------------------
# Certificate based SSL/TLS support
# -----------------------------------------------------------------
# Either bridge_cafile or bridge_capath must be defined to enable TLS support
# for this bridge.
# bridge_cafile defines the path to a file containing the
# Certificate Authority certificates that have signed the remote broker
# certificate.
# bridge_capath defines a directory that will be searched for files containing
# the CA certificates. For bridge_capath to work correctly, the certificate
# files must have ".crt" as the file ending and you must run "openssl rehash
# <path to capath>" each time you add/remove a certificate.
#bridge_cafile
#bridge_capath
# If the remote broker has more than one protocol available on its port, e.g.
# MQTT and WebSockets, then use bridge_alpn to configure which protocol is
# requested. Note that WebSockets support for bridges is not yet available.
#bridge_alpn
# When using certificate based encryption, bridge_insecure disables
# verification of the server hostname in the server certificate. This can be
# useful when testing initial server configurations, but makes it possible for
# a malicious third party to impersonate your server through DNS spoofing, for
# example. Use this option in testing only. If you need to resort to using this
# option in a production environment, your setup is at fault and there is no
# point using encryption.
#bridge_insecure false
# Path to the PEM encoded client certificate, if required by the remote broker.
#bridge_certfile
# Path to the PEM encoded client private key, if required by the remote broker.
#bridge_keyfile
# -----------------------------------------------------------------
# PSK based SSL/TLS support
# -----------------------------------------------------------------
# Pre-shared-key encryption provides an alternative to certificate based
# encryption. A bridge can be configured to use PSK with the bridge_identity
# and bridge_psk options. These are the client PSK identity, and pre-shared-key
# in hexadecimal format with no "0x". Only one of certificate and PSK based
# encryption can be used on one
# bridge at once.
#bridge_identity
#bridge_psk
# =================================================================
# External config files
# =================================================================
# External configuration files may be included by using the
# include_dir option. This defines a directory that will be searched
# for config files. All files that end in '.conf' will be loaded as
# a configuration file. It is best to have this as the last option
# in the main file. This option will only be processed from the main
# configuration file. The directory specified must not contain the
# main configuration file.
# Files within include_dir will be loaded sorted in case-sensitive
# alphabetical order, with capital letters ordered first. If this option is
# given multiple times, all of the files from the first instance will be
# processed before the next instance. See the man page for examples.
#include_dir
listener 1883 0.0.0.0
allow_anonymous true
listener 9001 127.0.0.1
protocol websockets
Loading…
Cancel
Save