BelikanM commited on
Commit
85dc5bd
·
1 Parent(s): 8e39276

Add Node.js backend server with Dockerfile

Browse files
Files changed (4) hide show
  1. Dockerfile +15 -0
  2. README.md +14 -4
  3. package.json +24 -0
  4. server.js +229 -0
Dockerfile ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM node:18
2
+
3
+ WORKDIR /app
4
+
5
+ COPY package*.json ./
6
+
7
+ RUN npm install
8
+
9
+ COPY . .
10
+
11
+ ENV PORT=7860
12
+
13
+ EXPOSE 7860
14
+
15
+ CMD ["npm", "start"]
README.md CHANGED
@@ -1,12 +1,22 @@
1
  ---
2
- title: Server
3
- emoji: 🐨
4
  colorFrom: blue
5
- colorTo: pink
6
  sdk: docker
7
  pinned: false
8
  license: mit
9
- short_description: excelapp
10
  ---
11
 
 
 
 
 
 
 
 
 
 
 
12
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Backend Server
3
+ emoji: 🚀
4
  colorFrom: blue
5
+ colorTo: red
6
  sdk: docker
7
  pinned: false
8
  license: mit
9
+ short_description: Node.js backend for authentication and notifications
10
  ---
11
 
12
+ # Backend Server
13
+
14
+ A Node.js Express server for user authentication, OTP verification, and email notifications using Cloudinary for data storage and Nodemailer for emails.
15
+
16
+ ## Features
17
+
18
+ - User registration and login with OTP
19
+ - Email notifications
20
+ - Cloudinary integration for user data storage
21
+
22
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
package.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "backend",
3
+ "version": "1.0.0",
4
+ "description": "Backend server for vehicle management app",
5
+ "main": "server.js",
6
+ "scripts": {
7
+ "start": "node server.js"
8
+ },
9
+ "dependencies": {
10
+ "cloudinary": "^1.41.0",
11
+ "cors": "^2.8.5",
12
+ "dotenv": "^16.3.1",
13
+ "express": "^4.18.2",
14
+ "mongodb": "^7.0.0",
15
+ "nodemailer": "^6.9.7"
16
+ },
17
+ "devDependencies": {
18
+ "pkg": "^5.8.1"
19
+ },
20
+ "keywords": [],
21
+ "author": "",
22
+ "license": "ISC",
23
+ "type": "commonjs"
24
+ }
server.js ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const express = require('express');
2
+ const nodemailer = require('nodemailer');
3
+ const crypto = require('crypto');
4
+ const cors = require('cors');
5
+ const https = require('https');
6
+ const cloudinary = require('cloudinary').v2;
7
+ require('dotenv').config({ path: process.cwd() + '/.env' });
8
+
9
+ const app = express();
10
+ app.use(express.json());
11
+ app.use(cors());
12
+
13
+ // Configuration Cloudinary
14
+ cloudinary.config({
15
+ cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
16
+ api_key: process.env.CLOUDINARY_API_KEY,
17
+ api_secret: process.env.CLOUDINARY_API_SECRET
18
+ });
19
+
20
+ console.log('Cloudinary configured with cloud_name:', process.env.CLOUDINARY_CLOUD_NAME);
21
+
22
+ // Configuration Nodemailer
23
+ const transporter = nodemailer.createTransport({
24
+ service: 'gmail',
25
+ auth: {
26
+ user: process.env.EMAIL_USER,
27
+ pass: process.env.EMAIL_PASS
28
+ }
29
+ });
30
+
31
+ console.log('Nodemailer transporter created for user:', process.env.EMAIL_USER);
32
+
33
+ // Stockage temporaire des OTP
34
+ const otpStore = new Map();
35
+
36
+ // Fonction pour charger les utilisateurs depuis Cloudinary
37
+ async function loadUsers() {
38
+ try {
39
+ console.log('Loading users from Cloudinary...');
40
+ const result = await cloudinary.api.resources({ resource_type: 'raw', type: 'upload', prefix: 'users/', max_results: 500 });
41
+ console.log('Cloudinary resources fetched:', result.resources.length);
42
+ const users = {};
43
+ for (const resource of result.resources) {
44
+ const publicId = resource.public_id;
45
+ console.log('Processing user:', publicId);
46
+ const downloadResult = await cloudinary.api.resource(publicId, { resource_type: 'raw' });
47
+ const url = downloadResult.secure_url;
48
+ const userData = await new Promise((resolve, reject) => {
49
+ https.get(url, (res) => {
50
+ let data = '';
51
+ res.on('data', (chunk) => data += chunk);
52
+ res.on('end', () => {
53
+ try {
54
+ resolve(JSON.parse(data));
55
+ } catch (e) {
56
+ reject(e);
57
+ }
58
+ });
59
+ }).on('error', reject);
60
+ });
61
+ if (userData.email) {
62
+ users[userData.email] = userData;
63
+ }
64
+ }
65
+ console.log('Users loaded:', Object.keys(users).length);
66
+ return users;
67
+ } catch (error) {
68
+ console.error('Erreur chargement utilisateurs:', error);
69
+ return {};
70
+ }
71
+ }
72
+
73
+ // Fonction pour sauvegarder un utilisateur dans Cloudinary
74
+ async function saveUser(email, userData) {
75
+ try {
76
+ const hash = crypto.createHash('md5').update(email).digest('hex');
77
+ const dataStr = JSON.stringify({ ...userData, email }); // Assurer que l'email est inclus
78
+ const dataBase64 = Buffer.from(dataStr).toString('base64');
79
+ await cloudinary.uploader.upload(`data:text/plain;base64,${dataBase64}`, {
80
+ public_id: `users/${hash}`,
81
+ resource_type: 'raw'
82
+ });
83
+ } catch (error) {
84
+ console.error('Erreur sauvegarde utilisateur:', error);
85
+ }
86
+ }
87
+
88
+ let users = {};
89
+
90
+ // Charger les utilisateurs au démarrage
91
+ loadUsers().then(loadedUsers => {
92
+ users = loadedUsers;
93
+ });
94
+
95
+ // Route d'inscription
96
+ app.post('/register', async (req, res) => {
97
+ const { email } = req.body;
98
+
99
+ if (!email) {
100
+ return res.status(400).json({ error: 'Email requis' });
101
+ }
102
+
103
+ if (users[email]) {
104
+ console.log(`Tentative d'inscription pour email déjà enregistré: ${email}`);
105
+ return res.status(400).json({ error: 'Utilisateur déjà enregistré' });
106
+ }
107
+
108
+ const otp = crypto.randomInt(100000, 999999).toString();
109
+ otpStore.set(email, { otp, expires: Date.now() + 5 * 60 * 1000 });
110
+
111
+ try {
112
+ console.log('Sending OTP email to:', email);
113
+ await transporter.sendMail({
114
+ from: process.env.EMAIL_USER,
115
+ to: email,
116
+ subject: 'Code de vérification - Inscription',
117
+ text: `Votre code de vérification est: ${otp}`
118
+ });
119
+ console.log('OTP email sent successfully for registration');
120
+ res.json({ message: 'Code envoyé à votre email' });
121
+ } catch (error) {
122
+ console.error('Erreur envoi email:', error);
123
+ res.status(500).json({ error: 'Erreur envoi email' });
124
+ }
125
+ });
126
+
127
+ // Route de connexion
128
+ app.post('/login', async (req, res) => {
129
+ const { email } = req.body;
130
+
131
+ if (!email) {
132
+ return res.status(400).json({ error: 'Email requis' });
133
+ }
134
+
135
+ if (!users[email]) {
136
+ console.log(`Tentative de connexion pour email non enregistré: ${email}`);
137
+ return res.status(400).json({ error: 'Utilisateur non trouvé' });
138
+ }
139
+
140
+ const otp = crypto.randomInt(100000, 999999).toString();
141
+ otpStore.set(email, { otp, expires: Date.now() + 5 * 60 * 1000 });
142
+
143
+ try {
144
+ console.log('Sending login OTP email to:', email);
145
+ await transporter.sendMail({
146
+ from: process.env.EMAIL_USER,
147
+ to: email,
148
+ subject: 'Code de vérification - Connexion',
149
+ text: `Votre code de vérification est: ${otp}`
150
+ });
151
+ console.log('Login OTP email sent successfully');
152
+ res.json({ message: 'Code envoyé à votre email' });
153
+ } catch (error) {
154
+ console.error('Erreur envoi email:', error);
155
+ res.status(500).json({ error: 'Erreur envoi email' });
156
+ }
157
+ });
158
+
159
+ // Route de vérification OTP
160
+ app.post('/verify', async (req, res) => {
161
+ const { email, otp } = req.body;
162
+
163
+ if (!email || !otp) {
164
+ return res.status(400).json({ error: 'Email et OTP requis' });
165
+ }
166
+
167
+ const stored = otpStore.get(email);
168
+
169
+ if (!stored || stored.otp !== otp || Date.now() > stored.expires) {
170
+ console.log(`OTP invalide ou expiré pour ${email}`);
171
+ return res.status(400).json({ error: 'OTP invalide ou expiré' });
172
+ }
173
+
174
+ otpStore.delete(email);
175
+
176
+ // Enregistrer l'utilisateur si c'est une inscription
177
+ if (!users[email]) {
178
+ users[email] = { email, registeredAt: new Date() };
179
+ console.log(`Nouveau utilisateur enregistré: ${email}`);
180
+ await saveUser(email, users[email]);
181
+ console.log(`Utilisateur ${email} sauvegardé dans Cloudinary`);
182
+ } else {
183
+ console.log(`Utilisateur existant connecté: ${email}`);
184
+ }
185
+
186
+ res.json({ message: 'Authentification réussie', token: 'dummy-token' });
187
+ });
188
+
189
+ // Route pour envoyer des notifications par email
190
+ app.post('/send-notification', async (req, res) => {
191
+ try {
192
+ const { to, subject, html, action_type, entity_type, entity_id, user_info, timestamp } = req.body;
193
+
194
+ if (!to || !subject || !html) {
195
+ return res.status(400).json({ error: 'Destinataire, sujet et contenu HTML requis' });
196
+ }
197
+
198
+ // Configuration de l'email
199
+ const mailOptions = {
200
+ from: process.env.EMAIL_USER,
201
+ to: to,
202
+ subject: subject,
203
+ html: html
204
+ };
205
+
206
+ // Envoi de l'email
207
+ const info = await transporter.sendMail(mailOptions);
208
+ console.log('Email de notification envoyé:', info.messageId);
209
+
210
+ res.json({
211
+ message: 'Notification envoyée avec succès',
212
+ messageId: info.messageId,
213
+ action_type,
214
+ entity_type,
215
+ entity_id,
216
+ user_info,
217
+ timestamp
218
+ });
219
+
220
+ } catch (error) {
221
+ console.error('Erreur envoi notification:', error);
222
+ res.status(500).json({ error: 'Erreur envoi notification: ' + error.message });
223
+ }
224
+ });
225
+
226
+ const PORT = process.env.PORT || 3000;
227
+ app.listen(PORT, () => {
228
+ console.log(`Serveur démarré sur le port ${PORT}`);
229
+ });