Browse Source

Started rest server.

Tomislav Cvetic 6 years ago
parent
commit
a66f711c0f

+ 1 - 1
.babelrc

@@ -1,4 +1,4 @@
 {
   "plugins": [["transform-object-rest-spread", {"useBuiltIns": true}]],
-  "presets": ["latest"]
+  "presets": ["env"]
 }

File diff suppressed because it is too large
+ 2221 - 312
package-lock.json


+ 3 - 2
package.json

@@ -5,9 +5,9 @@
   "dependencies": {
     "babel-core": "^6.25.0",
     "babel-polyfill": "^6.23.0",
-    "babel-preset-latest": "^6.24.1",
+    "babel-preset-env": "^1.7.0",
     "babel-register": "^6.24.1",
-    "bcrypt": "^1.0.2",
+    "bcrypt": "^2.0.1",
     "blob": "^0.0.4",
     "body-parser": "^1.17.2",
     "bootstrap": "3",
@@ -31,6 +31,7 @@
     "xlsx": "^0.10.4"
   },
   "devDependencies": {
+    "bhttp": "^1.2.4",
     "html-inline": "^1.2.0",
     "react-bootstrap": "^0.31.0",
     "react-scripts": "^1.0.7"

+ 48 - 0
public/index.html

@@ -22,6 +22,54 @@
     <title>SZTM Excel</title>
   </head>
   <body>
+    <header>
+      <nav>
+        <a href="players/">Spieler</a> |
+        <a href="draws/">Tableaux</a> |
+        <a href="calendar/">Spielplan</a> |
+        <a href="sms/">SMS</a> |
+        <a href="email/">E-Mail</a>
+      </nav>
+    </header>
+    <aside>
+      <h4>Epcot Center</h4>
+      <p>The Epcot Center is a theme park in Disney World, Florida.</p>
+    </aside>
+    <section>
+      <h1>WWF</h1>
+      <p>The world wide fund for nature (WWF) is...</p>
+    </section>
+    <main>
+      <article>
+        <h1>What does WWF do</h1>
+        <p>WWF's mission is to stop the degradation of our planet's natural environment,
+    and build a future in which humans live in harmony with nature.</p>
+        <figure>
+          <img src="pic_mountain.jpg" alt="The Pulpit Rock" width="304" height="228">
+          <figcaption>Fig1. - The Pulpit Rock, Norway.</figcaption>
+        </figure>
+      </article>
+      <article>
+        <header>
+          <h1>What Does WWF Do?</h1>
+          <p>WWF's mission:</p>
+        </header>
+        <p>WWF's mission is to stop the degradation of our planet's natural environment,
+        and build a future in <mark>which humans</mark> live in harmony with nature.</p>
+        <details>
+          <summary>Click this...</summary>
+          ...to show or hide.
+          <time datetime="2008-02-14 20:00">Valentines day</time>
+        </details>
+        <footer>
+          <p>Posted by: Hege Refsnes</p>
+          <p>Contact information: <a href="mailto:someone@example.com">
+          someone@example.com</a>.</p>
+        </footer>
+      </article>
+    </main>
+    <footer></footer>
+
     <noscript>
       You need to enable JavaScript to run this app.
     </noscript>

+ 89 - 0
public/semantic.html

@@ -0,0 +1,89 @@
+<!doctype html>
+<html lang="de-ch">
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+    <meta name="theme-color" content="#000000">
+    <!--
+      manifest.json provides metadata used when your web app is added to the
+      homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
+    -->
+    <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
+    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
+    <!--
+      Notice the use of %PUBLIC_URL% in the tags above.
+      It will be replaced with the URL of the `public` folder during the build.
+      Only files inside the `public` folder can be referenced from the HTML.
+
+      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
+      work correctly both with client-side routing and a non-root public URL.
+      Learn how to configure a non-root public URL by running `npm run build`.
+    -->
+    <title>SZTM Excel</title>
+  </head>
+  <body>
+    <h1>Semantic Elements in HTML5</h1>
+    <a>https://www.w3schools.com/html/html5_semantic_elements.asp</a>
+    <header>
+      <nav>
+        <a href="/html/">HTML</a> |
+        <a href="/css/">CSS</a> |
+        <a href="/js/">JavaScript</a> |
+        <a href="/jquery/">jQuery</a>
+      </nav>
+    </header>
+    <aside>
+      <h4>Epcot Center</h4>
+      <p>The Epcot Center is a theme park in Disney World, Florida.</p>
+    </aside>
+    <section>
+      <h1>WWF</h1>
+      <p>The world wide fund for nature (WWF) is...</p>
+    </section>
+    <main>
+      <article>
+        <h1>What does WWF do</h1>
+        <p>WWF's mission is to stop the degradation of our planet's natural environment,
+    and build a future in which humans live in harmony with nature.</p>
+        <figure>
+          <img src="pic_mountain.jpg" alt="The Pulpit Rock" width="304" height="228">
+          <figcaption>Fig1. - The Pulpit Rock, Norway.</figcaption>
+        </figure>
+      </article>
+      <article>
+        <header>
+          <h1>What Does WWF Do?</h1>
+          <p>WWF's mission:</p>
+        </header>
+        <p>WWF's mission is to stop the degradation of our planet's natural environment,
+        and build a future in <mark>which humans</mark> live in harmony with nature.</p>
+        <details>
+          <summary>Click this...</summary>
+          ...to show or hide.
+          <time datetime="2008-02-14 20:00">Valentines day</time>
+        </details>
+        <footer>
+          <p>Posted by: Hege Refsnes</p>
+          <p>Contact information: <a href="mailto:someone@example.com">
+          someone@example.com</a>.</p>
+        </footer>
+      </article>
+    </main>
+    <footer></footer>
+
+    <noscript>
+      You need to enable JavaScript to run this app.
+    </noscript>
+    <div id="root"></div>
+    <!--
+      This HTML file is a template.
+      If you open it directly in the browser, you will see an empty page.
+
+      You can add webfonts, meta tags, or analytics to this file.
+      The build step will place the bundled scripts into the <body> tag.
+
+      To begin the development, run `npm start` or `yarn start`.
+      To create a production bundle, use `npm run build` or `yarn build`.
+    -->
+  </body>
+</html>

+ 16 - 0
src/restServer/README.md

@@ -0,0 +1,16 @@
+## restServer
+
+### What is it good for
+The REST server is responsible for fetching player lists and calendars from the Swisstennis site and saving the data in a database for faster access.
+
+### Steps
+1. Log in to REST server
+2. Enter login data for swisstennis
+3. Fetch PlayerList and Calendar
+4. Check if there is a change
+5. Save new version in database
+6. Serve the following information
+    * Login status with swisstennis
+    * Player list 
+    * Calendar
+    * Version list

+ 90 - 61
src/restServer/api.js

@@ -1,12 +1,11 @@
 import express from 'express'
 import bodyParser from 'body-parser'
-import morgan from 'morgan'
 import mongoose from 'mongoose'
-import passport from 'passport'
-import jwt from 'jwt-simple'
+import bcrypt from 'bcrypt'
+import jwt from 'jsonwebtoken'
+import bhttp from 'bhttp'
 
 import config from './config/database'
-import { configPassport } from './config/passport'
 import User from './models/user'
 
 const port = process.env.PORT || 8080
@@ -14,85 +13,115 @@ const app = express()
 
 app.use(bodyParser.urlencoded({ extended: false }))
 app.use(bodyParser.json())
-app.use(morgan('dev'))
-app.use(passport.initialize())
 
 app.get('/', (req, res) => {
   res.send(`Express API at http://localhost:${port}/api`)
 })
 
 mongoose.connect(config.database)
-configPassport(passport)
 const apiRoutes = express.Router()
 
-apiRoutes.post('/signup', (req, res) => {
-  if (!req.body.name || !req.body.password) {
-    res.json({ success: false, msg: 'Please pass name and password.' })
-  } else {
-    const newUser = new User({
-      name: req.body.name,
-      password: req.body.password
-    })
-    newUser.save(err => {
-      if (err) {
-        return res.json({ success: false, msg: 'Username already exists.' })
-      }
-      res.json({ success: true, msg: 'Successfully created user.' })
-    })
+apiRoutes.post('/login', (req, res) => {
+  const { username, password } = req.body
+  if (!username || !password) {
+    res.status(400).json({ success: false, msg: 'Parameters name and password are required' })
+    return
   }
-})
 
-apiRoutes.post('/authenticate', (req, res) => {
-  User.findOne({ name: req.body.name }, (err, user) => {
+  User.findOne({ name: username }, (err, user) => {
     if (err) {
-      throw err
+      res.status(400).json({ success: false, msg: err })
+      return
     }
     if (!user) {
-      res.send({ success: false, msg: 'Authentication failed. User not found.' })
+      res.status(400).json({ success: false, msg: 'Authentication failed. User not found.' })
+      return
+    }
+    console.log(password, user)
+    if (!bcrypt.compareSync(password, user.password)) {
+      res.status(400).json({ success: false, msg: 'Authentication failed. Wrong password' })
     } else {
-      user.comparePassword(req.body.password, (err, isMatch) => {
-        if (isMatch && !err) {
-          const token = jwt.encode(user, config.secret)
-          res.json({ success: true, token: `JWT ${token}` })
-        } else {
-          res.send({ soccess: false, msg: 'Authentication failed. Wrong password.' })
-        }
-      })
+      const token = jwt.sign({
+        exp: Math.floor(Date.now() / 1000) + 24*60*60,
+        data: user
+      }, "bugu")
+      res.json({ success: true, token })
     }
   })
 })
 
-apiRoutes.get('/memberinfo', passport.authenticate('jwt', { session: false }), (req, res) => {
-  const token = getToken(req.headers)
-  if (token) {
-    const decoded = jwt.decode(token, config.secret)
-    User.findOne({ name: decoded.name }, (err, user) => {
-      if (err) {
-        throw err
-      }
-      if (!user) {
-        return res.status(403).send({ success: false, msg: 'Authentication failed. User not found.' })
-      } else {
-        res.json({ success: true, msg: `Welcome in the member area, ${user.name}!` })
-      }
+const swisstennis = express.Router()
+swisstennis.post('/login', async (req, res) => {
+  const { username, tournament, password } = req.body
+  const session = bhttp.session()
+  if (!username || !password) {
+    res.status(400).json({ success: false, msg: 'Parameters username and password are required' })
+    return
+  }
+  const loginData = {
+    Lang: 'D',
+    id: username,
+    pwd: password,
+    Tournament: ''
+  }
+  try {
+    console.log('attempting to fetch login page.')
+    const reqPage = await session.get('https://comp.swisstennis.ch/advantage/servlet/MyTournamentList?Lang=D')
+    console.log('successfully fetched login page.')
+  } catch (error) {
+    console.log('Error fetching login page.', error)
+    res.status(400).json({
+      msg: error
     })
-  } else {
-    return res.status(403).send({ success: false, msg: 'No token provided.' })
+    return
   }
-})
-
-function getToken (headers) {
-  if (headers && headers.authorization) {
-    const parted = headers.authorization.split(' ')
-    if (parted.length === 2) {
-      return parted[1]
-    } else {
-      return null
+  try {
+    console.log('attempting to login.', loginData)
+    const loginPage = await session.post('https://comp.swisstennis.ch/advantage/servlet/Login', loginData)
+    const dec = loginPage.body.toString()
+    console.log('received a page.')
+    if (dec.includes('Zugriff verweigert')) {
+      console.log('failed to log in')
+      res.status(400).json({
+        msg: dec
+      })
+      return
     }
-  } else {
-    return null
+  } catch (error) {
+    console.log('Error logging in.', error)
+    res.status(400).json({
+      msg: error
+    })
+    return
   }
-}
+  try {
+    console.log('attempting to fetch my tournaments.')
+    const myTournamentsPage = await session.get('https://comp.swisstennis.ch/advantage/servlet/MyTournamentList?Lang=D')
+    const mdec = myTournamentsPage.body.toString()
+    let match
+    const matches = {}
+    const regexp = /<a href=".*ProtectedDisplayTournament.*tournament=Id(\d+)">([^<]+)<\/a>/gm
+    
+    do {
+      match = regexp.exec(mdec)
+      console.log(match)
+      if (match) {
+        matches[match[1]] = match[2]
+      }
+    } while (match)
+    res.json({
+      matches
+    })
+  } catch (error) {
+    console.log('Error fetching tournaments.')
+    res.status(400).json({
+      msg: error
+    })
+    return
+  }  
+})
+
+apiRoutes.use('/swisstennis', swisstennis)
 
 app.use('/api', apiRoutes)
 

+ 0 - 23
src/restServer/config/passport.js

@@ -1,23 +0,0 @@
-import { Strategy, ExtractJwt } from 'passport-jwt'
-import User from '../models/user'
-import config from '../config/database'
-
-function configPassport (passport) {
-  const opts = {}
-  opts.secretOrKey = config.secret
-  opts.jwtFromRequest = ExtractJwt.fromAuthHeader()
-  passport.use(new Strategy(opts, (jwtPayload, done) => {
-    User.findOne({ id: jwtPayload.id }, (err, user) => {
-      if (err) {
-        return done(err, false)
-      }
-      if (user) {
-        done(null, user)
-      } else {
-        done(null, false)
-      }
-    })
-  }))
-}
-
-export { configPassport }

+ 3 - 3
src/scraper/state.js

@@ -78,7 +78,7 @@ function * swisstennisLogin (action) {
 
   const requestOptions = {
     uri: 'https://comp.swisstennis.ch/advantage/servlet/MyTournamentList?Lang=D',
-    // method: 'GET',
+    //method: 'GET',
     jar,
     headers: {
       Host: 'comp.swisstennis.ch',
@@ -131,7 +131,7 @@ function * swisstennisLogin (action) {
     const reqPage = yield call(rp.get, requestOptions)
     console.log('successfully fetched login page.', reqPage, jar)
   } catch (error) {
-    console.log('Error fetching login page.', jar)
+    console.log('Error fetching login page.', jar, error)
     yield put(actions.loginFailure(error))
     return
   }
@@ -146,7 +146,7 @@ function * swisstennisLogin (action) {
     }
     return
   } catch (error) {
-    console.log('successfully logged in.', error)
+    console.log('Error logging in.', error)
     return
   }
   try {

+ 24 - 0
src/swisstennis/swisstennis.js

@@ -0,0 +1,24 @@
+/*
+Login 
+  URL: https://comp.swisstennis.ch/advantage/servlet/Login
+  Form data:
+    Lang: "D"
+    id: "1174"
+    pwd: "14959T"
+    Tournament: ""
+  Sets Cookie:
+    JSESSIONID
+    _ga:
+    _gid: 
+Tournament List
+  URL: https://comp.swisstennis.ch/advantage/servlet/MyTournamentList?Lang=D
+Tournament Display
+  URL: https://comp.swisstennis.ch/advantage/servlet/ProtectedDisplayTournament?Lang=D&tournament=Id112680
+  List of Tournaments encoded in this URL: https://comp.swisstennis.ch/advantage/servlet/DisplayEvent?eventId=480034&lang=D
+Calendar:
+  URL: https://comp.swisstennis.ch/advantage/servlet/Calendar.xls?Lang=D&tournament=Id112680&Type=Match&Inp_DateRangeFilter.fromDate=04.06.2018&Inp_DateRangeFilter.toDate=16.09.2018"
+PlayerList:
+  URL: https://comp.swisstennis.ch/advantage/servlet/PlayerList.xls?tournament=Id112680&lang=D  
+Display Draw:
+  URL: https://comp.swisstennis.ch/advantage/servlet/DisplayDraw.xls?eventId=480034&lang=D  
+ */

Some files were not shown because too many files changed in this diff