Commit f64e6e2b authored by nano's avatar nano

init

parent af2efa57
# Created by .ignore support plugin (hsz.mobi)
.env
node_modules/
/.idea/
*.js
*.js.map
node-debug.log
/mongodb_config.json
.DS_Store
/npm-debug.log
*.js
*.map
\ No newline at end of file
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="PROJECT" charset="UTF-8" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<includedPredefinedLibrary name="ECMAScript 6" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/mycard-console-backend.iml" filepath="$PROJECT_DIR$/.idea/mycard-console-backend.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="TypeScriptCompiler">
<option name="isCompilerEnabled" value="true" />
<option name="useConfig" value="true" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
This diff is collapsed.
FROM node
FROM node:alpine
RUN apt-get update
RUN apt-get install -y gdebi-core
RUN wget https://repo.varnish-cache.org/pkg/5.0.0/varnish_5.0.0-1_amd64.deb
RUN gdebi -n varnish_5.0.0-1_amd64.deb
RUN rm varnish_5.0.0-1_amd64.deb
MAINTAINER nanoo
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json /usr/src/app/
COPY npm-shrinkwrap.json /usr/src/app/
RUN npm install
COPY . /usr/src/app
CMD [ "./entrypoint.sh" ]
#COPY package.json /usr/src/app
#RUN npm install
#COPY . /usr/src/app
EXPOSE 8080
CMD ["npm","start"]
\ No newline at end of file
This diff is collapsed.
/**
* Created by weijian on 2016/12/30.
*/
export function field(target: any, propertyKey: string): any {
return {
get (): any {
return this.get(propertyKey);
},
set (value: any): void {
this.set(propertyKey, value);
}
};
}
/**
* Created by weijian on 2016/12/29.
*/
import {MongoClient, Collection, InsertOneWriteOpResult, DeleteWriteOpResultObject} from 'mongodb';
import pluralize = require('pluralize');
interface Config {
dbSettings: {
connectionString: string;
};
}
const config: Config = require('./../mongodb_config.json');
const promise = MongoClient.connect(config.dbSettings.connectionString);
export class Model {
static get dbName(): string {
return pluralize(this.name.toLowerCase());
}
static async getCollection(): Promise<Collection> {
let db = await promise;
return db.collection(this.dbName);
}
static async deleteOne(filter: Object): Promise<DeleteWriteOpResultObject> {
let collection = await this.getCollection();
return await collection.deleteOne(filter);
}
static async findOne(query: Object): Promise<any|null> {
let collection = await this.getCollection();
let result = await collection.find(query).limit(1).next();
console.log(result, query,this.dbName);
if (result) {
return new this(result);
} else {
return null;
}
}
constructor(o: any) {
for (let [key, value] of Object.entries(o)) {
this[key] = value;
}
}
async save(): Promise<InsertOneWriteOpResult> {
let db = await promise;
return db.collection(Model.dbName).insertOne(this);
}
}
import {STATUS_CODES} from 'http';
/**
* Created by weijian on 2016/12/29.
*/
export class KoaError extends Error {
constructor(msg: string, public status: number) {
super(msg);
}
}
export class NotFound extends KoaError {
constructor(msg = STATUS_CODES[404]) {
super(msg, 404);
}
}
export class BadRequest extends KoaError {
constructor(msg = STATUS_CODES[400]) {
super(msg, 400);
}
}
export class InternalError extends KoaError {
constructor(public error: Error) {
super(STATUS_CODES[500], 500);
}
}
import {Db} from 'mongodb';
export async function up(db: Db, next: Function) {
await db.collection('apps').createIndex('id', {unique: true});
next();
}
export async function down(db: Db, next: Function) {
await db.dropCollection('apps');
next();
}
import 'reflect-metadata';
import * as Mongorito from 'mongorito';
import Model = Mongorito.Model;
import {field} from '../db/decorators';
import {ModelExistsError} from './errors';
import {File} from './package'
/**
* Created by weijian on 2016/12/28.
*/
interface I18n<T> {
[locale: string]: T;
}
interface Platform<T> {
[platform: string]: T;
}
interface Package{
id: string;
name: string;
platforms: Platform<string[]>;
locales: I18n<string[]>;
files: File[];
}
export class App extends Model {
@field
id: string;
@field
name?: I18n<string>;
@field
description?: I18n<string>
@field
developers?: I18n<[{ name: string, url: string }]>
@field
publishers?: I18n<[{ name: string, url: string }]>
@field
released_at?: string;
@field
category?: string;
@field
parent?: string;
@field
tag?: string[];
@field
dependencies?: Platform<string[]>;
@field
references?: Platform<string[]>;
@field
homepage?: string;
@field
locales?: string[];
@field
actions?: Platform<{[key: string]: {execuate: string, args: string[], env: {[key: string]: string}}}>;
@field
files?: {[key: string]: { sync: boolean}}
@field
version?: Platform<string>;
@field
news?: I18n<{title: string, url: string, image: string}[]>;
@field
conference?: string;
@field
data?: any;
@field
icon?: string;
@field
cover?: string;
@field
background?: string;
@field
packages?: Package[];
async checkExists() {
let app = await App.findOne({id: this.id});
if (app) {
throw new ModelExistsError(`App ${this.id} exists`);
}
}
configure() {
this.before('create', this.checkExists);
}
}
/**
* Created by zh99998 on 2017/1/4.
*/
export interface I18n<T> {
[locale: string]: T;
}
class App {
id: string;
name: I18n<string>;
description: I18n<string> = {};
parent?: string;
locales: string[] = [];
news: I18n<{title: string, url: string, image: string}[]> = {};
conference?: string;
data: any;
icon = 'http://www.immersion-3d.com/wp-content/uploads/2015/12/image-placeholder-500x500.jpg';
created_at: Date;
status = '已发布';
// TODO: 实现进 Model 里
constructor(o: any) {
for (let [key, value] of Object.entries(o)) {
this[key] = value;
}
this.created_at = new Date(o.created_at);
}
}
export default App;
import {KoaError} from '../koa/errors';
/**
* Created by weijian on 2017/1/4.
*/
export abstract class ModelError extends KoaError {
abstract errCode: string;
constructor(msg: string, status: number) {
super(msg, status);
}
}
export class ModelExistsError extends ModelError {
errCode: string = 'ERROR_MODULE_EXISTS';
constructor(msg: string) {
super(msg, 400);
}
}
export class ModelInvalidError extends ModelError {
errCode: string = 'ERROR_MODEL_INVALID';
constructor(msg: string) {
super(msg, 400);
}
}
/**
* Created by weijian on 2016/12/29.
*/
import {Model} from 'mongorito';
import {field} from '../db/decorators';
type Locale = 'zh-CN' | 'en-US' | 'ja-JP'
type Platform = 'win32' | 'linux' | 'darwin'
export interface Action {
execute: string;
args: string[];
env: {};
open?: string;
}
export interface File {
path: string;
size: number;
hash: string;
}
export class Package extends Model {
@field
id: string;
@field
name: string;
@field
appId: string;
@field
version: string;
@field
locales: Locale[];
@field
platforms: Platform[];
@field
files: File[];
static async findAllByApp(appId: string) {
return await Package.find({appId: appId});
}
}
{
"dbSettings": {
"connectionString": "mongodb://wudizhanche.mycard.moe:27017/mycard"
}
}
\ No newline at end of file
{
"name": "mycard-console",
"version": "1.0.0",
"private": true,
"name": "application-name",
"version": "0.0.1",
"scripts": {
"prestart": "tsc",
"start": "node server.js",
"server": "node server.js",
"tsc": "tsc",
"lint": "tslint -e ./node_modules/** ./**/*.ts -t verbose",
"migrate": "tsc && mongo-migrate --runMongoMigrate --config mongodb_config.json --dbPropName dbSettings"
"server": "node server.js"
},
"dependencies": {
"@types/bluebird": "^3.5.0",
"@types/uuid": "^2.0.29",
"aliyun-oss-upload-stream": "^1.3.0",
"aliyun-sdk": "^1.9.22",
"async-busboy": "^0.3.4",
"bluebird": "^3.5.0",
"clone": "^2.1.0",
"core-js": "^2.4.1",
"hammerjs": "^2.0.8",
"dot-env": "^0.0.1",
"dotenv": "^4.0.0",
"inversify": "^3.3.0",
"iridium": "^7.1.6",
"is-zip": "^1.0.0",
"koa": "^2.0.0",
"koa-bodyparser": "^3.2.0",
"koa-log4": "^2.1.0",
"koa-router": "^7.0.1",
"mime": "^1.3.4",
"mongodb": "^2.2.16",
"mongodb-migrate": "^2.0.1",
"mongorito": "^2.2.0",
"nodemon": "^1.11.0",
"random": "^1.0.0-beta-1",
"react": "^15.4.2",
"react-intl": "^2.2.3",
"reflect-metadata": "^0.1.9",
"mongoose": "^4.9.4",
"mongoose-timestamp": "^0.6.0",
"mongoose-unique-validator": "^1.0.4",
"tmp": "0.0.31",
"typed-promisify": "^0.4.0",
"uuid": "^3.0.1",
"zone.js": "^0.7.4"
"uuid": "^3.0.1"
},
"devDependencies": {
"@types/clone": "^0.1.30",
"@types/hammerjs": "^2.0.34",
"@types/bluebird": "^3.5.0",
"@types/koa": "^2.0.37",
"@types/koa-bodyparser": "^3.0.22",
"@types/koa-router": "^7.0.21",
......@@ -49,8 +37,10 @@
"@types/node": "^6.0.55",
"@types/pluralize": "0.0.27",
"@types/tmp": "0.0.32",
"@types/uuid": "^2.0.29",
"concurrently": "^3.1.0",
"lite-server": "^2.2.2",
"nodemon": "^1.11.0",
"tslint": "^3.15.1",
"typescript": "^2.1.4"
}
......
/**
* Created by weijian on 2017/1/6.
*/
const queue = [];
while(true){
}
/**
* Created by weijian on 2016/12/28.
*/
import Router = require('koa-router');
import {NotFound, InternalError} from '../koa/errors';
import {App} from '../models/app';
import {Package} from '../models/Package'
import {ModelError, ModelInvalidError} from '../models/errors';
const router = new Router();
router.get('/apps', async(ctx, next) => {
let apps: App[]|null = await App.all();
apps = await Promise.all(apps.map(async app => {
if(app.packages && app.packages.length > 0) {
app.packages = await Promise.all(app.packages.map(async id => {
return await Package.findOne({id})
}))
}
return app
}))
ctx.body = apps
});
router.get('/apps/:id', async(ctx, next) => {
let app = await App.findOne({id: ctx.params.id});
if (app) {
ctx.body = app;
} else {
throw new NotFound(`App ${ctx.params.id} Not Found`);
}
});
router.post('/apps/:id', async(ctx, next) => {
if (!ctx.request.body.id || ctx.params.id !== ctx.request.body.id) {
throw new ModelInvalidError('App id not same');
}
let app = new App(ctx.request.body);
try {
ctx.body = await app.save();
} catch (e) {
if (e instanceof ModelError) {
throw e;
} else {
throw new InternalError(e);
}
}
});
router.patch('/apps/:id', async(ctx, next) => {
let app: App|null = await App.findOne({id: ctx.params.id});
if (!app) {
throw new NotFound(`App ${ctx.params.id} Not Found`);
}
if (!ctx.request.body.id || ctx.request.body.id !== app.id) {
throw new ModelInvalidError('Can not change AppID');
}
try {
if(ctx.request.body.packages.length > 0) {
ctx.request.body.packages = await Promise.all(ctx.request.body.packages.map(async _p=> {
const p: Package|null = await Package.findOne({ id: _p.id })
if(p) {
Object.assign(p, _p)
await p.save()
return p.id
}
const newP = new Package(_p)
await newP.save()
return newP.id
}))
}
Object.assign(app, ctx.request.body);
ctx.body = await app.save();
} catch (error) {
ctx.throw(403, error)
}
});
router.delete('/apps/:id', async(ctx, next) => {
let result = await App.remove({id: ctx.params.id});
if (!result.result.n) {
throw new NotFound(`App ${ctx.params.id} Not Found`);
}
ctx.body = result.result;
});
export default router;
import Router = require('koa-router');
const router = new Router();
/* GET home page. */
router.get('/', (ctx, next) => {
ctx.body = 'Hello World';
});
export default router;
/**
* Created by weijian on 2016/12/29.
*/
import Router = require('koa-router');
import {NotFound} from '../koa/errors';
import {Package} from '../models/package';
import {ModelInvalidError} from '../models/errors';
import * as tmp from 'tmp';
import {ChildProcess} from 'child_process';
import fs = require('fs');
import http = require('http');
import isZip = require('is-zip');
import path = require('path');
import child_process = require('child_process');
const router = new Router();
interface Option {
dir?: string;
}
class Archive {
constructor(public tarPath = 'tar', public unzipPath = 'unzip') {
}
async extract(options?: Option) {
}
private async isZip(file: string): Promise<boolean > {
return new Promise<boolean>((resolve, reject) => {
fs.readFile(file, (err, data) => {
if (err) {
reject(err);
} else {
resolve(isZip(data));
}
});
});
}
async decompress(file: string, option?: Option) {
let dir = '.';
if (option) {
if (option.dir) {
dir = option.dir;
}
}
await new Promise(async(resolve, reject) => {
let process: ChildProcess;
if (await this.isZip(file)) {
// TODO zip解压
process = child_process.spawn(this.unzipPath);
} else {
process = child_process.spawn(this.tarPath, ['xvf', file, '-c', dir]);
}
process.on('exit', (code, signal) => {
if (code !== 0) {
reject(`tar exited by accident, code ${code}`);
} else {
resolve();
}
});
});
}
}
router.get('/packages/all/:appId', async(ctx, next) => {
let appId = ctx.params.appId;
ctx.body = await Package.findAllByApp(appId);
});
router.get('/packages/:id', async(ctx, next) => {
let p: Package|null = await Package.findOne({id: ctx.params.id});
if (!p) {
throw new NotFound(`Package id ${ctx.params.id} not found`);
}
ctx.body = p;
});
// router.post('/packages/:id', async(ctx, next) => {
// let p: Package|null = await Package.findOne({id: ctx.params.id});
// if (!p) {
// throw new NotFound(`Package ${ctx.params.id} Not Found`);
// }
// if (!ctx.request.body.id || ctx.request.body.id !== p.id) {
// throw new ModelInvalidError('Can not change AppID');
// }
// Object.assign(p, ctx.request.body);
// ctx.body = await p.save();
// })
router.patch('/packages/:id', async(ctx, next) => {
new Promise<string|Buffer>((resolve, reject) => {
let downloadUrl = ctx.request.body.downloadUrl;
tmp.tmpName((e, file) => {
if (e) {
reject(e);
} else {
let writeStream = fs.createWriteStream(file);
http.get(downloadUrl, (response) => {
response.pipe(writeStream);
writeStream.on('finish', () => {
resolve(writeStream.path);
});
}).on('error', (err) => {
reject(err);
});
}
});
});
// TODO 打包
});
export default router;
import * as Router from 'koa-router'
import * as path from 'path'
import * as uuid from 'uuid'
import * as _fs from 'fs'
import { promisifyAll} from 'bluebird'
const fs:any = promisifyAll(_fs)
import * as busboy from 'async-busboy'
import * as mime from 'mime'
const router = new Router();
function uploadImageStream(file){
return new Promise(async (resolve, reject) => {
const ext = mime.extension(file.mime)
if(['png','jpg','jpeg','gif','webp'].indexOf(ext) === -1) {
return reject(new Error("Unsupported image type"))
}
const hash = uuid.v1()
const uploadDir = 'upload'
const fileName = `${hash}.${ext}`
try {
let access = await fs.accessAsync(uploadDir)
} catch (error) {
await fs.mkdirAsync(uploadDir)
}
let writeStream = fs.createWriteStream(path.join(uploadDir, fileName))
file.pipe(writeStream)
resolve({fileName})
})
}
router.post('/upload/image', async(ctx, next) => {
try {
const {files} = await busboy(ctx.req)
const res = await Promise.all(files.map(file => {
return uploadImageStream(file)
}))
ctx.body = res
} catch (err) {
ctx.throw(403, err)
}
})
export default router;
import Router = require('koa-router');
const router = new Router();
/* GET home page. */
router.get('/users', (ctx, next) => {
ctx.body = 'Hello World';
});
router.post('/users/:id(\\d*)', async(ctx, next) => {
});
export default router;
import Koa = require('koa');
import index from './routes/index';
import upload from './routes/upload';
import users from './routes/users';
import apps from './routes/apps';
import packages from './routes/packages';
import bodyParser = require('koa-bodyparser');
import * as mongoose from 'mongoose'
// import Mongorito = require('mongorito');
import log4js = require('log4js');
if(process.env.NODE_ENV !== 'production') {
require('dotenv').config()
}
import * as Koa from 'koa'
import * as log4js from 'log4js'
import * as bodyParser from 'koa-bodyparser'
import { mongodb } from './src/models/iridium'
// import index from './routes/index';
import upload from './src/routes/upload';
// import users from './src/routes/users';
import apps from './src/routes/app';
// import packages from './routes/packages';
const logger = log4js.getLogger();
const url = require('./mongodb_config.json').dbSettings.connectionString;
const logger = log4js.getLogger();
const app = new Koa();
......@@ -58,91 +60,16 @@ app.use(async(ctx, next) => {
app.use(bodyParser());
app.use(index.routes());
app.use(users.routes());
// app.use(index.routes());
// app.use(users.routes());
app.use(apps.routes());
app.use(upload.routes());
app.use(packages.routes());
// app.use(packages.routes());
mongoose.connect(url).then(() => {
app.listen(8001, () => {
console.log("app listening port 8001")
});
mongodb.connect().then(() => {
app.listen(8001, () => {
console.log("app listening port 8001")
});
})
// Mongorito.connect(url).then(() => {
// app.listen(8001, () => {
// console.log("app listening port 8001")
// });
// });
// function getKoaLogger (logger4js, options) {
// if (typeof options === 'object') {
// options = options || {}
// } else if (options) {
// options = { format: options }
// } else {
// options = {}
// }
//
// var thislogger = logger4js
// var level = levels.toLevel(options.level, levels.INFO)
// var fmt = options.format || DEFAULT_FORMAT
// var nolog = options.nolog ? createNoLogCondition(options.nolog) : null
//
// return co.wrap(function *(ctx, next) {
// // mount safety
// if (ctx.request._logging) return yield next()
//
// // nologs
// if (nolog && nolog.test(ctx.originalUrl)) return yield next()
// if (thislogger.isLevelEnabled(level) || options.level === 'auto') {
// var start = new Date()
// var writeHead = ctx.response.writeHead
//
// // flag as logging
// ctx.request._logging = true
//
// // proxy for statusCode.
// ctx.response.writeHead = function (code, headers) {
// ctx.response.writeHead = writeHead
// ctx.response.writeHead(code, headers)
// ctx.response.__statusCode = code
// ctx.response.__headers = headers || {}
//
// // status code response level handling
// if (options.level === 'auto') {
// level = levels.INFO
// if (code >= 300) level = levels.WARN
// if (code >= 400) level = levels.ERROR
// } else {
// level = levels.toLevel(options.level, levels.INFO)
// }
// }
//
// yield next()
// // hook on end request to emit the log entry of the HTTP request.
// ctx.response.responseTime = new Date() - start
// // status code response level handling
// if (ctx.res.statusCode && options.level === 'auto') {
// level = levels.INFO
// if (ctx.res.statusCode >= 300) level = levels.WARN
// if (ctx.res.statusCode >= 400) level = levels.ERROR
// }
// if (thislogger.isLevelEnabled(level)) {
// var combinedTokens = assembleTokens(ctx, options.tokens || [])
// if (typeof fmt === 'function') {
// var line = fmt(ctx, function (str) {
// return format(str, combinedTokens)
// })
// if (line) thislogger.log(level, line)
// } else {
// thislogger.log(level, format(fmt, combinedTokens))
// }
// }
// } else {
// // ensure next gets always called
// yield next()
// }
// })
// }
import { Container } from 'inversify'
import TYPES from './types'
const container = new Container()
export default container
\ No newline at end of file
import {Core, Model, Instance, Collection, Index, Property, ObjectID} from 'iridium'
import {handleImg} from '../utils'
interface I18n<T> {
[locale: string]: T;
}
interface Platform<T> {
[platform: string]: T;
}
interface Package{
id: string;
name: string;
platforms: Platform<string[]>;
locales: I18n<string[]>;
files: File[];
}
interface File {
path: string;
size: number;
hash: string;
}
export interface App {
id: string;
name?: I18n<string>;
description?: I18n<string>
developers?: I18n<[{ name: string, url: string }]>
publishers?: I18n<[{ name: string, url: string }]>
released_at?: string;
category?: string;
parent?: string;
tag?: string[];
dependencies?: Platform<string[]>;
references?: Platform<string[]>;
homepage?: string;
locales?: string[];
actions?: Platform<{[key: string]: {execuate: string, args: string[], env: {[key: string]: string}}}>;
files?: {[key: string]: { sync: boolean}}
version?: Platform<string>;
news?: I18n<{title: string, url: string, image: string}[]>;
conference?: string;
data?: any;
icon?: string;
cover?: string;
background?: string;
packages?: Package[];
created_at: Date;
}
@Collection('apps')
@Index({id: 1}, { unique: true })
export class AppSchema extends Instance<App, AppSchema> implements App {
@Property(String, true)
id: string;
@Property(Object, false)
name?: I18n<string>;
@Property(Object, false)
description?: I18n<string>
@Property(Object, false)
developers?: I18n<[{ name: string, url: string }]>
@Property(Object, false)
publishers?: I18n<[{ name: string, url: string }]>
@Property(String, false)
released_at?: string;
@Property(String, false)
category?: string;
@Property(String, false)
parent?: string;
@Property(Array, false)
tag?: string[];
@Property(Object, false)
dependencies?: Platform<string[]>;
@Property(Object, false)
references?: Platform<string[]>;
@Property(String, false)
homepage?: string;
@Property(Array, false)
locales?: string[];
@Property(Object, false)
actions?: Platform<{[key: string]: {execuate: string, args: string[], env: {[key: string]: string}}}>;
@Property(Object, false)
files?: {[key: string]: { sync: boolean}}
@Property(Object, false)
version?: Platform<string>;
@Property(Object, false)
news?: I18n<{title: string, url: string, image: string}[]>;
@Property(String, false)
conference?: string;
@Property(Object, false)
data?: any;
@Property(String, false)
icon?: string;
@Property(String, false)
cover?: string;
@Property(String, false)
background?: string;
@Property(Array, false)
packages?: Package[];
@Property(Date, false)
created_at: Date;
static onCreating(app: App){
app.created_at = new Date()
app.packages = []
}
handleUpdate(data: App) {
Object.assign(this, data)
}
toJSON() {
this.Convert()
return JSON.parse(this)
}
Convert() {
this.icon = handleImg(this.icon),
this.cover = handleImg(this.cover),
this.background = handleImg(this.background)
}
}
import {Core, Model} from "iridium";
import {App, AppSchema} from "./App";
import {Package, PackageSchema} from "./Package";
export class MongoDB extends Core {
Apps = new Model<App, AppSchema>(this, AppSchema)
Packages = new Model<Package, PackageSchema>(this,PackageSchema)
}
export const mongodb = new MongoDB(process.env["MONGODB"])
import {Core, Model, Instance, Collection, Index, Property, ObjectID} from 'iridium'
type Locale = 'zh-CN' | 'en-US' | 'ja-JP'
type Platform = 'win32' | 'linux' | 'darwin'
export interface Action {
execute: string;
args: string[];
env: {};
open?: string;
}
export interface File {
path: string;
size: number;
hash: string;
}
export interface Package {
id: string;
name: string;
appId: string;
version: string;
locales: Locale[];
platforms: Platform[];
files: File[];
}
@Collection("packages")
@Index({id: 1}, { unique: true })
export class PackageSchema extends Instance<Package, PackageSchema> implements Package {
@Property(String, true)
id: string;
@Property(String, false)
name: string;
@Property(String, false)
appId: string;
@Property(String, false)
version: string;
@Property(Array, false)
locales: Locale[];
@Property(Array, false)
platforms: Platform[];
@Property(Array, false)
files: File[];
handleUpdate(data: Package) {
Object.assign(this, data)
}
}
\ No newline at end of file
import Router = require('koa-router');
import {mongodb} from '../models/iridium'
import {App, AppSchema} from "../models/App";
import {Context} from "koa";
const router = new Router();
router.get('/apps', async (ctx: Context, next) => {
ctx.body = await mongodb.Apps.find({})
.map(async app => {
if(Array.isArray(app.packages) && app.packages.length > 0){
app.packages = await Promise.all(app.packages.map(async p => {
return await mongodb.Packages.findOne({id: p})
}))
}
return app
})
});
router.post('/apps/:id', async (ctx: Context, next) => {
if (!ctx.request.body.id || ctx.params.id !== ctx.request.body.id) {
ctx.throw(400, "App is not same")
}
let exists = await mongodb.Apps.findOne({id: ctx.request.body.id});
if (exists) {
ctx.throw(400, "App id is exists")
}
try {
ctx.body = await mongodb.Apps.insert(ctx.request.body)
} catch (e) {
ctx.throw(400, e)
}
})
router.patch('/apps/:id', async (ctx: Context, next) => {
let data = ctx.request.body
let app: AppSchema | null = await mongodb.Apps.findOne({id: ctx.params.id});
if (!app) {
ctx.throw(400, `App ${ctx.params.id} Not Found `);
}
if (!ctx.request.body.id || ctx.request.body.id !== app!.id) {
ctx.throw(400, `Can not change AppID`)
}
if(Array.isArray(data.packages)) {
data.packages = await Promise.all(data.packages.map(async _p => {
const p = await mongodb.Packages.findOne({id: _p.id})
if(p) {
p.handleUpdate(_p)
await p.save()
return p.id
} else {
const newP = await mongodb.Packages.insert(_p)
return newP.id
}
}))
}
app!.handleUpdate(data)
ctx.body = await app!.save()
})
export default router
\ No newline at end of file
import { Context } from 'koa';
import { OSS } from 'aliyun-sdk';
import * as busboy from 'async-busboy';
import * as mime from 'mime';
import * as uuid from 'uuid';
import * as Client from 'aliyun-oss-upload-stream';
import Router = require('koa-router');
const ossStream = Client(new OSS({
accessKeyId: process.env["OSS_ACCESS_ID"],
secretAccessKey: process.env["OSS_ACCESS_KEY"],
endpoint: process.env["OSS_ENDPOINT"],
apiVersion: '2013-10-15'
}));
const router = new Router()
const UploadImage = async (ctx: Context) => {
try {
const { files } = await busboy(ctx.req);
ctx.body = await Promise.all(files.map(async file => {
const ext = mime.extension(file.mime);
if (['png', 'jpg', 'jpeg', 'gif', 'webp'].indexOf(ext) === -1) {
throw new Error('Unsupported image type');
}
const filename = `test/${uuid.v1()}`;
const upload = ossStream.upload({
Bucket: process.env["OSS_BUCKET"],
Key: filename,
ContentType: file.mimeType
});
upload.minPartSize(1048576); // 1M,表示每块part大小至少大于1M
file.pipe(upload);
return await new Promise((resolve, reject) => {
upload.on('error', reject);
upload.on('uploaded', resolve);
});
}));
} catch (err) {
ctx.throw(403, err);
}
};
router.post('/upload/image', UploadImage)
export default router
const TYPES = {
}
export default TYPES
\ No newline at end of file
import { URL } from 'url';
export const handleImg = (img) => {
if (img) {
let url: URL;
if (img.substring(0, 16) == '/uploads/default') {
url = new URL(img, 'https://ygobbs.com');
} else {
url = new URL(img, 'https://cdn01.moecube.com');
}
return url.toString();
} else {
return 'https://cdn01.moecube.com/accounts/default_avatar.jpg';
}
}
\ No newline at end of file
{
"rules": {
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"eofline": true,
"forin": true,
"indent": [
true,
"spaces"
],
"label-position": true,
"label-undefined": true,
"max-line-length": [
true,
140
],
"member-access": false,
"member-ordering": [
true,
"static-before-instance",
"variables-before-functions"
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-key": true,
"no-duplicate-variable": true,
"no-empty": false,
"no-eval": true,
"no-inferrable-types": true,
"no-shadowed-variable": true,
"no-string-literal": false,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": true,
"no-unused-expression": true,
"no-unused-variable": true,
"no-unreachable": true,
"no-use-before-declare": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"quotemark": [
true,
"single"
],
"radix": true,
"semicolon": [
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
]
}
}
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment