├── wyfReader ├── .watchmanconfig ├── .gitattributes ├── app.json ├── app │ ├── images │ │ ├── 2.png │ │ ├── up.png │ │ ├── back.png │ │ ├── clock.png │ │ ├── down.png │ │ ├── house.png │ │ ├── test.jpg │ │ ├── person.png │ │ ├── search.png │ │ ├── search_1.png │ │ ├── tabbar1.png │ │ └── directory.png │ ├── services │ │ ├── auth.js │ │ └── app.js │ ├── utils │ │ ├── index.js │ │ ├── setAuthorizationToken.js │ │ ├── dva.js │ │ ├── request.js │ │ └── utils.js │ ├── libs │ │ └── request.js │ ├── index.js │ ├── models │ │ ├── router.js │ │ ├── reader.js │ │ └── app.js │ ├── containers │ │ ├── Account.js │ │ ├── Directory.js │ │ ├── Register.js │ │ ├── Login.js │ │ ├── Detail.js │ │ ├── Search.js │ │ └── Home.js │ └── router.js ├── android │ ├── app │ │ ├── src │ │ │ └── main │ │ │ │ ├── res │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ └── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── wyfreader │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ └── MainApplication.java │ │ │ │ └── AndroidManifest.xml │ │ ├── BUCK │ │ ├── proguard-rules.pro │ │ └── build.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── keystores │ │ ├── debug.keystore.properties │ │ └── BUCK │ ├── settings.gradle │ ├── build.gradle │ ├── gradle.properties │ ├── gradlew.bat │ └── gradlew ├── ios │ ├── wyfReader │ │ ├── Images.xcassets │ │ │ ├── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── AppDelegate.h │ │ ├── main.m │ │ ├── AppDelegate.m │ │ ├── Info.plist │ │ └── Base.lproj │ │ │ └── LaunchScreen.xib │ ├── wyfReaderTests │ │ ├── Info.plist │ │ └── wyfReaderTests.m │ ├── wyfReader-tvOSTests │ │ └── Info.plist │ ├── wyfReader-tvOS │ │ └── Info.plist │ └── wyfReader.xcodeproj │ │ └── xcshareddata │ │ └── xcschemes │ │ ├── wyfReader.xcscheme │ │ └── wyfReader-tvOS.xcscheme ├── .buckconfig ├── .babelrc ├── index.js ├── jsconfig.json ├── .editorconfig ├── __tests__ │ └── App.js ├── .gitignore ├── .eslintrc ├── App.js ├── package.json └── .flowconfig ├── wu-server ├── .rsync-exclude ├── .babelrc ├── index.js ├── config │ ├── env │ │ ├── common.js │ │ ├── test.js │ │ ├── development.js │ │ └── production.js │ ├── index.js │ └── passport.js ├── .eslintrc.json ├── nginx.conf ├── src │ ├── middleware │ │ ├── index.js │ │ └── validators.js │ ├── modules │ │ ├── auth │ │ │ ├── router.js │ │ │ └── controller.js │ │ ├── test │ │ │ ├── router.js │ │ │ └── controller.js │ │ ├── users │ │ │ ├── router.js │ │ │ └── controller.js │ │ ├── chapters.js │ │ │ ├── router.js │ │ │ └── controller.js │ │ ├── bookshelves.js │ │ │ ├── router.js │ │ │ └── controller.js │ │ ├── novels.js │ │ │ ├── router.js │ │ │ └── controller.js │ │ └── index.js │ ├── utils │ │ ├── auth.js │ │ ├── schedule │ │ │ └── updateChapter.js │ │ ├── redis.js │ │ ├── handle │ │ │ └── index.js │ │ ├── updateNovel.js │ │ └── crawler.js │ └── models │ │ ├── novels.js │ │ ├── bookshelfs.js │ │ ├── chapters.js │ │ └── users.js ├── .vscode │ └── launch.json ├── README.md ├── Dockerfile ├── release.sh ├── .editorconfig ├── bin │ └── server.js └── package.json ├── LICENSE ├── .gitignore └── README.md /wyfReader/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /wyfReader/.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | -------------------------------------------------------------------------------- /wu-server/.rsync-exclude: -------------------------------------------------------------------------------- 1 | .git/* 2 | logs/* 3 | node_modules/* 4 | npm-* 5 | coverage -------------------------------------------------------------------------------- /wyfReader/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wyfReader", 3 | "displayName": "wyfReader" 4 | } -------------------------------------------------------------------------------- /wu-server/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015-node5", 4 | "stage-0" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /wyfReader/app/images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/app/images/2.png -------------------------------------------------------------------------------- /wyfReader/app/images/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/app/images/up.png -------------------------------------------------------------------------------- /wyfReader/app/images/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/app/images/back.png -------------------------------------------------------------------------------- /wyfReader/app/images/clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/app/images/clock.png -------------------------------------------------------------------------------- /wyfReader/app/images/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/app/images/down.png -------------------------------------------------------------------------------- /wyfReader/app/images/house.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/app/images/house.png -------------------------------------------------------------------------------- /wyfReader/app/images/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/app/images/test.jpg -------------------------------------------------------------------------------- /wu-server/index.js: -------------------------------------------------------------------------------- 1 | require('babel-core/register')() 2 | require('babel-polyfill') 3 | require('./bin/server.js') 4 | -------------------------------------------------------------------------------- /wyfReader/app/images/person.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/app/images/person.png -------------------------------------------------------------------------------- /wyfReader/app/images/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/app/images/search.png -------------------------------------------------------------------------------- /wyfReader/app/images/search_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/app/images/search_1.png -------------------------------------------------------------------------------- /wyfReader/app/images/tabbar1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/app/images/tabbar1.png -------------------------------------------------------------------------------- /wyfReader/app/images/directory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/app/images/directory.png -------------------------------------------------------------------------------- /wu-server/config/env/common.js: -------------------------------------------------------------------------------- 1 | export default { 2 | port: process.env.PORT || 5000, 3 | crawlerUrl: "https://www.qu.la" 4 | } 5 | -------------------------------------------------------------------------------- /wyfReader/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | wyfReader 3 | 4 | -------------------------------------------------------------------------------- /wyfReader/ios/wyfReader/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /wyfReader/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /wyfReader/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /wyfReader/app/services/auth.js: -------------------------------------------------------------------------------- 1 | import { delay } from '../utils' 2 | 3 | export const login = async () => { 4 | await delay(2000) 5 | return true 6 | } 7 | -------------------------------------------------------------------------------- /wu-server/config/env/test.js: -------------------------------------------------------------------------------- 1 | export default { 2 | session: 'secret-boilerplate-token', 3 | token: 'secret-jwt-token', 4 | database: 'mongodb://localhost:27017/wu' 5 | } 6 | -------------------------------------------------------------------------------- /wyfReader/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /wyfReader/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /wyfReader/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /wyfReader/android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /wyfReader/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react-native"], 3 | "plugins": [ 4 | "transform-decorators-legacy", 5 | ["import", { "libraryName": "antd-mobile" }] 6 | ] 7 | } -------------------------------------------------------------------------------- /wyfReader/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyafeiJS/Reader/HEAD/wyfReader/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /wyfReader/index.js: -------------------------------------------------------------------------------- 1 | // import { AppRegistry } from 'react-native' 2 | // import App from './App' 3 | 4 | // AppRegistry.registerComponent('wyfReader', () => App) 5 | import './app/index' -------------------------------------------------------------------------------- /wyfReader/android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = "debug", 3 | properties = "debug.keystore.properties", 4 | store = "debug.keystore", 5 | visibility = [ 6 | "PUBLIC", 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /wu-server/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "standard", 4 | "env": { 5 | "node": true, 6 | "mocha": true 7 | }, 8 | "rules": { 9 | "eqeqeq": 0 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /wu-server/config/index.js: -------------------------------------------------------------------------------- 1 | import common from './env/common' 2 | 3 | const env = process.env.NODE_ENV || 'development' 4 | const config = require(`./env/${env}`).default 5 | 6 | export default Object.assign({}, common, config) 7 | -------------------------------------------------------------------------------- /wyfReader/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "allowSyntheticDefaultImports": true, 5 | "experimentalDecorators": true 6 | }, 7 | "exclude": [ 8 | "node_modules" 9 | ] 10 | } -------------------------------------------------------------------------------- /wyfReader/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'wyfReader' 2 | include ':react-native-svg' 3 | project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android') 4 | 5 | include ':app' 6 | -------------------------------------------------------------------------------- /wyfReader/app/utils/index.js: -------------------------------------------------------------------------------- 1 | export { NavigationActions } from 'react-navigation' 2 | 3 | export const delay = time => new Promise(resolve => setTimeout(resolve, time)) 4 | 5 | export const createAction = type => payload => ({ type, payload }) 6 | -------------------------------------------------------------------------------- /wu-server/config/env/development.js: -------------------------------------------------------------------------------- 1 | export default { 2 | session: 'secret-boilerplate-token', 3 | token: 'secret-jwt-token', 4 | database: 'mongodb://120.79.161.225:27017/wu', 5 | redis: { 6 | host: 'localhost', 7 | port: 6379, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /wu-server/config/env/production.js: -------------------------------------------------------------------------------- 1 | export default { 2 | session: 'secret-boilerplate-token', 3 | token: 'secret-jwt-token', 4 | database: 'mongodb://120.79.161.225:27017/wu', 5 | redis: { 6 | host: 'localhost', 7 | port: 6379, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /wyfReader/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /wu-server/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | location / { 4 | root /opt/html; 5 | index index.html index.html; 6 | } 7 | location /server/ { 8 | expires -1; 9 | add_header Cache-Control no-cache,no-store; 10 | proxy_pass http://120.79.161.255:8080/; 11 | } 12 | } -------------------------------------------------------------------------------- /wyfReader/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Apr 26 14:34:44 CST 2018 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip 7 | -------------------------------------------------------------------------------- /wu-server/src/middleware/index.js: -------------------------------------------------------------------------------- 1 | export function errorMiddleware () { 2 | return async (ctx, next) => { 3 | try { 4 | await next() 5 | } catch (err) { 6 | ctx.status = err.status || 500 7 | ctx.body = err.message 8 | ctx.app.emit('error', err, ctx) 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /wyfReader/app/utils/setAuthorizationToken.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios' 2 | 3 | export default function setAuthorizationToken(token) { 4 | if (token) { 5 | axios.defaults.headers.common['Authorization'] = `Bearer ${token}` 6 | } else { 7 | delete axios.defaults.headers.common['Authorization'] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /wyfReader/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | max_line_length = 80 11 | trim_trailing_whitespace = true 12 | 13 | [*.md] 14 | max_line_length = 0 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /wyfReader/__tests__/App.js: -------------------------------------------------------------------------------- 1 | import 'react-native'; 2 | import React from 'react'; 3 | import App from '../App'; 4 | 5 | // Note: test renderer must be required after react-native. 6 | import renderer from 'react-test-renderer'; 7 | 8 | it('renders correctly', () => { 9 | const tree = renderer.create( 10 | 11 | ); 12 | }); 13 | -------------------------------------------------------------------------------- /wu-server/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "program": "${workspaceFolder}/index.js" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /wu-server/src/modules/auth/router.js: -------------------------------------------------------------------------------- 1 | import * as auth from './controller' 2 | 3 | export const baseUrl = '/auth' 4 | 5 | export default [ 6 | { 7 | method: 'POST', 8 | route: '/', 9 | handlers: [ 10 | auth.authUser 11 | ] 12 | }, 13 | { 14 | method: 'POST', 15 | route: '/test', 16 | handlers: [ 17 | auth.testUser 18 | ] 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /wu-server/src/modules/test/router.js: -------------------------------------------------------------------------------- 1 | import * as test from './controller' 2 | 3 | export const baseUrl = '/test' 4 | 5 | export default [ 6 | { 7 | method: 'GET', 8 | route: '/', 9 | handlers: [ 10 | test.getChapters 11 | ] 12 | }, 13 | { 14 | method: 'GET', 15 | route: '/img', 16 | handlers: [ 17 | test.getImgs 18 | ] 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /wu-server/README.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 基于koa2的api服务器,数据库mongoodb。 3 | 4 | ## 安装 5 | 请先确定安装了 mongoodb。 6 | ```bash 7 | git clone https://github.com/dlyt/YCool_Server.git 8 | npm install 9 | ``` 10 | 11 | ## 开发 12 | ```bash 13 | npm run dev 14 | ``` 15 | 16 | ## API文档 17 | 18 | ```bash 19 | npm run docs 20 | ``` 21 | 22 | 运行项目后查看: http://localhost:5000/docs/ 23 | 24 | ## License 25 | 26 | 仅供学习使用 27 | -------------------------------------------------------------------------------- /wu-server/src/utils/auth.js: -------------------------------------------------------------------------------- 1 | export function getToken (ctx) { 2 | const header = ctx.request.header.authorization 3 | if (!header) { 4 | return null 5 | } 6 | 7 | const parts = header.split(' ') 8 | if (parts.length !== 2) { 9 | return null 10 | } 11 | const scheme = parts[0] 12 | const token = parts[1] 13 | if (/^Bearer$/i.test(scheme)) { 14 | return token 15 | } 16 | return null 17 | } 18 | -------------------------------------------------------------------------------- /wyfReader/android/app/src/main/java/com/wyfreader/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.wyfreader; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "wyfReader"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /wu-server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM hub.c.163.com/library/node:8.4-slim 2 | MAINTAINER wuyafei 3 | 4 | RUN mkdir -p /opt/reader-server 5 | ADD . /opt/reader-server 6 | 7 | COPY ./ /opt/reader-server 8 | WORKDIR /opt/reader-server 9 | # RUN npm config set registry http://10.2.144.44:8081/repository/npm && \ 10 | # NODEJS_ORG_MIRROR=http://10.2.144.44:8081/repository/node npm i --production --verbose 11 | RUN npm i 12 | 13 | EXPOSE 5000 14 | 15 | CMD NODE_ENV=production node index.js 16 | -------------------------------------------------------------------------------- /wyfReader/ios/wyfReader/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /wu-server/src/modules/users/router.js: -------------------------------------------------------------------------------- 1 | import { ensureUser } from '../../middleware/validators' 2 | import * as user from './controller' 3 | 4 | export const baseUrl = '/users' 5 | 6 | export default [ 7 | { 8 | method: 'POST', 9 | route: '/tourists', 10 | handlers: [ 11 | user.createTourist 12 | ] 13 | }, 14 | { 15 | method: 'POST', 16 | route: '/register', 17 | handlers: [ 18 | user.register 19 | ] 20 | }, 21 | { 22 | method: 'GET', 23 | route: '/captcha', 24 | handlers: [ 25 | user.getCaptcha 26 | ] 27 | } 28 | ] 29 | 30 | -------------------------------------------------------------------------------- /wyfReader/ios/wyfReader/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /wu-server/src/models/novels.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose' 2 | 3 | const Schema = mongoose.Schema 4 | const ObjectId = Schema.Types.ObjectId 5 | 6 | const Novel = new mongoose.Schema({ 7 | type: { type: String, default: 'Normal' }, 8 | name: { type: String , unique: true}, 9 | url: { type: String }, 10 | status: { type: Number }, 11 | author: { type: String }, 12 | introduction: { type: String }, 13 | img: { type: String, default: '' }, 14 | updateTime: { type: String }, 15 | lastChapterTitle: { type: String }, 16 | countChapter: { type: Number }, 17 | }) 18 | 19 | 20 | export default mongoose.model('novel', Novel) 21 | -------------------------------------------------------------------------------- /wyfReader/app/utils/dva.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { create } from 'dva-core' 3 | import { Provider, connect } from 'react-redux' 4 | 5 | export { connect } 6 | 7 | export default function(options) { 8 | const app = create(options) 9 | if (!global.registered) options.models.forEach(model => app.model(model)) 10 | global.registered = true 11 | app.start() 12 | // eslint-disable-next-line no-underscore-dangle 13 | const store = app._store 14 | 15 | app.start = container => () => 16 | 17 | {container} 18 | 19 | 20 | app.getStore = () => store 21 | 22 | return app 23 | } 24 | -------------------------------------------------------------------------------- /wu-server/src/middleware/validators.js: -------------------------------------------------------------------------------- 1 | import User from '../models/users' 2 | import config from '../../config' 3 | import { getToken } from '../utils/auth' 4 | import { verify } from 'jsonwebtoken' 5 | 6 | export async function ensureUser (ctx, next) { 7 | const token = getToken(ctx) 8 | 9 | if (!token) { 10 | ctx.throw(401) 11 | } 12 | 13 | let decoded = null 14 | try { 15 | decoded = verify(token, config.token) 16 | } catch (err) { 17 | ctx.throw(401) 18 | } 19 | // 缓存userid 20 | ctx.state.user = await User.findById(decoded.id, '-password') 21 | if (!ctx.state.user) { 22 | ctx.throw(401) 23 | } 24 | 25 | return next() 26 | } 27 | -------------------------------------------------------------------------------- /wyfReader/app/libs/request.js: -------------------------------------------------------------------------------- 1 | let request = {}; 2 | const prefix = 'http://120.79.161.225/server' 3 | request.get = (url) => { 4 | let options = { 5 | method: 'GET', 6 | header: { 7 | 'Content-Type': 'application/json' 8 | } 9 | } 10 | let link = `${prefix}${url}` 11 | return new Promise((resolve, reject) => { 12 | fetch(link, options).then(res => { 13 | if (res.ok) { 14 | return res.json() 15 | } 16 | return reject({ status: res.status }) 17 | }).then(res => { 18 | resolve(res) 19 | }).catch((err) => { 20 | reject({status: -1, msg: err.message}) 21 | }) 22 | }) 23 | } 24 | // request.post = () 25 | 26 | export default request -------------------------------------------------------------------------------- /wu-server/src/modules/test/controller.js: -------------------------------------------------------------------------------- 1 | import Chapter from '../../models/chapters' 2 | import Novel from '../../models/novels' 3 | import * as Crawler from '../../utils/crawler' 4 | import * as UpdateNovel from '../../utils/updateNovel' 5 | 6 | 7 | export async function getChapters (ctx) { 8 | await UpdateNovel.update() 9 | ctx.body = { 10 | success: true 11 | } 12 | } 13 | 14 | export async function getImgs (ctx) { 15 | const type = ctx.query.type 16 | // const data = await Crawler.request('http://112.74.34.241:3000/meizi/random?type=%E5%8F%B0%E6%B9%BE') 17 | // const url = JSON.parse(data).url 18 | 19 | ctx.body = { 20 | // url: url 21 | url: "http://og1m0yoqf.bkt.clouddn.com/banner_index.png" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /wu-server/src/utils/schedule/updateChapter.js: -------------------------------------------------------------------------------- 1 | let schedule = require('node-schedule') 2 | let cucurrentRule = new schedule.RecurrenceRule() 3 | import * as UpdateNovel from '../updateNovel' 4 | // let scheduleTime = [10, 51, 81] // 检查频率 5 | // cucurrentRule.dayOfWeek = 0 6 | cucurrentRule.hour = 24 7 | cucurrentRule.minute = 0 8 | // cucurrentRule.second = scheduleTime 9 | console.log('===scheduler start ========.') 10 | schedule.scheduleJob(cucurrentRule, async function () { 11 | try { 12 | console.info('===update started at: ' + new Date()) 13 | await UpdateNovel.update() 14 | console.log('====down at: ' + new Date()) 15 | } catch (error) { 16 | console.error('process error: ' + error) 17 | } finally { 18 | console.info('===ended at: ' + new Date()) 19 | } 20 | }) 21 | -------------------------------------------------------------------------------- /wu-server/release.sh: -------------------------------------------------------------------------------- 1 | BUILD_TIME=`date "+%Y%m%d%H%M"` 2 | SERVER_HOST="root@120.79.161.225" 3 | SERVER_PATH="/opt/wuReader" 4 | IMAGE_NAME="hub.c.163.com/wuyafeijs/reader-server:$BUILD_TIME" 5 | 6 | rsync -cavzP --delete-after ./ --exclude-from='.rsync-exclude' root@120.79.161.225:$SERVER_PATH 7 | ssh $SERVER_HOST "\ 8 | cd $SERVER_PATH; \ 9 | docker kill reader-server; \ 10 | docker rm reader-server; \ 11 | echo "清理过时的镜像"; \ 12 | docker images | awk '/^hub.c.163.com\/wuyafeijs\/reader-server[ ]+/ { print \$3 }' | xargs docker rmi ; \ 13 | docker build -t $IMAGE_NAME .;\ 14 | docker run --name reader-server -p 8080:5000 -d --restart=always $IMAGE_NAME; \ 15 | exit; \ 16 | " 17 | echo "\033[40;32m\n" 18 | echo "Image: $IMAGE_NAME"; \ 19 | # echo "Image run success." 20 | echo "\033[0m" 21 | -------------------------------------------------------------------------------- /wu-server/src/modules/chapters.js/router.js: -------------------------------------------------------------------------------- 1 | import { ensureUser } from '../../middleware/validators' 2 | import * as chapter from './controller' 3 | 4 | export const baseUrl = '/chapters' 5 | 6 | export default [ 7 | { 8 | method: 'POST', 9 | route: '/', 10 | handlers: [ 11 | ensureUser, 12 | chapter.getChapterInfo 13 | ] 14 | }, 15 | { 16 | method: 'GET', 17 | route: '/firstRender', 18 | handlers: [ 19 | ensureUser, 20 | chapter.getFirstRenderChapter 21 | ] 22 | }, 23 | { 24 | method: 'GET', 25 | route: '/next/:id', 26 | handlers: [ 27 | chapter.getNextChapterInfo 28 | ] 29 | }, 30 | { 31 | method: 'GET', 32 | route: '/last/:id', 33 | handlers: [ 34 | chapter.getLastChapterInfo 35 | ] 36 | }, 37 | ] 38 | -------------------------------------------------------------------------------- /wyfReader/ios/wyfReader/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /wu-server/src/modules/bookshelves.js/router.js: -------------------------------------------------------------------------------- 1 | import { ensureUser } from '../../middleware/validators' 2 | import * as bookshelf from './controller' 3 | 4 | export const baseUrl = '/bookshelfs' 5 | 6 | export default [ 7 | { 8 | method: 'GET', 9 | route: '/', 10 | handlers: [ 11 | ensureUser, 12 | bookshelf.getBookshelf 13 | ] 14 | }, 15 | { 16 | method: 'POST', 17 | route: '/order', 18 | handlers: [ 19 | ensureUser, 20 | bookshelf.orderNovel 21 | ] 22 | }, 23 | { 24 | method: 'POST', 25 | route: '/delete', 26 | handlers: [ 27 | bookshelf.delectNovel 28 | ] 29 | }, 30 | { 31 | method: 'POST', 32 | route: '/change', 33 | handlers: [ 34 | ensureUser, 35 | bookshelf.changeBookshelf 36 | ] 37 | } 38 | ] 39 | -------------------------------------------------------------------------------- /wu-server/src/models/bookshelfs.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose' 2 | 3 | const Schema = mongoose.Schema 4 | const ObjectId = Schema.Types.ObjectId 5 | 6 | const Bookshelf = new mongoose.Schema({ 7 | user: { type: ObjectId, ref: 'user' }, 8 | novel: { type: ObjectId, ref: 'novel'}, 9 | chapter: { type: ObjectId, ref: 'chapter'}, 10 | number: { type: Number, default: 0}, 11 | progress: { type: Number, default: 0} 12 | }) 13 | 14 | Bookshelf.statics = { 15 | getList: function (id){ 16 | return this 17 | .find({user: id}) 18 | .populate('novel') 19 | .populate('chapter') 20 | .exec() 21 | }, 22 | findByUserAndNovelId: function (options){ 23 | return this 24 | .findOne({user: options.userId, novel: options.novelId}) 25 | .exec() 26 | } 27 | } 28 | 29 | export default mongoose.model('bookshelf', Bookshelf) 30 | -------------------------------------------------------------------------------- /wyfReader/ios/wyfReaderTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /wyfReader/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | maven { 7 | url 'https://maven.google.com' 8 | } 9 | google() 10 | } 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:3.0.1' 13 | 14 | // NOTE: Do not place your application dependencies here; they belong 15 | // in the individual module build.gradle files 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | mavenLocal() 22 | jcenter() 23 | maven { 24 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 25 | url "$rootDir/../node_modules/react-native/android" 26 | } 27 | google() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /wyfReader/ios/wyfReader-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /wu-server/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | 3 | # A special property that should be specified at the top of the file outside of 4 | # any sections. Set to true to stop .editor config file search on current file 5 | root = true 6 | 7 | [*] 8 | # Indentation style 9 | # Possible values - tab, space 10 | indent_style = space 11 | 12 | # Indentation size in single-spaced characters 13 | # Possible values - an integer, tab 14 | indent_size = 2 15 | 16 | # Line ending file format 17 | # Possible values - lf, crlf, cr 18 | end_of_line = lf 19 | 20 | # File character encoding 21 | # Possible values - latin1, utf-8, utf-16be, utf-16le 22 | charset = utf-8 23 | 24 | # Denotes whether to trim whitespace at the end of lines 25 | # Possible values - true, false 26 | trim_trailing_whitespace = true 27 | 28 | # Denotes whether file should end with a newline 29 | # Possible values - true, false 30 | insert_final_newline = true 31 | -------------------------------------------------------------------------------- /wu-server/src/utils/redis.js: -------------------------------------------------------------------------------- 1 | // import Config from '../../config' 2 | 3 | 4 | // const redis = require('redis').createClient(Config.redis) 5 | // redis.on("error", function (err) { 6 | // console.log("Error " + err) 7 | // }) 8 | 9 | // //存入redis 10 | // export function set(key, value, expire) { 11 | // return new Promise(function(resolve, reject) { 12 | // const multi = redis.multi() 13 | // multi.set(key, value) 14 | // if (expire) { 15 | // multi.expire(key, expire) 16 | // } 17 | // try { 18 | // multi.exec() 19 | // } catch (e) { 20 | // reject(e) 21 | // } 22 | // resolve() 23 | // }) 24 | // } 25 | 26 | // //从redis中取出数据 27 | // export function get(key) { 28 | // return new Promise(function(resolve, reject) { 29 | // redis.get(key, (e, result) => { 30 | // if (e) { 31 | // reject(e) 32 | // } 33 | // else { 34 | // resolve(result) 35 | // } 36 | // }) 37 | // }) 38 | // } 39 | -------------------------------------------------------------------------------- /wyfReader/app/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { AppRegistry, AsyncStorage } from 'react-native' 3 | import { persistStore, autoRehydrate } from 'redux-persist' // 状态持久化 4 | import axios from 'axios' 5 | import dva from './utils/dva' 6 | import Router from './router' 7 | import appModel from './models/app' 8 | import reader from './models/reader' 9 | import routerModel from './models/router' 10 | 11 | const app = dva({ 12 | initialState: {}, 13 | models: [appModel, routerModel, reader], 14 | extraEnhancers: [autoRehydrate()], 15 | onError(e) { 16 | console.log('onError', e) 17 | }, 18 | }) 19 | // 设置后台地址 20 | // axios.defaults.baseURL = 'http://localhost:5000' 21 | axios.defaults.baseURL = 'http://120.79.161.225/server' 22 | const App = app.start() 23 | persistStore(app.getStore(), { 24 | storage: AsyncStorage, 25 | blacklist: ['router'], 26 | }) 27 | 28 | AppRegistry.registerComponent('wyfReader', () => App) 29 | -------------------------------------------------------------------------------- /wu-server/src/models/chapters.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose' 2 | 3 | const Schema = mongoose.Schema 4 | const ObjectId = Schema.Types.ObjectId 5 | 6 | const Chapter = new mongoose.Schema({ 7 | chapters: { type: Array }, 8 | novel: { type: ObjectId, ref: 'novel'}, 9 | }) 10 | 11 | Chapter.statics = { 12 | getTitles: function (id){ 13 | return this 14 | .find({novel: id}) 15 | .exec() 16 | }, 17 | getContent: function (id){ 18 | return this 19 | .findById(id) 20 | .populate('novel',['name', 'url']) 21 | .exec() 22 | }, 23 | findByNumber: function (id, num) { 24 | return this 25 | .findOne({number: num, novel: id}) 26 | .exec() 27 | }, 28 | getDirectory: function (options) { 29 | return this 30 | .find(options.where, options.attributes) 31 | .sort({number: options.order}) 32 | .limit() 33 | .exec() 34 | } 35 | } 36 | 37 | export default mongoose.model('chapter', Chapter) 38 | -------------------------------------------------------------------------------- /wyfReader/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /wyfReader/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IntelliJ 26 | # 27 | build/ 28 | .idea 29 | .gradle 30 | local.properties 31 | *.iml 32 | 33 | # node.js 34 | # 35 | node_modules/ 36 | npm-debug.log 37 | yarn-error.log 38 | 39 | # BUCK 40 | buck-out/ 41 | \.buckd/ 42 | *.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | -------------------------------------------------------------------------------- /wu-server/src/modules/novels.js/router.js: -------------------------------------------------------------------------------- 1 | import { ensureUser } from '../../middleware/validators' 2 | import * as novel from './controller' 3 | 4 | export const baseUrl = '/novels' 5 | 6 | export default [ 7 | { 8 | method: 'GET', 9 | route: '/:id', 10 | handlers: [ 11 | novel.downloadChapters 12 | ] 13 | }, 14 | { 15 | method: 'GET', 16 | route: '/search/zh', 17 | handlers: [ 18 | novel.searchFromZH 19 | ] 20 | }, 21 | { 22 | method: 'GET', 23 | route: '/search/bqk', 24 | handlers: [ 25 | novel.searchFromBQK 26 | ] 27 | }, 28 | { 29 | method: 'POST', 30 | route: '/search', 31 | handlers: [ 32 | novel.searchNovel 33 | ] 34 | }, 35 | { 36 | method: 'POST', 37 | route: '/acquire', 38 | handlers: [ 39 | ensureUser, 40 | novel.getNovel 41 | ] 42 | }, 43 | { 44 | method: 'GET', 45 | route: '/directory/:id', 46 | handlers: [ 47 | novel.getDirectory 48 | ] 49 | } 50 | ] 51 | -------------------------------------------------------------------------------- /wu-server/src/modules/index.js: -------------------------------------------------------------------------------- 1 | import glob from 'glob' 2 | import Router from 'koa-router' 3 | 4 | exports = module.exports = function initModules (app) { 5 | glob(`${__dirname}/*`, { ignore: '**/index.js' }, (err, matches) => { 6 | if (err) { throw err } 7 | 8 | matches.forEach((mod) => { 9 | const router = require(`${mod}/router`) 10 | 11 | const routes = router.default 12 | const baseUrl = router.baseUrl 13 | const instance = new Router({ prefix: baseUrl }) 14 | 15 | routes.forEach((config) => { 16 | const { 17 | method = '', 18 | route = '', 19 | handlers = [] 20 | } = config 21 | 22 | const lastHandler = handlers.pop()// 会修改原数组 23 | // 集成路由,支持多重回调 24 | instance[method.toLowerCase()](route, ...handlers, async function(ctx) { 25 | return await lastHandler(ctx) 26 | }) 27 | 28 | app 29 | .use(instance.routes()) 30 | .use(instance.allowedMethods()) 31 | }) 32 | }) 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 wuyafeiJS 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /wyfReader/app/models/router.js: -------------------------------------------------------------------------------- 1 | import { delay, NavigationActions } from '../utils' 2 | import { routerReducer } from '../router' 3 | 4 | const actions = [ 5 | NavigationActions.BACK, 6 | NavigationActions.INIT, 7 | NavigationActions.NAVIGATE, 8 | NavigationActions.RESET, 9 | NavigationActions.SET_PARAMS, 10 | NavigationActions.URI, 11 | ] 12 | 13 | export default { 14 | namespace: 'router', 15 | state: { 16 | ...routerReducer(), 17 | }, 18 | reducers: { 19 | apply(state, { payload: action }) { 20 | return routerReducer(state, action) 21 | }, 22 | }, 23 | effects: { 24 | watch: [ 25 | function* watch({ take, call, put }) { 26 | const loop = true 27 | while (loop) { 28 | const payload = yield take(actions) 29 | yield put({ 30 | type: 'apply', 31 | payload, 32 | }) 33 | // debounce, see https://github.com/react-community/react-navigation/issues/271 34 | if (payload.type === 'Navigation/NAVIGATE') { 35 | yield call(delay, 500) 36 | } 37 | } 38 | }, 39 | { type: 'watcher' }, 40 | ], 41 | }, 42 | } 43 | -------------------------------------------------------------------------------- /wyfReader/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 19 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /wyfReader/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true 5 | }, 6 | "extends": [ 7 | "airbnb", 8 | "prettier", 9 | "prettier/react" 10 | ], 11 | "plugins": [ 12 | "react", 13 | "jsx-a11y", 14 | "import", 15 | "prettier" 16 | ], 17 | "globals": { 18 | "__DEV__": true 19 | }, 20 | "rules": { 21 | "arrow-parens": 0, 22 | "global-require": 0, 23 | "import/prefer-default-export": 0, 24 | "no-console": 0, 25 | "no-mixed-operators": 0, 26 | "no-use-before-define": 0, 27 | "radix": 0, 28 | "react/jsx-filename-extension": 0, 29 | "react/react-in-jsx-scope": 0, 30 | "react/prefer-stateless-function":0, 31 | "no-underscore-dangle":0, 32 | "react/prop-types": 0, 33 | "semi": [0, "never"], 34 | "spaced-comment": 0, 35 | "func-names": 0, 36 | "object-shorthand": 0, 37 | "object-shorthan": 0, 38 | "no-lonely-if": 0, 39 | "one-var": 0, 40 | "prefer-const": 0, 41 | "no-plusplus": 0, 42 | "camelcase": 0, 43 | "eqeqeq": 0, 44 | "react/no-string-refs": 0, 45 | "class-methods-use-this": 0, 46 | "react/self-closing-comp": 0, 47 | "react/jsx-no-bind": 0, 48 | "no-unused-vars": 1, 49 | "no-return-assign": 0, 50 | "react/sort-comp": 0 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /wu-server/config/passport.js: -------------------------------------------------------------------------------- 1 | import passport from 'koa-passport' 2 | import User from '../src/models/users' 3 | import { Strategy } from 'passport-local' 4 | 5 | /** 6 | * @param username 用户输入的用户名 7 | * @param password 用户输入的密码 8 | * @param done 验证完成后的回调函数 9 | */ 10 | passport.use('local', new Strategy({ 11 | usernameField: 'username', 12 | passwordField: 'password' 13 | }, async (username, password, done) => { 14 | try { 15 | const user = await User.findOne({ username }) 16 | if (!user) { return done(null, false) } 17 | 18 | try { 19 | const isMatch = await user.validatePassword(password) 20 | 21 | if (!isMatch) { return done(null, false) } 22 | 23 | done(null, user) 24 | } catch (err) { 25 | done(err) 26 | } 27 | } catch (err) { 28 | return done(err) 29 | } 30 | })) 31 | // serializeUser 在用户登录验证成功后将会把用户的数据储存到 session 中 32 | passport.serializeUser((user, done) => { 33 | console.log('kkkkkkk') 34 | done(null, user.id) 35 | }) 36 | 37 | // deserializeUser 在每次请求时候将从 session 中读用户对象 38 | passport.deserializeUser(async (id, done) => { 39 | console.log('deserializeUser, id: ' + id) 40 | try { 41 | const user = await User.findById(id, '-password') 42 | done(null, user) 43 | } catch (err) { 44 | done(err) 45 | } 46 | }) 47 | 48 | export default passport 49 | -------------------------------------------------------------------------------- /wyfReader/android/app/src/main/java/com/wyfreader/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.wyfreader; 2 | 3 | import android.app.Application; 4 | 5 | import com.facebook.react.ReactApplication; 6 | import com.horcrux.svg.SvgPackage; 7 | import com.facebook.react.ReactNativeHost; 8 | import com.facebook.react.ReactPackage; 9 | import com.facebook.react.shell.MainReactPackage; 10 | import com.facebook.soloader.SoLoader; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class MainApplication extends Application implements ReactApplication { 16 | 17 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 18 | @Override 19 | public boolean getUseDeveloperSupport() { 20 | return BuildConfig.DEBUG; 21 | } 22 | 23 | @Override 24 | protected List getPackages() { 25 | return Arrays.asList( 26 | new MainReactPackage(), 27 | new SvgPackage() 28 | ); 29 | } 30 | 31 | @Override 32 | protected String getJSMainModuleName() { 33 | return "index"; 34 | } 35 | }; 36 | 37 | @Override 38 | public ReactNativeHost getReactNativeHost() { 39 | return mReactNativeHost; 40 | } 41 | 42 | @Override 43 | public void onCreate() { 44 | super.onCreate(); 45 | SoLoader.init(this, /* native exopackage */ false); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /wyfReader/App.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | Platform, 10 | StyleSheet, 11 | Text, 12 | View 13 | } from 'react-native'; 14 | 15 | const instructions = Platform.select({ 16 | ios: 'Press Cmd+R to reload,\n' + 17 | 'Cmd+D or shake for dev menu', 18 | android: 'Double tap R on your keyboard to reload,\n' + 19 | 'Shake or press menu button for dev menu', 20 | }); 21 | 22 | export default class App extends Component { 23 | render() { 24 | return ( 25 | 26 | 27 | Welcome to React Native!wyf 28 | 29 | 30 | To get started, edit App.js 31 | 32 | 33 | {instructions} 34 | 35 | 36 | ); 37 | } 38 | } 39 | 40 | const styles = StyleSheet.create({ 41 | container: { 42 | flex: 1, 43 | justifyContent: 'center', 44 | alignItems: 'center', 45 | backgroundColor: '#F5FCFF', 46 | }, 47 | welcome: { 48 | fontSize: 20, 49 | textAlign: 'center', 50 | margin: 10, 51 | }, 52 | instructions: { 53 | textAlign: 'center', 54 | color: '#333333', 55 | marginBottom: 5, 56 | }, 57 | }); 58 | -------------------------------------------------------------------------------- /wu-server/src/modules/auth/controller.js: -------------------------------------------------------------------------------- 1 | import passport from '../../../config/passport' 2 | 3 | /** 4 | * @apiDefine TokenError 5 | * @apiError Unauthorized Invalid JWT token 6 | * 7 | * @apiErrorExample {json} Unauthorized-Error: 8 | * HTTP/1.1 401 Unauthorized 9 | * { 10 | * "status": 401, 11 | * "error": "Unauthorized" 12 | * } 13 | */ 14 | // 认证登录 15 | export async function authUser (ctx, next) { 16 | const code = ctx.request.body.code 17 | const captcha = ctx.session.captcha.toLowerCase() 18 | if (captcha !== code.toLowerCase()) { 19 | ctx.body = { 20 | code: -1, 21 | msg: '验证码错误' 22 | } 23 | return 24 | } 25 | return passport.authenticate('local', (user) => { 26 | if (!user) { 27 | // ctx.throw(401) 28 | ctx.body = { 29 | code: 11, 30 | msg: '账号或密码错误' 31 | } 32 | return 33 | } 34 | 35 | const token = user.generateToken() 36 | 37 | const response = user.toJSON() 38 | delete response.password 39 | ctx.body = { 40 | code: 0, 41 | token, 42 | username: response.username 43 | } 44 | ctx.login(user) 45 | })(ctx, next) 46 | } 47 | // 测试是否认证 48 | export async function testUser (ctx, next) { 49 | console.log(ctx.isAuthenticated(), '=======') 50 | if (ctx.isAuthenticated()) { 51 | ctx.body = '认证通过' 52 | } else { 53 | ctx.throw(401) 54 | ctx.body = '非法访问' 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /wu-server/src/utils/handle/index.js: -------------------------------------------------------------------------------- 1 | //全局函数 2 | 3 | import nodemailer from 'nodemailer' 4 | import smtpTransport from 'nodemailer-smtp-transport' 5 | import wellknown from 'nodemailer-wellknown' 6 | import app from '../../../bin/server' 7 | // import * as Redis from '../redis' 8 | 9 | const handle = {} 10 | 11 | //统计api访问量 12 | handle.count = async (key) => { 13 | try { 14 | return true 15 | // let num = await Redis.get(key) 16 | // let newNum = num === 'NaN' ? 0 : parseInt(num) + 1 17 | // await Redis.set(key, newNum) 18 | } catch (e) { 19 | Handle.sendEmail(e.message) 20 | } 21 | } 22 | 23 | handle.success = (data = {}) => { 24 | return { 25 | success: true, 26 | code: 0, 27 | data: data 28 | } 29 | } 30 | 31 | //报错时,发送邮件 32 | handle.sendEmail = (mes) => { 33 | 34 | const config = wellknown("QQ") 35 | config.auth = { 36 | user: '', 37 | pass: '', 38 | } 39 | 40 | const transporter = nodemailer.createTransport(smtpTransport(config)) 41 | 42 | const mailOptions = { 43 | from: '', 44 | to: '', 45 | subject: '妈的又出Bug了,赶紧去调。', 46 | text: '', 47 | html: mes, 48 | } 49 | 50 | if (app.env === 'production') { 51 | transporter.sendMail(mailOptions, function(error, info){ 52 | if(error){ 53 | console.log(error) 54 | } 55 | else { 56 | console.log('Message sent: ' + info.response) 57 | } 58 | 59 | }) 60 | } 61 | 62 | } 63 | 64 | 65 | 66 | 67 | module.exports = handle 68 | -------------------------------------------------------------------------------- /wyfReader/ios/wyfReader/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import 13 | #import 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | NSURL *jsCodeLocation; 20 | 21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 22 | 23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 24 | moduleName:@"wyfReader" 25 | initialProperties:nil 26 | launchOptions:launchOptions]; 27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 28 | 29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 30 | UIViewController *rootViewController = [UIViewController new]; 31 | rootViewController.view = rootView; 32 | self.window.rootViewController = rootViewController; 33 | [self.window makeKeyAndVisible]; 34 | return YES; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /wyfReader/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wyf-reader", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start", 7 | "test": "jest", 8 | "prettier": "prettier --write --single-quote --no-semi --trailing-comma es5 --print-width 80 \"app/**/*.js\"", 9 | "lint": "eslint app", 10 | "format": "yarn prettier && yarn lint -- --fix", 11 | "precommit": "yarn format" 12 | }, 13 | "dependencies": { 14 | "antd-mobile": "^2.1.1", 15 | "axios": "^0.17.1", 16 | "dva-core": "^0.1.3", 17 | "dva-loading": "^1.0.4", 18 | "rc-form": "^2.1.7", 19 | "react": "16.0.0", 20 | "react-native": "0.50.4", 21 | "react-native-device-info": "^0.13.0", 22 | "react-native-svg": "^6.0.1-rc.3", 23 | "react-native-swipeout": "^2.3.3", 24 | "react-navigation": "^1.0.0-beta.11", 25 | "react-redux": "^5.0.6", 26 | "redux-persist": "^4.8.3" 27 | }, 28 | "devDependencies": { 29 | "babel-eslint": "^7.2.3", 30 | "babel-jest": "21.2.0", 31 | "babel-plugin-import": "^1.6.3", 32 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 33 | "babel-preset-react-native": "4.0.0", 34 | "eslint": "^4.4.1", 35 | "eslint-config-airbnb": "^15.1.0", 36 | "eslint-config-prettier": "^2.3.0", 37 | "eslint-plugin-babel": "^4.1.2", 38 | "eslint-plugin-import": "^2.7.0", 39 | "eslint-plugin-jsx-a11y": "^5.1.1", 40 | "eslint-plugin-prettier": "^2.1.2", 41 | "eslint-plugin-react": "^7.2.0", 42 | "husky": "^0.14.3", 43 | "jest": "21.2.1", 44 | "prettier": "^1.5.3", 45 | "react-test-renderer": "16.0.0" 46 | }, 47 | "jest": { 48 | "preset": "react-native" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /wyfReader/.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore unexpected extra "@providesModule" 9 | .*/node_modules/.*/node_modules/fbjs/.* 10 | 11 | ; Ignore duplicate module providers 12 | ; For RN Apps installed via npm, "Libraries" folder is inside 13 | ; "node_modules/react-native" but in the source repo it is in the root 14 | .*/Libraries/react-native/React.js 15 | 16 | ; Ignore polyfills 17 | .*/Libraries/polyfills/.* 18 | 19 | [include] 20 | 21 | [libs] 22 | node_modules/react-native/Libraries/react-native/react-native-interface.js 23 | node_modules/react-native/flow/ 24 | 25 | [options] 26 | emoji=true 27 | 28 | module.system=haste 29 | 30 | munge_underscores=true 31 | 32 | module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub' 33 | 34 | suppress_type=$FlowIssue 35 | suppress_type=$FlowFixMe 36 | suppress_type=$FlowFixMeProps 37 | suppress_type=$FlowFixMeState 38 | suppress_type=$FixMe 39 | 40 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) 41 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ 42 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy 43 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 44 | 45 | unsafe.enable_getters_and_setters=true 46 | 47 | [version] 48 | ^0.56.0 49 | -------------------------------------------------------------------------------- /wyfReader/app/utils/request.js: -------------------------------------------------------------------------------- 1 | // import axios from 'axios' 2 | // import { Toast } from 'antd-mobile' 3 | // // let checkStatus=(response)=>{ 4 | // // if (response.status >= 200 && response.status < 300) { 5 | // // return response; 6 | // // } 7 | // // const error = new Error(response.statusText); 8 | // // error.response = response; 9 | // // throw error; 10 | // // } 11 | 12 | // const handledata=(data)=>{ 13 | // if(!data) data={ msg: '研发GG正在加班修复中,请您稍后再试' } 14 | // if(data.code === 0) { 15 | // Toast.hide() 16 | // // if(data.msg) Toast.success('操作成功',4); 17 | // return data 18 | // } 19 | // // else if(data.code == 401 || data.code == 11){ 20 | // // if(data.msg) Toast.fail('未绑定广发通账号', 2); 21 | // // } 22 | 23 | // Toast.hide() 24 | // return data 25 | 26 | // } 27 | 28 | // const handleError=(err)=>{ 29 | // Toast.hide() 30 | // Toast.fail(err.msg||'火星网络传输慢,下拉返回地球哦~',2) 31 | // } 32 | 33 | // /** 34 | // * @param {string} url The URL we want to request 35 | // * @param {object} [options] The options we want to pass to "fetch" 36 | // * @return {object} An object containing either "data" or "err" 37 | // */ 38 | 39 | // export default async function request(url, options) { 40 | // const path = `http://localhost:5000${url}` 41 | // // Toast.loading('Loading...',10); 42 | // const response = await fetch(path, {...options,credentials:'include'}) 43 | // try { 44 | // const data = await response.json() 45 | // handledata(data) 46 | // const ret = { 47 | // data 48 | // } 49 | // return ret 50 | // } catch (err) { 51 | // handleError(err) 52 | // } 53 | // } -------------------------------------------------------------------------------- /wyfReader/app/models/reader.js: -------------------------------------------------------------------------------- 1 | import { Toast } from 'antd-mobile' 2 | import { createAction, NavigationActions } from '../utils' 3 | import * as authService from '../services/auth' 4 | import * as services from '../services/app' 5 | 6 | export default { 7 | namespace: 'reader', 8 | state: { 9 | }, 10 | reducers: { 11 | receiveRenderChapters(state, { payload: { id } }) { 12 | return { ...state, id } 13 | }, 14 | receiveFirstChapters(state, { payload: { firstChapter } }) { 15 | return { ...state, firstChapter } 16 | }, 17 | receiveChapters(state, { payload: { chapter } }) { 18 | return { ...state, chapter } 19 | }, 20 | receiveDirectory(state, { payload: { directory } }) { 21 | return { ...state, directory } 22 | }, 23 | }, 24 | effects: { 25 | *getFirstRenderChapters({ payload: { id, num } }, { call, put }) { 26 | const { data } = yield call(services.getFirstRenderChapters, id, num) 27 | yield put({ 28 | type: 'receiveFirstChapters', 29 | payload: { 30 | firstChapter: data.data.response 31 | } 32 | }) 33 | }, 34 | *getChapters({ payload: { id, num } }, { call, put }) { 35 | const { data } = yield call(services.getChapters, id, num) 36 | yield put({ 37 | type: 'receiveChapters', 38 | payload: { 39 | chapter: data.data.response 40 | } 41 | }) 42 | }, 43 | *getDirectory({ payload: { id, order } }, { call, put }) { 44 | const { data } = yield call(services.getDirectory, id, order) 45 | yield put({ 46 | type: 'receiveDirectory', 47 | payload: { 48 | directory: data.data.chapters 49 | } 50 | }) 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /wyfReader/ios/wyfReader/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleIconFile 6 | 7 | NSAppTransportSecurity 8 | 9 | NSAllowsArbitraryLoads 10 | 11 | 12 | LSApplicationCategoryType 13 | 14 | CFBundleGetInfoString 15 | 16 | CFBundleDevelopmentRegion 17 | en 18 | CFBundleDisplayName 19 | wyfReader 20 | CFBundleExecutable 21 | $(EXECUTABLE_NAME) 22 | CFBundleIdentifier 23 | $(PRODUCT_BUNDLE_IDENTIFIER) 24 | CFBundleInfoDictionaryVersion 25 | 6.0 26 | CFBundleName 27 | $(PRODUCT_NAME) 28 | CFBundlePackageType 29 | APPL 30 | CFBundleShortVersionString 31 | 1.0 32 | CFBundleSignature 33 | ???? 34 | CFBundleVersion 35 | 1 36 | LSRequiresIPhoneOS 37 | 38 | NSLocationWhenInUseUsageDescription 39 | 40 | UILaunchStoryboardName 41 | LaunchScreen 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | UISupportedInterfaceOrientations 47 | 48 | UIInterfaceOrientationPortrait 49 | UIInterfaceOrientationLandscapeLeft 50 | UIInterfaceOrientationLandscapeRight 51 | 52 | UIViewControllerBasedStatusBarAppearance 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /wu-server/bin/server.js: -------------------------------------------------------------------------------- 1 | import Koa from 'koa' 2 | import bodyParser from 'koa-bodyparser' 3 | import convert from 'koa-convert' 4 | import logger from 'koa-logger' 5 | import mongoose from 'mongoose' 6 | import session from 'koa-generic-session' 7 | import passport from '../config/passport' 8 | import mount from 'koa-mount' 9 | import serve from 'koa-static' 10 | 11 | import config from '../config' 12 | import handle from '../src/utils/handle' 13 | import { errorMiddleware } from '../src/middleware' 14 | 15 | // 性能监控 16 | // const easyMonitor = require('easy-monitor') 17 | // easyMonitor({ 18 | // cluster: true, 19 | // bootstrap: 'embrace', 20 | // project_name: 'wu-server', 21 | // /** 22 | // @param {string} tcp_host 填写你部署的 dashboard 进程所在的服务器 ip 23 | // @param {number} tcp_port 填写你部署的 dashboard 进程所在的服务器 端口 24 | // **/ 25 | // embrace: { 26 | // tcp_host: '127.0.0.1', 27 | // tcp_port: 26666 28 | // } 29 | // }) 30 | 31 | global.Handle = handle 32 | 33 | const app = new Koa() 34 | app.keys = [config.session] 35 | 36 | mongoose.Promise = global.Promise 37 | mongoose.connect(config.database) 38 | 39 | app.use(convert(logger())) 40 | app.use(bodyParser()) 41 | app.use(convert(session())) 42 | app.use(errorMiddleware()) 43 | 44 | app.use(convert(mount('/docs', serve(`${process.cwd()}/docs`)))) 45 | 46 | // require('../config/passport') 47 | app.use(passport.initialize()) 48 | app.use(passport.session()) 49 | 50 | const modules = require('../src/modules') 51 | modules(app) 52 | 53 | app.listen(config.port, () => { 54 | console.log(`Server started on ${config.port}`) 55 | }) 56 | 57 | // 每天凌晨准时更新小说爬虫 58 | // const UpdateNovel = require('../src/utils/updateNovel') 59 | // if (app.env === 'production') { 60 | // UpdateNovel.update() 61 | // } 62 | require('../src/utils/schedule/updateChapter') 63 | 64 | export default app 65 | -------------------------------------------------------------------------------- /wyfReader/ios/wyfReader-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UIViewControllerBasedStatusBarAppearance 38 | 39 | NSLocationWhenInUseUsageDescription 40 | 41 | NSAppTransportSecurity 42 | 43 | 44 | NSExceptionDomains 45 | 46 | localhost 47 | 48 | NSExceptionAllowsInsecureHTTPLoads 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /wyfReader/android/app/BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | lib_deps = [] 12 | 13 | for jarfile in glob(['libs/*.jar']): 14 | name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')] 15 | lib_deps.append(':' + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | 21 | for aarfile in glob(['libs/*.aar']): 22 | name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')] 23 | lib_deps.append(':' + name) 24 | android_prebuilt_aar( 25 | name = name, 26 | aar = aarfile, 27 | ) 28 | 29 | android_library( 30 | name = "all-libs", 31 | exported_deps = lib_deps, 32 | ) 33 | 34 | android_library( 35 | name = "app-code", 36 | srcs = glob([ 37 | "src/main/java/**/*.java", 38 | ]), 39 | deps = [ 40 | ":all-libs", 41 | ":build_config", 42 | ":res", 43 | ], 44 | ) 45 | 46 | android_build_config( 47 | name = "build_config", 48 | package = "com.wyfreader", 49 | ) 50 | 51 | android_resource( 52 | name = "res", 53 | package = "com.wyfreader", 54 | res = "src/main/res", 55 | ) 56 | 57 | android_binary( 58 | name = "app", 59 | keystore = "//android/keystores:debug", 60 | manifest = "src/main/AndroidManifest.xml", 61 | package_type = "debug", 62 | deps = [ 63 | ":app-code", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /wu-server/src/models/users.js: -------------------------------------------------------------------------------- 1 | import mongoose from 'mongoose' 2 | import bcrypt from 'bcrypt' 3 | import config from '../../config' 4 | import jwt from 'jsonwebtoken' 5 | 6 | const User = new mongoose.Schema({ 7 | type: { type: String, default: 'User' }, 8 | name: { type: String }, 9 | email: { type: String }, 10 | username: { type: String }, 11 | password: { type: String }, 12 | uuid: { type: String }, 13 | meta: { 14 | createAt: { 15 | type: Date, 16 | default: Date.now() 17 | }, 18 | update: { 19 | type: Date, 20 | default: Date.now() 21 | } 22 | } 23 | }) 24 | 25 | User.pre('save', function preSave (next) { 26 | const user = this 27 | 28 | if (this.isNew) { 29 | this.meta.createAt = this.meta.update = Date.now() 30 | } else { 31 | this.meta.update = Date.now 32 | } 33 | if (this.uuid && !this.username) { 34 | return next() 35 | } 36 | new Promise((resolve, reject) => { 37 | bcrypt.genSalt(10, (err, salt) => { 38 | if (err) { 39 | return reject(err) 40 | } 41 | resolve(salt) 42 | }) 43 | }) 44 | .then(salt => { 45 | bcrypt.hash(user.password, salt, (err, hash) => { 46 | if (err) { 47 | throw new Error(err) 48 | } 49 | user.password = hash 50 | return next() 51 | }) 52 | }) 53 | .catch(err => { 54 | next(err) 55 | }) 56 | }) 57 | 58 | User.methods.validatePassword = function validatePassword(password) { 59 | const user = this 60 | return new Promise((resolve, reject) => { 61 | bcrypt.compare(password, user.password, (err, isMatch) => { 62 | if (err) { 63 | return reject(err) 64 | } 65 | 66 | resolve(isMatch) 67 | }) 68 | }) 69 | } 70 | 71 | User.methods.generateToken = function generateToken() { 72 | const user = this 73 | 74 | return jwt.sign({ id: user.id }, config.token) 75 | }; 76 | 77 | export default mongoose.model('user', User) 78 | -------------------------------------------------------------------------------- /wyfReader/app/containers/Account.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { StyleSheet, View, Image, Text, Button, AsyncStorage } from 'react-native' 3 | import { connect } from 'react-redux' 4 | import { NavigationActions } from '../utils' 5 | 6 | @connect() 7 | class Account extends Component { 8 | static navigationOptions = { 9 | title: 'Account', 10 | tabBarLabel: 'Account', 11 | tabBarIcon: ({ focused, tintColor }) => 12 | , 16 | } 17 | constructor(props) { 18 | super(props) 19 | this.state = { 20 | username: null 21 | } 22 | } 23 | componentWillMount() { 24 | let that = this 25 | AsyncStorage.getItem('username').then((username) => { 26 | that.setState({ 27 | username 28 | }) 29 | }) 30 | } 31 | gotoLogin = () => { 32 | this.props.dispatch(NavigationActions.navigate({ routeName: 'Login' })) 33 | } 34 | loginout = () => { 35 | AsyncStorage.removeItem('username'); 36 | AsyncStorage.removeItem('userToken'); 37 | this.props.dispatch({type: 'app/receiveToken', payload:{token: ''}}) 38 | this.props.dispatch({type: 'app/getBookList', payload:{}}) 39 | this.setState({ 40 | username: null 41 | }) 42 | } 43 | render() { 44 | console.log(this.state.username,888) 45 | return ( 46 | 47 | {this.state.username ? 欢迎你,{this.state.username}