# Hacking

VEVN is a Bottle (WSGI) server that serves the VEVN website.

A primary design tenet of VEVN is to process the bulk of all requests server-side, with as little client-side work being done as possible. This approach prefers that a button POST request something to the server rather than doing something with JavaScript.

Another tenet is to keep the the amount of data is sent through request to a minimum in order to ensure fast loading times and to minimize security risks.

## Project structure

- db/: Contains a json with the credentials for all users (passwords hashed) and un surveys/ a directory for each survey containing its data
- routes/: Routes for each individual page. Routes code behaviour for each response type for a given page and renders using the template and style of the same name
- views/: Bottle templates that the routes render pages onto. base.tpl is the base template for all pages
- adapter.wsgi: Provides httpd the bottle object named "application" it expects
- readingparser.py: Various functions related to parsing survey readings
- security.py: Security functions like checking login data, hashing and checking passwords, etc.
- surveyparser.py: Functions to create and parse surveys
- vevn.py: Merges all routes from routes/ into a single bottle object

## Surveys

Surveys are stored in a directory in db/ named as the survey is named. Within this directory many files that the server needs are stored, .csv and .json files. Some are redundant information stored different data-structures in order to speed up certain operations.

- raw.csv: Mostly untouched file originally uploded by the user. This file is used to parse out the actual survey .csv but is kept because the user may request it be re-parsed with different parameters, such as a different list of multiple-choice questions. This option is considered not useful and will eventually be removed, thus making keeping the raw file useless
- survey.csv: Parsed raw .csv file. Empty rows and columns are removed, quesitons "categories" are removed (only second header row from raw remains), multiple-choice questions are grouped with answers ;-separated, fields are sanitized
- metadata.json: A file generated alongside the parsing of raw.csv into survey.csv with either redundant information from survey.csv to speed up calculations or information lost in parsing that is worth keeping somewhere. Has a dictionary with categories information removed in the parsing, a list of the questions which are multiple-choice and a dictionary with every possible unique answer to each question, very important for speeding up the filtering interface in /survey
- properties.json: Properties of the survey. Each explained in more detail below
- readings.json: Readings of the survey. Each explained in more detail below

### Properties

- anon-matches: When filtering, the minimum amount of matches to consider the results non-sensitive
- touchpoint-columns: Columns which are from multiple-choice questions
- guests: How many participants are guests
- hidden-columns: Which columns should be hidden from non-admin users
- notes: Description, comments or notes that are show in /survey
- public: Whether a survey can be viewed by non-registered users or not

### Readings

Each survey can have any number of readings. Admins can edit, add or remove these in /edit/readings/"survey name".

There are different type of reading:
- Loyalty: Two component reading, (1) eNPS score from numerical response to a question and (2) multiple-choice response aggregation, sorted by % response total
- Agreement: Agree-disagree scale response aggregation to questions, sorted by % "agree" response
- Satisfaction: Satisfactory-unsatisfactory scale response aggreagation to a single question, sorted satisfactory % to unsatisfactory %

## Users

User credentials are stored as a dictionary in db/users.json. Passwords are hashed and salt is stored along them. Surveys each user is allowed to view are stored too. Admins have the admin flag true. The only way to register new admins currently is to manually edit the .json. Eventually a non-exposed function in security.py will allow you to do this. 
