push
Browse files- package-lock.json +77 -0
- package.json +32 -26
- src/scripts/createAdmin.ts +98 -18
- src/server.ts +4 -0
- zurri-mock-frontend +1 -1
- zurriwebsite +1 -0
package-lock.json
CHANGED
|
@@ -22,6 +22,7 @@
|
|
| 22 |
"paystack-node": "*",
|
| 23 |
"pg": "*",
|
| 24 |
"pinata": "*",
|
|
|
|
| 25 |
"reflect-metadata": "*",
|
| 26 |
"swagger-jsdoc": "*",
|
| 27 |
"swagger-ui-express": "*",
|
|
@@ -5528,12 +5529,77 @@
|
|
| 5528 |
"url": "https://opencollective.com/express"
|
| 5529 |
}
|
| 5530 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5531 |
"node_modules/react-is": {
|
| 5532 |
"version": "18.3.1",
|
| 5533 |
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
|
| 5534 |
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
|
| 5535 |
"dev": true
|
| 5536 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5537 |
"node_modules/readable-stream": {
|
| 5538 |
"version": "3.6.2",
|
| 5539 |
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
|
@@ -5716,6 +5782,12 @@
|
|
| 5716 |
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
| 5717 |
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
| 5718 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5719 |
"node_modules/semver": {
|
| 5720 |
"version": "6.3.1",
|
| 5721 |
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
|
@@ -5760,6 +5832,11 @@
|
|
| 5760 |
"node": ">= 18"
|
| 5761 |
}
|
| 5762 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5763 |
"node_modules/set-function-length": {
|
| 5764 |
"version": "1.2.2",
|
| 5765 |
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
|
|
|
| 22 |
"paystack-node": "*",
|
| 23 |
"pg": "*",
|
| 24 |
"pinata": "*",
|
| 25 |
+
"react-router-dom": "^7.9.6",
|
| 26 |
"reflect-metadata": "*",
|
| 27 |
"swagger-jsdoc": "*",
|
| 28 |
"swagger-ui-express": "*",
|
|
|
|
| 5529 |
"url": "https://opencollective.com/express"
|
| 5530 |
}
|
| 5531 |
},
|
| 5532 |
+
"node_modules/react": {
|
| 5533 |
+
"version": "19.2.0",
|
| 5534 |
+
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
| 5535 |
+
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
| 5536 |
+
"peer": true,
|
| 5537 |
+
"engines": {
|
| 5538 |
+
"node": ">=0.10.0"
|
| 5539 |
+
}
|
| 5540 |
+
},
|
| 5541 |
+
"node_modules/react-dom": {
|
| 5542 |
+
"version": "19.2.0",
|
| 5543 |
+
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
| 5544 |
+
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
|
| 5545 |
+
"peer": true,
|
| 5546 |
+
"dependencies": {
|
| 5547 |
+
"scheduler": "^0.27.0"
|
| 5548 |
+
},
|
| 5549 |
+
"peerDependencies": {
|
| 5550 |
+
"react": "^19.2.0"
|
| 5551 |
+
}
|
| 5552 |
+
},
|
| 5553 |
"node_modules/react-is": {
|
| 5554 |
"version": "18.3.1",
|
| 5555 |
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
|
| 5556 |
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
|
| 5557 |
"dev": true
|
| 5558 |
},
|
| 5559 |
+
"node_modules/react-router": {
|
| 5560 |
+
"version": "7.9.6",
|
| 5561 |
+
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.6.tgz",
|
| 5562 |
+
"integrity": "sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==",
|
| 5563 |
+
"dependencies": {
|
| 5564 |
+
"cookie": "^1.0.1",
|
| 5565 |
+
"set-cookie-parser": "^2.6.0"
|
| 5566 |
+
},
|
| 5567 |
+
"engines": {
|
| 5568 |
+
"node": ">=20.0.0"
|
| 5569 |
+
},
|
| 5570 |
+
"peerDependencies": {
|
| 5571 |
+
"react": ">=18",
|
| 5572 |
+
"react-dom": ">=18"
|
| 5573 |
+
},
|
| 5574 |
+
"peerDependenciesMeta": {
|
| 5575 |
+
"react-dom": {
|
| 5576 |
+
"optional": true
|
| 5577 |
+
}
|
| 5578 |
+
}
|
| 5579 |
+
},
|
| 5580 |
+
"node_modules/react-router-dom": {
|
| 5581 |
+
"version": "7.9.6",
|
| 5582 |
+
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.6.tgz",
|
| 5583 |
+
"integrity": "sha512-2MkC2XSXq6HjGcihnx1s0DBWQETI4mlis4Ux7YTLvP67xnGxCvq+BcCQSO81qQHVUTM1V53tl4iVVaY5sReCOA==",
|
| 5584 |
+
"dependencies": {
|
| 5585 |
+
"react-router": "7.9.6"
|
| 5586 |
+
},
|
| 5587 |
+
"engines": {
|
| 5588 |
+
"node": ">=20.0.0"
|
| 5589 |
+
},
|
| 5590 |
+
"peerDependencies": {
|
| 5591 |
+
"react": ">=18",
|
| 5592 |
+
"react-dom": ">=18"
|
| 5593 |
+
}
|
| 5594 |
+
},
|
| 5595 |
+
"node_modules/react-router/node_modules/cookie": {
|
| 5596 |
+
"version": "1.0.2",
|
| 5597 |
+
"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
|
| 5598 |
+
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
|
| 5599 |
+
"engines": {
|
| 5600 |
+
"node": ">=18"
|
| 5601 |
+
}
|
| 5602 |
+
},
|
| 5603 |
"node_modules/readable-stream": {
|
| 5604 |
"version": "3.6.2",
|
| 5605 |
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
|
|
|
| 5782 |
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
| 5783 |
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
| 5784 |
},
|
| 5785 |
+
"node_modules/scheduler": {
|
| 5786 |
+
"version": "0.27.0",
|
| 5787 |
+
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz",
|
| 5788 |
+
"integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==",
|
| 5789 |
+
"peer": true
|
| 5790 |
+
},
|
| 5791 |
"node_modules/semver": {
|
| 5792 |
"version": "6.3.1",
|
| 5793 |
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
|
|
|
|
| 5832 |
"node": ">= 18"
|
| 5833 |
}
|
| 5834 |
},
|
| 5835 |
+
"node_modules/set-cookie-parser": {
|
| 5836 |
+
"version": "2.7.2",
|
| 5837 |
+
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
|
| 5838 |
+
"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="
|
| 5839 |
+
},
|
| 5840 |
"node_modules/set-function-length": {
|
| 5841 |
"version": "1.2.2",
|
| 5842 |
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
package.json
CHANGED
|
@@ -14,45 +14,51 @@
|
|
| 14 |
"type": "git",
|
| 15 |
"url": "https://huggingface.co/spaces/nexusbert/zurri"
|
| 16 |
},
|
| 17 |
-
"keywords": [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
"author": "",
|
| 19 |
"license": "ISC",
|
| 20 |
"dependencies": {
|
| 21 |
-
"express": "*",
|
| 22 |
-
"typeorm": "*",
|
| 23 |
-
"pg": "*",
|
| 24 |
-
"jsonwebtoken": "*",
|
| 25 |
-
"dotenv": "*",
|
| 26 |
-
"cors": "*",
|
| 27 |
-
"helmet": "*",
|
| 28 |
-
"express-rate-limit": "*",
|
| 29 |
"axios": "*",
|
| 30 |
-
"uuid": "*",
|
| 31 |
-
"reflect-metadata": "*",
|
| 32 |
"bcryptjs": "*",
|
| 33 |
-
"
|
| 34 |
-
"
|
|
|
|
|
|
|
| 35 |
"form-data": "*",
|
| 36 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
"swagger-jsdoc": "*",
|
| 38 |
-
"
|
|
|
|
|
|
|
| 39 |
},
|
| 40 |
"devDependencies": {
|
|
|
|
|
|
|
| 41 |
"@types/express": "*",
|
| 42 |
-
"@types/
|
| 43 |
"@types/jsonwebtoken": "*",
|
| 44 |
-
"@types/cors": "*",
|
| 45 |
-
"@types/uuid": "*",
|
| 46 |
-
"@types/bcryptjs": "*",
|
| 47 |
"@types/multer": "*",
|
| 48 |
-
"@types/
|
| 49 |
-
"typescript": "*",
|
| 50 |
-
"ts-node-dev": "*",
|
| 51 |
-
"jest": "*",
|
| 52 |
-
"ts-jest": "*",
|
| 53 |
-
"supertest": "*",
|
| 54 |
"@types/supertest": "*",
|
|
|
|
| 55 |
"@types/swagger-ui-express": "*",
|
| 56 |
-
"@types/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 57 |
}
|
| 58 |
}
|
|
|
|
| 14 |
"type": "git",
|
| 15 |
"url": "https://huggingface.co/spaces/nexusbert/zurri"
|
| 16 |
},
|
| 17 |
+
"keywords": [
|
| 18 |
+
"ai",
|
| 19 |
+
"agents",
|
| 20 |
+
"marketplace",
|
| 21 |
+
"chat"
|
| 22 |
+
],
|
| 23 |
"author": "",
|
| 24 |
"license": "ISC",
|
| 25 |
"dependencies": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
"axios": "*",
|
|
|
|
|
|
|
| 27 |
"bcryptjs": "*",
|
| 28 |
+
"cors": "*",
|
| 29 |
+
"dotenv": "*",
|
| 30 |
+
"express": "*",
|
| 31 |
+
"express-rate-limit": "*",
|
| 32 |
"form-data": "*",
|
| 33 |
+
"helmet": "*",
|
| 34 |
+
"jsonwebtoken": "*",
|
| 35 |
+
"multer": "*",
|
| 36 |
+
"paystack-node": "*",
|
| 37 |
+
"pg": "*",
|
| 38 |
+
"pinata": "*",
|
| 39 |
+
"react-router-dom": "^7.9.6",
|
| 40 |
+
"reflect-metadata": "*",
|
| 41 |
"swagger-jsdoc": "*",
|
| 42 |
+
"swagger-ui-express": "*",
|
| 43 |
+
"typeorm": "*",
|
| 44 |
+
"uuid": "*"
|
| 45 |
},
|
| 46 |
"devDependencies": {
|
| 47 |
+
"@types/bcryptjs": "*",
|
| 48 |
+
"@types/cors": "*",
|
| 49 |
"@types/express": "*",
|
| 50 |
+
"@types/jest": "*",
|
| 51 |
"@types/jsonwebtoken": "*",
|
|
|
|
|
|
|
|
|
|
| 52 |
"@types/multer": "*",
|
| 53 |
+
"@types/node": "*",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
"@types/supertest": "*",
|
| 55 |
+
"@types/swagger-jsdoc": "*",
|
| 56 |
"@types/swagger-ui-express": "*",
|
| 57 |
+
"@types/uuid": "*",
|
| 58 |
+
"jest": "*",
|
| 59 |
+
"supertest": "*",
|
| 60 |
+
"ts-jest": "*",
|
| 61 |
+
"ts-node-dev": "*",
|
| 62 |
+
"typescript": "*"
|
| 63 |
}
|
| 64 |
}
|
src/scripts/createAdmin.ts
CHANGED
|
@@ -10,8 +10,13 @@ if (fs.existsSync(envPath)) {
|
|
| 10 |
dotenv.config();
|
| 11 |
}
|
| 12 |
|
| 13 |
-
const ADMIN_EMAIL =
|
| 14 |
-
const ADMIN_PASSWORD =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
console.log('π§ Admin Email:', ADMIN_EMAIL);
|
| 17 |
console.log('π Password:', ADMIN_PASSWORD ? 'SET' : 'NOT SET');
|
|
@@ -22,7 +27,82 @@ import { AppDataSource } from '../config/database';
|
|
| 22 |
import { User } from '../entities/User';
|
| 23 |
import bcrypt from 'bcryptjs';
|
| 24 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
async function createAdmin() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
try {
|
| 27 |
console.log('\nπ§ Initializing database connection...');
|
| 28 |
await AppDataSource.initialize();
|
|
@@ -30,43 +110,40 @@ async function createAdmin() {
|
|
| 30 |
|
| 31 |
const userRepository = AppDataSource.getRepository(User);
|
| 32 |
|
| 33 |
-
console.log(`\nπ Looking for user: ${
|
| 34 |
|
| 35 |
-
let user = await userRepository.findOne({ where: { email:
|
| 36 |
|
| 37 |
if (user) {
|
| 38 |
-
console.log('β
User found, updating to admin...');
|
| 39 |
user.isAdmin = true;
|
| 40 |
user.isActive = true;
|
| 41 |
|
| 42 |
-
const
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
user.password = hashedPassword;
|
| 46 |
-
console.log('β
Password updated');
|
| 47 |
-
}
|
| 48 |
|
| 49 |
await userRepository.save(user);
|
| 50 |
-
console.log('β
User updated to admin successfully!');
|
| 51 |
console.log(`\nπ§ Email: ${user.email}`);
|
| 52 |
console.log(`π€ Admin: ${user.isAdmin}`);
|
| 53 |
console.log(`π User ID: ${user.id}`);
|
| 54 |
} else {
|
| 55 |
-
console.log('β οΈ User not found, creating new admin user...');
|
| 56 |
|
| 57 |
-
const hashedPassword = await bcrypt.hash(
|
| 58 |
|
| 59 |
user = userRepository.create({
|
| 60 |
-
email:
|
| 61 |
password: hashedPassword,
|
| 62 |
-
name: 'Admin User',
|
| 63 |
isAdmin: true,
|
| 64 |
isActive: true,
|
| 65 |
isCreator: false,
|
| 66 |
});
|
| 67 |
|
| 68 |
await userRepository.save(user);
|
| 69 |
-
console.log('β
|
| 70 |
console.log(`\nπ§ Email: ${user.email}`);
|
| 71 |
console.log(`π€ Admin: ${user.isAdmin}`);
|
| 72 |
console.log(`π User ID: ${user.id}`);
|
|
@@ -85,4 +162,7 @@ async function createAdmin() {
|
|
| 85 |
}
|
| 86 |
}
|
| 87 |
|
| 88 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
dotenv.config();
|
| 11 |
}
|
| 12 |
|
| 13 |
+
const ADMIN_EMAIL = process.env.ADMIN_EMAIL?.trim();
|
| 14 |
+
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD?.trim();
|
| 15 |
+
|
| 16 |
+
if (!ADMIN_EMAIL || !ADMIN_PASSWORD) {
|
| 17 |
+
console.error('β ADMIN_EMAIL and ADMIN_PASSWORD must be set in environment variables');
|
| 18 |
+
process.exit(1);
|
| 19 |
+
}
|
| 20 |
|
| 21 |
console.log('π§ Admin Email:', ADMIN_EMAIL);
|
| 22 |
console.log('π Password:', ADMIN_PASSWORD ? 'SET' : 'NOT SET');
|
|
|
|
| 27 |
import { User } from '../entities/User';
|
| 28 |
import bcrypt from 'bcryptjs';
|
| 29 |
|
| 30 |
+
/**
|
| 31 |
+
* Initialize permanent admin user from environment variables
|
| 32 |
+
* This ensures the admin user always exists and maintains admin status
|
| 33 |
+
*/
|
| 34 |
+
export async function initializeAdmin(): Promise<void> {
|
| 35 |
+
const adminEmail = process.env.ADMIN_EMAIL?.trim();
|
| 36 |
+
const adminPassword = process.env.ADMIN_PASSWORD?.trim();
|
| 37 |
+
|
| 38 |
+
if (!adminEmail || !adminPassword) {
|
| 39 |
+
console.log('β οΈ ADMIN_EMAIL and ADMIN_PASSWORD not set - skipping admin initialization');
|
| 40 |
+
return;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
try {
|
| 44 |
+
// Check if database is already initialized
|
| 45 |
+
if (!AppDataSource.isInitialized) {
|
| 46 |
+
await AppDataSource.initialize();
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
const userRepository = AppDataSource.getRepository(User);
|
| 50 |
+
|
| 51 |
+
let user = await userRepository.findOne({ where: { email: adminEmail.toLowerCase() } });
|
| 52 |
+
|
| 53 |
+
if (user) {
|
| 54 |
+
// User exists - ensure they are admin and update password if needed
|
| 55 |
+
const needsUpdate = !user.isAdmin || !user.isActive;
|
| 56 |
+
|
| 57 |
+
if (needsUpdate) {
|
| 58 |
+
user.isAdmin = true;
|
| 59 |
+
user.isActive = true;
|
| 60 |
+
console.log(`β
Updated user ${adminEmail} to admin status`);
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
// Always update password to match env (ensures it stays in sync)
|
| 64 |
+
const hashedPassword = await bcrypt.hash(adminPassword, 12);
|
| 65 |
+
user.password = hashedPassword;
|
| 66 |
+
|
| 67 |
+
await userRepository.save(user);
|
| 68 |
+
console.log(`β
Permanent admin user maintained: ${adminEmail}`);
|
| 69 |
+
} else {
|
| 70 |
+
// Create new admin user
|
| 71 |
+
const hashedPassword = await bcrypt.hash(adminPassword, 12);
|
| 72 |
+
|
| 73 |
+
user = userRepository.create({
|
| 74 |
+
email: adminEmail.toLowerCase(),
|
| 75 |
+
password: hashedPassword,
|
| 76 |
+
name: process.env.ADMIN_NAME || 'Admin User',
|
| 77 |
+
isAdmin: true,
|
| 78 |
+
isActive: true,
|
| 79 |
+
isCreator: false,
|
| 80 |
+
});
|
| 81 |
+
|
| 82 |
+
await userRepository.save(user);
|
| 83 |
+
console.log(`β
Permanent admin user created: ${adminEmail}`);
|
| 84 |
+
}
|
| 85 |
+
} catch (error) {
|
| 86 |
+
console.error('β Error initializing admin:', error);
|
| 87 |
+
if (error instanceof Error) {
|
| 88 |
+
console.error('Error message:', error.message);
|
| 89 |
+
}
|
| 90 |
+
// Don't throw - allow app to continue even if admin init fails
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
/**
|
| 95 |
+
* Standalone script to create/update admin user
|
| 96 |
+
*/
|
| 97 |
async function createAdmin() {
|
| 98 |
+
const adminEmail = ADMIN_EMAIL;
|
| 99 |
+
const adminPassword = ADMIN_PASSWORD;
|
| 100 |
+
|
| 101 |
+
if (!adminEmail || !adminPassword) {
|
| 102 |
+
console.error('β ADMIN_EMAIL and ADMIN_PASSWORD must be set in environment variables');
|
| 103 |
+
process.exit(1);
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
try {
|
| 107 |
console.log('\nπ§ Initializing database connection...');
|
| 108 |
await AppDataSource.initialize();
|
|
|
|
| 110 |
|
| 111 |
const userRepository = AppDataSource.getRepository(User);
|
| 112 |
|
| 113 |
+
console.log(`\nπ Looking for user: ${adminEmail}`);
|
| 114 |
|
| 115 |
+
let user = await userRepository.findOne({ where: { email: adminEmail.toLowerCase() } });
|
| 116 |
|
| 117 |
if (user) {
|
| 118 |
+
console.log('β
User found, updating to permanent admin...');
|
| 119 |
user.isAdmin = true;
|
| 120 |
user.isActive = true;
|
| 121 |
|
| 122 |
+
const hashedPassword = await bcrypt.hash(adminPassword, 12);
|
| 123 |
+
user.password = hashedPassword;
|
| 124 |
+
console.log('β
Password updated');
|
|
|
|
|
|
|
|
|
|
| 125 |
|
| 126 |
await userRepository.save(user);
|
| 127 |
+
console.log('β
User updated to permanent admin successfully!');
|
| 128 |
console.log(`\nπ§ Email: ${user.email}`);
|
| 129 |
console.log(`π€ Admin: ${user.isAdmin}`);
|
| 130 |
console.log(`π User ID: ${user.id}`);
|
| 131 |
} else {
|
| 132 |
+
console.log('β οΈ User not found, creating new permanent admin user...');
|
| 133 |
|
| 134 |
+
const hashedPassword = await bcrypt.hash(adminPassword, 12);
|
| 135 |
|
| 136 |
user = userRepository.create({
|
| 137 |
+
email: adminEmail.toLowerCase(),
|
| 138 |
password: hashedPassword,
|
| 139 |
+
name: process.env.ADMIN_NAME || 'Admin User',
|
| 140 |
isAdmin: true,
|
| 141 |
isActive: true,
|
| 142 |
isCreator: false,
|
| 143 |
});
|
| 144 |
|
| 145 |
await userRepository.save(user);
|
| 146 |
+
console.log('β
Permanent admin user created successfully!');
|
| 147 |
console.log(`\nπ§ Email: ${user.email}`);
|
| 148 |
console.log(`π€ Admin: ${user.isAdmin}`);
|
| 149 |
console.log(`π User ID: ${user.id}`);
|
|
|
|
| 162 |
}
|
| 163 |
}
|
| 164 |
|
| 165 |
+
// Only run if this file is executed directly (not imported)
|
| 166 |
+
if (require.main === module) {
|
| 167 |
+
createAdmin();
|
| 168 |
+
}
|
src/server.ts
CHANGED
|
@@ -21,6 +21,7 @@ if (!isHuggingFaceSpace && !isProduction) {
|
|
| 21 |
import 'reflect-metadata';
|
| 22 |
import { AppDataSource } from './config/database';
|
| 23 |
import app from './app';
|
|
|
|
| 24 |
|
| 25 |
const PORT = parseInt(process.env.PORT || process.env.SPACE_PORT || '7860', 10);
|
| 26 |
|
|
@@ -51,6 +52,9 @@ AppDataSource.initialize()
|
|
| 51 |
}
|
| 52 |
}
|
| 53 |
|
|
|
|
|
|
|
|
|
|
| 54 |
app.listen(PORT, '0.0.0.0', () => {
|
| 55 |
console.log(`π Server running on port ${PORT}`);
|
| 56 |
console.log(`π Server accessible at http://0.0.0.0:${PORT}`);
|
|
|
|
| 21 |
import 'reflect-metadata';
|
| 22 |
import { AppDataSource } from './config/database';
|
| 23 |
import app from './app';
|
| 24 |
+
import { initializeAdmin } from './scripts/createAdmin';
|
| 25 |
|
| 26 |
const PORT = parseInt(process.env.PORT || process.env.SPACE_PORT || '7860', 10);
|
| 27 |
|
|
|
|
| 52 |
}
|
| 53 |
}
|
| 54 |
|
| 55 |
+
// Initialize permanent admin user from environment variables
|
| 56 |
+
await initializeAdmin();
|
| 57 |
+
|
| 58 |
app.listen(PORT, '0.0.0.0', () => {
|
| 59 |
console.log(`π Server running on port ${PORT}`);
|
| 60 |
console.log(`π Server accessible at http://0.0.0.0:${PORT}`);
|
zurri-mock-frontend
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
Subproject commit
|
|
|
|
| 1 |
+
Subproject commit 05aab1df678d680e947fa3e24b05c8fd35266c7b
|
zurriwebsite
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
Subproject commit 4013f080c954f64ecc95a16ae6477460eb8b0762
|