lots...
This commit is contained in:
		
							
								
								
									
										49
									
								
								models/sql/authtoken.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								models/sql/authtoken.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| module.exports = (sequelize, DataTypes, Model) => { | ||||
|   class AuthToken extends Model { | ||||
|     /** | ||||
|      * Helper method for defining associations. | ||||
|      * This method is not a part of Sequelize lifecycle. | ||||
|      * The `models/index` file will call this method automatically. | ||||
|      */ | ||||
|     static associate(models) { | ||||
|     } | ||||
|  | ||||
|     check(){ | ||||
|       // check expires_on date | ||||
|       return this.is_valid; | ||||
|     } | ||||
|   } | ||||
|   AuthToken.init({ | ||||
|     token:{ | ||||
|       type: DataTypes.UUID, | ||||
|       defaultValue: DataTypes.UUIDV4, | ||||
|       allowNull: false, | ||||
|       primaryKey: true | ||||
|     }, | ||||
|     expires_on: { | ||||
|       type: DataTypes.DATE, | ||||
|       allowNull: true, | ||||
|       validate:{ | ||||
|         isDate:true | ||||
|       } | ||||
|     }, | ||||
|     username: { | ||||
|       type: DataTypes.STRING, | ||||
|       ldapModel: 'User', | ||||
|       allowNull: false, | ||||
|       validate:{ | ||||
|         notNull: true, | ||||
|       }, | ||||
|     }, | ||||
|     is_valid: { | ||||
|       type: DataTypes.BOOLEAN, | ||||
|       defaultValue: true | ||||
|     } | ||||
|   }, { | ||||
|     sequelize, | ||||
|     modelName: 'AuthToken', | ||||
|   }); | ||||
|   return AuthToken; | ||||
| }; | ||||
							
								
								
									
										3
									
								
								models/sql/config/config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								models/sql/config/config.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| const conf = require('../../../conf'); | ||||
|  | ||||
| module.exports = conf.sql; | ||||
							
								
								
									
										109
									
								
								models/sql/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								models/sql/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,109 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const fs = require('fs'); | ||||
| const path = require('path'); | ||||
| const { Sequelize, Utils } = require('sequelize'); | ||||
| const process = require('process'); | ||||
| const basename = path.basename(__filename); | ||||
| const env = process.env.NODE_ENV || 'development'; | ||||
| const config = require(__dirname + '/config/config.js'); | ||||
| const db = {}; | ||||
|  | ||||
| let sequelize; | ||||
|  | ||||
| // Connect sequelize models to LDAP models | ||||
| const ldapModels = require('../ldap'); | ||||
|  | ||||
| function getFieldWithLdap(attributes){ | ||||
|   let out = []; | ||||
|  | ||||
|   for (const [attribute, options] of Object.entries(attributes)) { | ||||
|     if(options.ldapModel) out.push(attribute) | ||||
|   } | ||||
|    | ||||
|   return out; | ||||
| } | ||||
|  | ||||
| const sequilze_conf = { | ||||
|   define: { | ||||
|     hooks: { | ||||
|       async afterValidate(instance) { | ||||
|         let hasError = false; | ||||
|         function itemError(key, validator, message){ | ||||
|           let error = new Sequelize.ValidationErrorItem(message); | ||||
|           error.type = 'Validation error'; | ||||
|           error.path = key; | ||||
|           error.origin = 'FUNCTION'; | ||||
|           error.instance = instance; | ||||
|           error.validatorKey = 'validator'; | ||||
|           error.validatorName = 'validator'; | ||||
|           error.validatorArgs = []; | ||||
|           error.original = []; | ||||
|  | ||||
|           throw new Sequelize.ValidationError(null, [error]); | ||||
|         } | ||||
|  | ||||
|         for(let attribute of getFieldWithLdap(this.getAttributes())){ | ||||
|           let externalModel = ldapModels[this.getAttributes()[attribute].ldapModel]; | ||||
|          | ||||
|           if(!externalModel) itemError(attribute, 'modelExists', `LDAP model ${this.getAttributes()[attribute].ldapModel} not found.`); | ||||
|  | ||||
|           if(!hasError && !(await externalModel.exists(instance[attribute])) ) itemError(attribute, 'foreignKey', `LDAP model has no object ${instance[attribute]}`); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| class _Model extends Sequelize.Model{ | ||||
|   constructor(...args){ | ||||
|     super(...args) | ||||
|     let hasLdap = getFieldWithLdap(this.constructor.getAttributes()) | ||||
|     for(let attribute of hasLdap){ | ||||
|       let externalModelName = this.constructor.getAttributes()[attribute].ldapModel; | ||||
|       this[`get${externalModelName}`] = async function(){ | ||||
|         return await ldapModels[externalModelName].get(this[attribute]); | ||||
|       }  | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Backward compatible with my LDAP and Redis models. | ||||
|   // I will update the LDAP and Redis stuff to have method interfaces inline with sequilze | ||||
|   static async get(token){ | ||||
|     return await this.findByPk(token); | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| if (config.use_env_variable) { | ||||
|   sequelize = new Sequelize(process.env[config.use_env_variable], config); | ||||
| } else { | ||||
|   sequelize = new Sequelize(config.database, config.username, config.password, {...config, ...sequilze_conf}); | ||||
| } | ||||
|  | ||||
|  | ||||
| fs | ||||
|   .readdirSync(__dirname) | ||||
|   .filter(file => { | ||||
|     return ( | ||||
|       file.indexOf('.') !== 0 && | ||||
|       file !== basename && | ||||
|       file.slice(-3) === '.js' && | ||||
|       file.indexOf('.test.js') === -1 | ||||
|     ); | ||||
|   }) | ||||
|   .forEach(file => { | ||||
|     const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes, _Model); | ||||
|     db[model.name] = model; | ||||
|   }); | ||||
|  | ||||
| Object.keys(db).forEach(modelName => { | ||||
|   if (db[modelName].associate) { | ||||
|     db[modelName].associate(db); | ||||
|   } | ||||
| }); | ||||
|  | ||||
| db.sequelize = sequelize; | ||||
| db.Sequelize = Sequelize; | ||||
|  | ||||
| module.exports = db; | ||||
							
								
								
									
										38
									
								
								models/sql/migrations/20231230031017-create-auth-token.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								models/sql/migrations/20231230031017-create-auth-token.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| 'use strict'; | ||||
| /** @type {import('sequelize-cli').Migration} */ | ||||
| module.exports = { | ||||
|   async up(queryInterface, Sequelize) { | ||||
|     await queryInterface.createTable('AuthTokens', { | ||||
|       token: { | ||||
|         type: Sequelize.UUID, | ||||
|         defaultValue: Sequelize.UUIDV4, | ||||
|         allowNull: false, | ||||
|         primaryKey: true | ||||
|       }, | ||||
|       is_valid: { | ||||
|         type: Sequelize.BOOLEAN, | ||||
|         defaultValue: true, | ||||
|         allowNull: false, | ||||
|       }, | ||||
|       username: { | ||||
|         type: Sequelize.STRING, | ||||
|         allowNull: false, | ||||
|       }, | ||||
|       expires_on: { | ||||
|         allowNull: true, | ||||
|         type: Sequelize.DATE | ||||
|       }, | ||||
|       createdAt: { | ||||
|         allowNull: false, | ||||
|         type: Sequelize.DATE | ||||
|       }, | ||||
|       updatedAt: { | ||||
|         allowNull: false, | ||||
|         type: Sequelize.DATE | ||||
|       } | ||||
|     }); | ||||
|   }, | ||||
|   async down(queryInterface, Sequelize) { | ||||
|     await queryInterface.dropTable('AuthTokens'); | ||||
|   } | ||||
| }; | ||||
							
								
								
									
										63
									
								
								models/sql/migrations/20240101174644-create-torrent.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								models/sql/migrations/20240101174644-create-torrent.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| 'use strict'; | ||||
| /** @type {import('sequelize-cli').Migration} */ | ||||
| module.exports = { | ||||
|   async up(queryInterface, Sequelize) { | ||||
|     await queryInterface.createTable('Torrents', { | ||||
|       id: { | ||||
|         allowNull: false, | ||||
|         autoIncrement: true, | ||||
|         primaryKey: true, | ||||
|         type: Sequelize.INTEGER | ||||
|       }, | ||||
|       torrent_id: { | ||||
|         type: Sequelize.STRING | ||||
|       }, | ||||
|       hashString: { | ||||
|         type: Sequelize.STRING | ||||
|       }, | ||||
|       magnetLink: { | ||||
|         type: Sequelize.STRING | ||||
|       }, | ||||
|       name: { | ||||
|         type: Sequelize.STRING | ||||
|       }, | ||||
|       status: { | ||||
|         type: Sequelize.NUMBER | ||||
|       }, | ||||
|       isPrivate: { | ||||
|         type: Sequelize.BOOLEAN, | ||||
|         defaultValue: false, | ||||
|         allowNull: false, | ||||
|       }, | ||||
|       percentDone: { | ||||
|         type: Sequelize.FLOAT | ||||
|       }, | ||||
|       errorString: { | ||||
|         type: Sequelize.STRING, | ||||
|         allowNull: true | ||||
|       }, | ||||
|       downloadDir: { | ||||
|         type: Sequelize.STRING, | ||||
|         allowNull: true | ||||
|       }, | ||||
|       sizeWhenDone: { | ||||
|         type: Sequelize.NUMBER, | ||||
|         allowNull: true | ||||
|       }, | ||||
|       added_by: { | ||||
|         type: Sequelize.STRING | ||||
|       }, | ||||
|       createdAt: { | ||||
|         allowNull: false, | ||||
|         type: Sequelize.DATE | ||||
|       }, | ||||
|       updatedAt: { | ||||
|         allowNull: false, | ||||
|         type: Sequelize.DATE | ||||
|       } | ||||
|     }); | ||||
|   }, | ||||
|   async down(queryInterface, Sequelize) { | ||||
|     await queryInterface.dropTable('Torrents'); | ||||
|   } | ||||
| }; | ||||
							
								
								
									
										126
									
								
								models/sql/torrent.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								models/sql/torrent.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,126 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const Transmission = require('transmission-promise'); | ||||
| const conf = require('>/conf'); | ||||
|  | ||||
| const tr_client = new Transmission(conf.transmission) | ||||
|  | ||||
| const statusMap = [ | ||||
|   'STOPPED',        | ||||
|   'CHECK_WAIT',     | ||||
|   'CHECK',          | ||||
|   'DOWNLOAD_WAIT',  | ||||
|   'DOWNLOAD',       | ||||
|   'SEED_WAIT',      | ||||
|   'SEED',           | ||||
|   'ISOLATED',       | ||||
| ]; | ||||
|  | ||||
| module.exports = (sequelize, DataTypes, Model) => { | ||||
|   class Torrent extends Model { | ||||
|     /** | ||||
|      * Helper method for defining associations. | ||||
|      * This method is not a part of Sequelize lifecycle. | ||||
|      * The `models/index` file will call this method automatically. | ||||
|      */ | ||||
|     static associate(models) { | ||||
|       // define association here | ||||
|     } | ||||
|  | ||||
|     static trClient = tr_client; | ||||
|  | ||||
|     static async create(data, ...args){ | ||||
|       try{ | ||||
|  | ||||
|         // let instance = this.build(data); | ||||
|         // console.log('instance', instance) | ||||
|         await this.build(data).validate(); | ||||
|         // console.log('validate', val); | ||||
|  | ||||
|         let res = await tr_client.addUrl(data.magnetLink); | ||||
|  | ||||
|         return await super.create({ | ||||
|           magnetLink: data.magnetLink, | ||||
|           torrent_id: res.id, | ||||
|           hashString: res.hashString, | ||||
|           name: res.name, | ||||
|           added_by: data.added_by, | ||||
|           status: 0, | ||||
|           percentDone: 0, | ||||
|         }, args); | ||||
|       }catch (error){ | ||||
|         // console.log('Torrent create error', error); | ||||
|         throw error; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     async getTorrentData(noUpdate){ | ||||
|       try{ | ||||
|         let res = ( await tr_client.get(Number(this.torrent_id), [ | ||||
|           "eta", "percentDone", "status", "rateDownload", | ||||
|           "errorString", "hashString", 'name', | ||||
|           'downloadDir', | ||||
|           'files', //array of files | ||||
|           'filesStats', // array of files with status | ||||
|           'isFinished', | ||||
|           'isStalled', | ||||
|           'peers', | ||||
|           'peersConnected', // array of peers, | ||||
|           'sizeWhenDone', | ||||
|         ]) ).torrents[0]; | ||||
|  | ||||
|         await this.update(res); | ||||
|         if(noUpdate) await this.save(); | ||||
|         return {...res, ...this.dataValues}; | ||||
|       }catch(error){ | ||||
|         console.error(`Torrent ${this.id} getTorrentData error`, error); | ||||
|         throw error; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   Torrent.init({ | ||||
|     torrent_id: DataTypes.STRING, | ||||
|     magnetLink: { | ||||
|       type: DataTypes.STRING, | ||||
|       allowNull: false, | ||||
|       validate:{ | ||||
|         notNull: true, | ||||
|         notEmpty: true, | ||||
|       }, | ||||
|     }, | ||||
|     isPrivate: { | ||||
|       type: DataTypes.BOOLEAN, | ||||
|       defaultValue: false, | ||||
|     }, | ||||
|     hashString: DataTypes.STRING, | ||||
|     name: DataTypes.STRING, | ||||
|     added_by: { | ||||
|       type: DataTypes.STRING, | ||||
|       ldapModel: 'User', | ||||
|       allowNull: false, | ||||
|       validate:{ | ||||
|         notNull: true, | ||||
|         notEmpty: true, | ||||
|       }, | ||||
|     }, | ||||
|     status: DataTypes.NUMBER, | ||||
|     percentDone: DataTypes.FLOAT, | ||||
|     downloadDir: { | ||||
|       type: DataTypes.STRING, | ||||
|       allowNull: true, | ||||
|     }, | ||||
|     errorString: { | ||||
|       type: DataTypes.STRING, | ||||
|       allowNull: true, | ||||
|     }, | ||||
|     sizeWhenDone: { | ||||
|       type: DataTypes.NUMBER, | ||||
|       allowNull: true, | ||||
|     }, | ||||
|   }, { | ||||
|     sequelize, | ||||
|     modelName: 'Torrent', | ||||
|     logging: false, | ||||
|   }); | ||||
|   return Torrent; | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user