Document IndexDen dependency #237
[oweals/karmaworld.git] / README.md
1 # KarmaWorld
2 __Description__: A django application for sharing and uploading class notes.
3
4 __Copyright__: FinalsClub, a 501c3 non-profit organization
5
6 __License__: GPLv3 except where otherwise noted
7
8 __Contact__: info@karmanotes.org
9
10 v3.0 of the karmanotes.org website from the FinalsClub Foundation
11
12 # Purpose
13
14 KarmaNotes is an online database of college lecture notes.  KarmaNotes empowers college students to participate in the free exchange of knowledge. 
15
16 # Pre-Installation
17
18 ## Code
19
20 Before doing anything, you'll need the code. Grab it from github.
21
22 Clone the project from the central repo using your github account:
23
24     git clone git@github.com:FinalsClub/karmaworld.git
25
26 If you aren't using a system setup for github, then grab the project with
27 this command instead:
28
29     git clone https://github.com/FinalsClub/karmaworld.git
30
31 Generally speaking, this will create a subdirectory called `karmaworld` under
32 the directory where the `git` command was run. This git repository directory
33 will be referred to herein as `{project_root}`.
34
35 There might be some confusion as the git repository's directory will likely be
36 called `karmaworld` (this is `{project_root}`), but there is also a `karmaworld`
37 directory underneath that (`{project_root}/karmaworld`) alongside files like
38 `fabfile.py` (`{project_root}/fabfile.py`) and `README.md`
39 (`{project_root}/README.md`).
40
41 ## External Service Dependencies
42
43 Notice: This software makes use of external third party services which require
44 accounts to access the service APIs. Without these third parties available,
45 this software may require considerable overhaul.
46
47 ### Filepicker
48 This software uses [Filepicker.io](https://www.inkfilepicker.com/) for uploading
49 files. This requires an account with Filepicker.
50
51 Filepicker requires an additional third party file hosting site where it may
52 send uploaded files. For this project, we have used Amazon S3.
53
54 Filepicker will provide an API key. This is needed by the software.
55
56 ### Amazon S3
57
58 #### for Filepicker
59 This software uses [Amazon S3](http://aws.amazon.com/s3/) as a third party file
60 hosting site. The primary use case is a destination for Filepicker files. The
61 software won't directly need any S3 information for this use case; it will be
62 provided directly to Filepicker.
63
64 #### for Static File hosting
65 A secondary use case for S3 is hosting static files. The software will need to
66 update static files on the S3 bucket. In this case, the software will need the
67 S3 bucket name, access key, and secret key.
68
69 The code assumes S3 is used for static files in a production environment. To
70 obviate the need for hosting static files through S3 (noting that it still might
71 be necessary for Filepicker), a workaround was explained [in this Github ticket](https://github.com/FinalsClub/karmaworld/issues/192#issuecomment-30193617).
72
73 That workaround is repeated here. Make the following changes to
74 `{project_root}/karmaworld/settings/prod.py`:
75
76 1. comment out everything about static_s3 from imports
77 2. comment out storages from the `INSTALLED_APPS`
78 3. change `STATIC_URL` to `'/assets/'`
79 4. comment out the entire storages section (save for part of `INSTALLED_APPS` and `STATIC_URL`)
80 5. add this to the nginx config:
81
82     location /assets/ {
83         root /var/www/karmaworld/karmaworld/;
84     }
85     
86 ### IndexDen
87 KarmaNotes uses IndexDen to create a searchable index of all the notes
88 in the system. Create an free IndexDen account at [their homepage](http://indexden.com/).
89 You will be given a private URL that accesses your IndexDen account.
90 Create a file at karmaworld/secret/indexden.py, and enter your private URL, and the name
91 of the index you want KarmaNotes to use. The index will be created automatically when
92 KarmaNotes is run if it doesn't already exist. For example,
93 ```
94 PRIVATE_URL = 'http://:secretsecret@secret.api.indexden.com'
95 INDEX = 'karmanotes_something_something'
96 ```
97
98 ### Google Drive
99 This software uses [Google Drive](https://developers.google.com/drive/) to
100 convert documents to and from various file formats.
101
102 A Google Drive service account with access to the Google Drive is required. Thismay be done with a Google Apps account with administrative privileges, or ask
103 your business sysadmin.
104
105 These are the instructions to create a Google Drive service account:
106 https://developers.google.com/drive/delegation
107
108 When completed, you'll have a file called `client_secrets.json` and a p12 file
109 which is the key to access the service account. Both are needed by the software.
110
111 ### Twitter
112
113 Twitter is used to post updates about new courses. Access to the Twitter API
114 will be required for this task.
115
116 If this Twitter feature is desired, the consumer key and secret as well as the
117 access token key and secret are needed by the software.
118
119 If the required files are not found, then no errors will occur.
120
121 # Development Install
122
123 If you need to setup the project for development, it is highly recommend that
124 you grab create a development virtual machine or (if available) grab one that
125 has already been created for your site.
126
127 The *host machine* is the system which runs e.g. VirtualBox, while the
128 *virtual machine* refers to the system running inside e.g. VirtualBox. 
129
130 ## Creating a Virtual Machine by hand
131
132 Create a virtual machine with your favorite VM software. Configure the virtual
133 machine for production with the steps shown in the [Production Install](#production-install) section.
134
135 ## Creating a Virtual Machine with Vagrant
136
137 Vagrant supports a variety of virtual machine software and there is additional
138 support for Vagrant to deploy to a wider variety. However, for these
139 instructions, it is assumed Vagrant will be deployed to VirtualBox.
140
141 1. Configure external dependencies on the host machine:
142    * Under `{project_root}/karmaworld/secret/`:
143         1. Copy files with the example extension to the corresponding filename
144           without the example extension (e.g.
145           `cp filepicker.py.example filepicker.py`)
146         1. Modify those files, but ignore `db_settings.py` (Vagrant takes care of that one)
147         1. Copy the Google Drive service account p12 file to `drive.p12`
148            (this filename and location may be changed in `drive.py`)
149         1. Ensure `*.py` in `secret/` are never added to the git repo.
150            (.gitignore should help warn against taking this action)
151
152 1. Install [VirtualBox](http://www.virtualbox.com/)
153
154 1. Install [vagrant](http://www.vagrantup.com/) 1.3 or higher
155
156 1. Use Vagrant to create the virtual machine.
157    * While in `cd {project_root}`, type `vagrant up`
158
159 1. Connect to the virtual machine with `vagrant ssh`
160
161 Note:
162 Port 80 of the virtual machine will be configured as port 6659 on the host
163 system. While on the host system, fire up your favorite browser and point it at
164 `http://localhost:6659/`. This connects to your host system on port 6659, which
165 forwards to your virtual machine's web site.
166
167 ## Completing the Virtual Machine with Fabric
168
169 *Notice* Fabric might not run properly if you presently in a virtualenv.
170 `deactivate` prior to running fab commands.
171
172 1. On the virtual machine, type `cd karmanotes` to get into the code repository.
173
174 1. In the code repo of the VM, type `fab -H 127.0.0.1 first_deploy`
175
176    During this process, you will be queried to create a Django site admin.
177    Provide information. You will be asked to remove duplicate schools. Respond
178    with yes.
179
180 # Production Install
181
182 These steps are taken care of by automatic utilities. Vagrant performs the
183 first subsection of these instructions and Fabric performs the second
184 subsection. These instructions are detailed here for good measure, but should
185 not generally be needed.
186
187 1. Ensure the following are installed:
188    * `git`
189    * `7zip` (for unzipping US Department of Education files)
190    * `PostgreSQL` (server and client)
191    * `nginx`
192    * `libxslt` and `libxml2` (used by some Python libraries)
193    * `RabbitMQ` (server)
194    * `memcached`
195    * `Python`
196    * `PIP`
197    * `virtualenv`
198    * `virtualenvwrapper` (might not be needed anymore)
199    * `pdf2htmlEX`
200
201    On a Debian system supporting Apt, this can be done with:
202
203         sudo apt-get install python-pip postgresql python-virtualenv nginx \
204                              virtualenvwrapper git libxml2-dev p7zip-full \
205                              postgresql-server-dev-9.1 libxslt1-dev \
206                              libmemcached-dev python-dev rabbitmq-server
207
208         sudo add-apt-repository ppa:coolwanglu/pdf2htmlex
209         sudo apt-get install pdf2htmlex
210
211 1. Generate a PostgreSQL database and a role with read/write permissions.
212    * For Debian, these instructions are helpful: https://wiki.debian.org/PostgreSql
213
214 1. Modify configuration files.
215    * There are settings in `{project_root}/karmaworld/settings/prod.py`
216        * Most of the setting should work fine by default.
217    * There are additional configuration options for external dependencies
218      under `{project_root}/karmaworld/secret/`.
219         1. Copy files with the example extension to the corresponding filename
220           without the example extension (e.g.
221           `cp filepicker.py.example filepicker.py`)
222         1. Modify those files.
223            * Ensure `PROD_DB_USERNAME`, `PROD_DB_PASSWORD`, and `PROD_DB_NAME`
224              inside `db_settings.py` match the role, password, and database
225              generated in the previous step.
226         1. Copy the Google Drive service account p12 file to `drive.p12`
227            (this filename and location may be changed in `drive.py`)
228         1. Ensure `*.py` in `secret/` are never added to the git repo.
229            (.gitignore should help warn against taking this action)
230
231 1. Make sure that /var/www exists, is owned by the www-data group, and that
232    the desired user is a member of the www-data group.
233
234 1. Configure nginx with a `proxy_pass` to port 8000 (or whatever port gunicorn
235    will be running the site on) and any virtual hosting that is desired.
236    Here is an example server file to put into `/etc/nginx/sites-available/`
237
238         server {
239             listen 80;
240             # don't do virtual hosting, handle all requests regardless of header
241             server_name "";
242             client_max_body_size 20M;
243         
244             location / {
245                 # pass traffic through to gunicorn
246                 proxy_pass http://127.0.0.1:8000;
247             }
248         }
249
250 1. Configure the system to start supervisor on boot. An init script for
251    supervisor is in the repo at `{project_root}/karmaworld/confs/supervisor`.
252    `update-rc.d supervisor defaults` is the Debian command to load the init
253    script into the correct directories.
254
255 1. Make sure `{project_root)/var/log` and `{project_root}/var/run` exist and
256    may be written to, or else put the desired logging and run file paths into
257    `{project_root}/confs/prod/supervisord.conf`
258
259 1. Create a virtualenv under `/var/www/karmaworld/venv`
260
261 1. Change into the virtualenv with `. /var/www/karmaworld/venv/bin/activate`.
262    Within the virtualenv:
263
264     1. Update the Python depenencies with `pip -i {project_root}/reqs/prod.txt`
265     
266     1. Setup the database with `python {project_root}/manage.py syncdb --migrate`
267
268     1. Collect static resources and put them in the static hosting location with
269        `python {project_root}/manage.py collect_static`
270
271 1. The database needs to be populated with schools. A list of accredited schools
272    may be found on the US Department of Education website:
273    http://ope.ed.gov/accreditation/GetDownloadFile.aspx
274
275    Alternatively, use the built-in scripts while in the virtualenv:
276
277    1. Fetch USDE schools with
278       `python {project_root}/manage.py fetch_usde_csv ./schools.csv`
279
280    1. Upload the schools into the database with
281       `python {project_root}/manage.py import_usde _csv ./schools.csv`
282
283    1. Clean up redundant information with
284       `python {project_root}/manage.py sanitize_usde_schools`
285
286 1. Startup `supervisor`, which will run `celery` and `gunicorn`. This may be
287    done from within the virtualenv by typing
288    `python {project_root}/manage.py start_supervisord`
289
290 1. If everything went well, gunicorn should be running the website on port 8000
291    and nginx should be serving gunicorn on port 80.
292
293 # Accessing the Vagrant Virtual Machine
294
295 ## Connecting to the VM via SSH
296 If you have installed a virtual machine using `vagrant up`, you can connect
297 to it by running `vagrant ssh` from `{project_root}`.
298
299 ## Connecting to the development website on the VM
300 To access the website running on the VM, point your browser at
301 http://localhost:6659/ using your host computer.
302
303 Port 6659 on your local machine is set to forward to the VM's port 80.
304
305 Fun fact: 6659 was chosen because of OM (sanskrit) and KW (KarmaWorld) on a
306 phone: 66 59.
307
308 ## Updating the VM code repository
309 Once connected to the virtual machine by SSH, you will see `karmaworld` in
310 the home directory. That is the `{project_root}` in the virtual machine.
311
312 `cd karmaworld` and then use `git fetch; git merge` and/or `git pull origin` as
313 desired.
314
315 The virtual machine's code repository is set to use your host machine's
316 local repository as the origin. So if you make changes locally and commit them,
317 without pushing them anywhere, your VM can pull those changes in for testing.
318
319 This may seem like duplication. It is. The duplication allows your host machine
320 to maintain git credentials and manage repository access control so that your
321 virtual machine doesn't need sensitive information. Your virtual machine simply
322 pulls from the local repository on your local file system without needing
323 credentials, etc.
324
325 ## Deleting the Virtual Machine
326 If you want to start a fresh virtual machine or simply remove the virtual
327 machine from your hard drive, Vagrant has a command for that. While in 
328 `{project_root}` of the host system, type `vagrant destroy` and confirm with
329 `y`. This will remove the VM from your hard drive.
330
331 If you wanted a fresh VM, the next step is to run `vagrant up`, which will
332 start a brand new VM (since the old one is gone).
333
334 ## Other Vagrant commands
335 Please see [vagrant documentation](http://docs.vagrantup.com/v2/cli/index.html)
336 for more information on how to use the vagrant CLI to manage your development
337 VM.
338
339 # Django Database management
340
341 ## South
342
343 We have setup Django to use
344 [south](http://south.aeracode.org/wiki/QuickStartGuide) for migrations. When
345 changing models, it is important to run
346 `python {project_root}/manage.py schemamigration` which will create a migration
347  to reflect the model changes into the database. These changes can be pulled
348 into the database with `python {project_root}/manage.py migrate`.
349
350 Sometimes the database already has a migration performed on it, but that
351 information wasn't told to south. There are subtleties to the process which
352 require looking at the south docs. As a tip, start by looking at the `--fake`
353 flag.
354
355 # Assets from Third Parties
356
357 A number of assets have been added to the repository which come from external
358 sources. It would be difficult to keep a complete list in this README and keep
359 it up to date. Software which originally came from outside parties can
360 generally be found in `{project_root}/karmaworld/assets`.
361
362 Additionally, all third party Python projects (downloaded and installed with
363 pip) are listed in these files:
364
365 * `{project_root}/reqs/common.txt`
366 * `{project_root}/reqs/dev.txt`
367 * `{project_root}/reqs/prod.txt`
368
369 # Thanks
370
371 * KarmaNotes.org is a project of the FinalsClub Foundation with generous funding from the William and Flora Hewlett Foundation
372
373 * Also thanks to [rdegges](https://github.com/rdegges/django-skel) for the django-skel template