Removing client_secrets.json as outdated and onerous. Untested.
[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 KarmaWorld is an online database of college lecture notes.  KarmaWorld
15 empowers college students to participate in the free exchange of knowledge.
16
17 # Naming
18
19 The repository and the project are called KarmaWorld. One implementation
20 of KarmaWorld, which is run by FinalsClub Foundation, is called
21 [KarmaNotes](https://www.karmanotes.org/).
22
23 # Pre-Installation
24
25 ## Code
26
27 Before doing anything, you'll need the code. Grab it from github.
28
29 Clone the project from the central repo using your github account:
30
31     git clone git@github.com:FinalsClub/karmaworld.git
32
33 If you aren't using a system setup for github, then grab the project with
34 this command instead:
35
36     git clone https://github.com/FinalsClub/karmaworld.git
37
38 Generally speaking, this will create a subdirectory called `karmaworld` under
39 the directory where the `git` command was run. This git repository directory
40 will be referred to herein as `{project_root}`.
41
42 There might be some confusion as the git repository's directory will likely be
43 called `karmaworld` (this is `{project_root}`), but there is also a `karmaworld`
44 directory underneath that (`{project_root}/karmaworld`) alongside files like
45 `fabfile.py` (`{project_root}/fabfile.py`) and `README.md`
46 (`{project_root}/README.md`).
47
48 ## External Software Dependencies
49
50 ### pdf2htmlEX
51
52 KarmaWorld uses [pdf2htmlEX](https://github.com/coolwanglu/pdf2htmlEX) as
53 a dependency. pdf2htmlEX is used to convert uploaded PDF notes into HTML.
54
55 An [outdated version of pdf2htmlEX](https://github.com/FinalsClub/pdf2htmlEX)
56 is available which includes the
57 [patch](https://github.com/FinalsClub/pdf2htmlEX/commit/3c19f6abd8d59d1b58cf254b7160b332b3f5b517)
58 required for pdf2htmlEX to correctly work with KarmaWorld.
59
60 Newer versions can be used by applying the patch by hand. It's a fairly
61 simple two-line modification that can be done after installing
62 pdf2htmlEX.
63
64 ### SSL Certificate
65
66 If you wish to host your system publicly, you'll almost certainly want
67 an SSL certificate signed by a proper authority.
68
69 You may need to set the `SSL_REDIRECT` environment variable to `true` to
70 make KarmaWorld redirect insecure connections to secure ones.
71
72 Follow [Heroku's SSL setup](https://devcenter.heroku.com/articles/ssl-endpoint)
73 to get SSL running on your server with Heroku.
74
75 ## External Service Dependencies
76
77 Notice: This software makes use of external third party services which require
78 accounts to access the service APIs. Without these third parties available,
79 this software may require considerable overhaul. These services have
80 API keys, credentials, and other information that you must provide to KarmaWorld
81 as environment variables. The best way to persist these environment variables is
82 by using a `.env` file.  Copy `.env.example` to `.env` and populate the fields as required.
83
84 A number of services are required even if running the KarmaWorld web service
85 locally, some of the services are recommended, and some are completely optional
86 even if running the web service on Heroku.
87
88 Many of these services have free tiers and can be used without charge for
89 development testing purposes.
90
91 * Reminder
92   * Copy `.env.example` to `.env` and populate the environment variables there.
93 * Required Services
94   * [Google Drive](#google-drive)
95   * [Filepicker](#filepicker)
96   * [PostgreSQL](#postgresql)
97   * [Celery](#celery-queue)
98 * Optional but recommended
99   * [IndexDen](#indexden): enables searching through courses, notes, etc
100   * [Heroku](#heroku): the production environment used by karmanotes.org
101     * it might not be possible to run KarmaWorld on Heroku using a free
102       webapp.
103   * [Amazon S3](#s3-for-static-files): for static file hosting
104 * Entirely optional (though used in the production environment)
105   * [Twitter](#twitter): share updates about new uploads
106   * [Amazon Mechanical Turk](#amazon-mechanical-turk): generate quizzes, flashcards, etc
107   * [Amazon CloudFront](#amazon-cloudfront-cdn)
108   * [Amazon S3](#s3-for-filepicker): store files uploaded to Filepicker
109     * Filepicker does not support S3 storage in its free tier
110
111 ### Heroku
112 This project has chosen to use [Heroku](www.heroku.com) to host the Django and
113 celery software. While not a hard requirement, the more up-to-date parts of this
114 documentation will operate assuming Heroku is in use.
115
116 See README.heroku for more information.
117
118 #### pdf2htmlEX on Heroku
119 If using Heroku, the default
120 [KarmaNotes Heroku buildpack](https://github.com/FinalsClub/heroku-buildpack-karmanotes)
121 will [include](https://github.com/FinalsClub/heroku-buildpack-karmanotes/blob/master/bin/steps/pdf2htmlex)
122 the [required version of pdf2htmlEX](#pdf2htmlex).
123
124 ### Celery Queue
125 Celery uses the Apache Message Queueing Protocol for passing messages to its workers.
126
127 For production, we recommend using Heroku's CloudAMQP add-on, getting your own CloudAMQP account, or
128 running a queueing system on your own. The `CLOUDAMQP_URL` environment variable must be set correctly
129 for KarmaWorld to be able to use Celery. The `CELERY_QUEUE_NAME` environment variable
130 must be set to the name of the queue you wish to use. Settings this to something unique
131 allows multiple instances of KarmaWorld (or some other software) to share the same queueing server.
132
133 For development on localhost, `RabbitMQ` is the default for `djcelery` and is well supported. Ensure
134 `RabbitMQ` is installed for local development.
135
136 ### PostgreSQL
137
138 PostgreSQL is not necessarily required; other RDBMS could probably be fit into
139 place. However, the code was largely written assuming PostgreSQL will be used.
140 Change to another system with the caveat that it might take some work.
141
142 There are many cloud providers which provide PostgreSQL databases. Heroku has
143 an add-on for providing a PostgreSQL database. Ensure something like this
144 is made available and installed to the app.
145
146 For local development, ensure a PostgreSQL is running on localhost or is
147 otherwise accessible.
148
149 ### Amazon S3
150 The instructions for creating an [S3](http://aws.amazon.com/s3/) bucket may be
151 [found on Amazon.](http://docs.aws.amazon.com/AmazonS3/latest/gsg/CreatingABucket.html)
152
153 Two, separate buckets may be used in production: one for static file hosting
154 and one as a communication bus with Filepicker.
155
156 #### S3 for Filepicker
157
158 This software uses S3 to store files which are sent to or received 
159 from Filepicker. Filepicker will need to know the S3 bucket name, access key,
160 and secret key.
161
162 Filepicker users can only make use of an S3 bucket with a paid account. For
163 development purposes, no Filepicker S3 bucket is needed. Skip all references to
164 the Filepicker S3 bucket in the development case.
165
166 The software will not need to know the S3 credentials for the Filepicker
167 bucket, because the software will upload files to the Filepicker S3 bucket
168 through Filepicker's API and it will link to or download files from the
169 Filepicker S3 bucket through Filepicker's URLs. This will be covered in the
170 [Filepicker section](#filepicker).
171
172 #### S3 for static files
173
174 This software uses S3 for hosting static files. The software will need to
175 update static files on the S3 bucket. As such, the software will need the
176 S3 bucket name, access key, and secret key via the environment variables. This
177 is described in subsections below.
178
179 To support static hosting, `DEFAULT_FILE_STORAGE` should be set to
180 `'storages.backends.s3boto.S3BotoStorage'`, unless there is a compelling reason
181 to change it.
182
183 There are three ways to setup access to the S3 buckets depending upon speed
184 and security. The more secure, the slower it will be to setup.
185
186 #### insecure S3 access
187 For quick and dirty insecure S3 access, create a single group and a single user
188 with full access to all buckets. Full access to all buckets is insecure!
189
190 Create an 
191 [Amazon IAM group](http://docs.aws.amazon.com/IAM/latest/UserGuide/Using_CreatingAndListingGroups.html)
192 with full access to the S3 bucket. Select the "Amazon S3 Full Accesss" Policy
193 Template.
194
195 Create an
196 [Amazon IAM user](http://docs.aws.amazon.com/IAM/latest/UserGuide/Using_SettingUpUser.html).
197 Copy the credentials into the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`
198 environment variables. Be sure to write down the access information, as it
199 will only be shown once.
200
201 #### secure S3 access
202 For secure S3 access, two users will be needed. One with access to the
203 Filepicker bucket and one with access to the static hosting bucket.
204
205 Note: this might need to be modified to prevent creation and deletion of
206 buckets?
207
208 Create an 
209 [Amazon IAM group](http://docs.aws.amazon.com/IAM/latest/UserGuide/Using_CreatingAndListingGroups.html)
210 with full access to the S3 bucket. The quick way is to select the
211 "Amazon S3 Full Accesss" Policy Template and replace `"Resource": "*"` with 
212 `"Resource": "arn:aws:s3:::<static_bucket_name>"`.
213
214 Create an
215 [Amazon IAM user](http://docs.aws.amazon.com/IAM/latest/UserGuide/Using_SettingUpUser.html).
216 Copy the credentials into the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`
217 environment variables. Be sure to write down the access information, as it
218 will only be shown once.
219
220 Ensure the created user is a member of the group with access to the S3
221 static files bucket.
222
223 Repeat the process again, creating a group for the Filepicker bucket and
224 creating a user with access to that group. These credentials will be passed
225 on to Filepicker.
226
227 #### somewhat secure S3 access
228 Create two groups as described in the `secure S3 access` section above.
229
230 Create a single user, save the credentials as described in the
231 `insecure S3 access` section above, and pass the credentials on to Filepicker.
232
233 Add the single user to both groups.
234
235 This is less secure because if your web server or Filepicker get compromised
236 (so there are two points for potential failure), the single compromised
237 user has full access to both buckets.
238
239 ### Amazon Cloudfront CDN
240 [Cloudfront CDN](http://aws.amazon.com/cloudfront/) assists static file hosting.
241
242 Follow
243 [Amazon's instructions](http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/GettingStarted.html)
244 to host static files out of the appropriate S3 bucket. Note that Django's static
245 file upload process has been modified to mark static files as publicly
246 assessible.
247
248 In the settings for the Cloudfront Distribution, copy the "Domain Name" from
249 General settings and set `CLOUDFRONT_DOMAIN` to it. For example, `abcdefghij.cloudfront.net`.
250
251 ### Amazon Mechanical Turk
252 Mechanical turk is employed to generate human feedback from uploaded notes.
253 This service is helpful for generating flash cards and quizzes.
254
255 This service is optional and it might cause unexpected charges when
256 deployed.  If the required environment variable is not found,
257 then no errors will occur and no mechanical turk tasks will be created, avoiding any unexpected
258 costs.
259
260 The `MTURK_HOST` environment variable is almost certainly
261 `"mechanicalturk.amazonaws.com"`.
262
263 The code will create and publish HITs on your behalf.
264
265 ### Google Drive
266 This software uses [Google Drive](https://developers.google.com/drive/) to
267 convert documents to and from various file formats.
268
269 A Google Drive service account with access to the Google Drive is required.
270 This may be done with a Google Apps account with administrative privileges, or ask
271 your business sysadmin.
272
273 Follow [Google's instructions](https://developers.google.com/drive/web/auth/web-server)
274 to create a Google Drive service account. If using Google Apps, it is worth
275 looking at [these instructions](https://developers.google.com/drive/delegation).
276
277 Populate the `GOOGLE_USER` environment variable with the email address of the
278 user whose Google Drive will be accessed. This is typically your own email
279 address.
280
281 Google Drive used to use p12 files by default. Now a new-style JSON file is
282 downloaded by default when creating new credentials. Until the code has been
283 [updated](https://github.com/FinalsClub/karmaworld/issues/437) to use the
284 new-style JSON file, make sure to click the `Generate a new P12 key` button.
285
286 While on the Credentials page (with the `Generate a new P12 key` button
287 visible), note the Service account Email address. It will have a format like
288 `numbers-alphanumerics@developer.gserviceaccount.com`. Copy this value and
289 paste it into the `GOOGLE_SERVICE_EMAIL` environment variable.
290
291 Convert the p12 file into a Base64 encoded string for the
292 `GOOGLE_SERVICE_KEY_BASE64` environment variable. There are many ways to do
293 this. If Python is available, the
294 [binascii library](https://docs.python.org/2/library/binascii.html#binascii.b2a_base64)
295 makes this very easy:
296
297         import binascii
298         with open('file.p12', 'r') as f:
299             print binascii.b2a_base64(f.read)
300
301 The following instructions require creating web application credentials as
302 separate. Ideally, we will
303 [remove this step](https://github.com/FinalsClub/karmaworld/issues/436).
304 Until then, please figure out how to create web application credentials.
305
306 Copy the contents of `client_secret_*.apps.googleusercontent.com.json` into the
307 `GOOGLE_CLIENT_SECRETS` environment variable.
308
309 ### Filepicker
310 This software uses [Filepicker.io](https://www.inkfilepicker.com/) for uploading
311 files. This requires an account with Filepicker.
312
313 Filepicker can use an additional third party file hosting site where it may
314 send uploaded files. This project, in production, uses Amazon S3 as the third
315 party. See the Amazon S3 section above for more information.  
316
317 Create a new App with Web SDK and provide the Heroku App URL for the
318 Application's URL. You'll be given an API Key for the App. Paste this into the
319 `FILEPICKER_API_KEY` environment variable.
320
321 Find the 'App Security' button on the left hand side of the web site. Make sure
322 'Use Security' is enabled. Generate a new secret key. Paste this key into the
323 `FILEPICKER_SECRET` environment variable.
324
325 If you have an upgraded plan, you can configure Filepicker to have access to
326 your Filepicker S3 bucket. Click 'Amazon S3' on the left hand side menu and
327 supply the credentials for the user with access to the Filepicker S3 bucket.
328
329 ### IndexDen
330 KarmaWorld uses IndexDen to create a searchable index of all the notes in the
331 system. Create an free IndexDen account at
332 [their homepage](http://indexden.com/). You will be given a private URL that
333 accesses your IndexDen account. This URL is visible on your dashboard (you
334 might need to scroll down).
335
336 Set the `INDEXDEN_PRIVATE_URL` environment variable to your private URL.
337
338 Set the `INDEXDEN_INDEX` environment variable to the name of the index you want
339 to use for KarmaWorld. The index will be created automatically when KarmaNotes
340 is run if it doesn't already exist. It may be created through the GUI if
341 desired.
342
343 ### Twitter
344
345 Twitter is used to post updates about new courses. Access to the Twitter API
346 will be required for this task.
347
348 If this Twitter feature is desired, the consumer key and secret as well as the
349 access token key and secret are needed by the software.
350
351 If the required environment variables are not found, then no errors will occur
352 and no tweets will be posted.
353
354 To set this up,
355 [create a new Twitter application](https://dev.twitter.com/apps/new).
356 Use your Heroku App URL for the website field. Leave the Callback field blank.
357
358 Make sure this application has read/write access. Generate an access token. Go
359 to your OAuth settings, and grab the "Consumer key", "Consumer secret",
360 "Access token", and "Access token secret". Paste these, respectively, into the
361 environment variables `TWITTER_CONSUMER_KEY`, `TWITTER_CONSUMER_SECRET`,
362 `TWITTER_ACCESS_TOKEN_KEY`, `TWITTER_ACCESS_TOKEN_SECRET`.
363
364 # Local
365
366 ## Configuring foreman
367
368 KarmaNotes runs on Heroku as a webapp and thus makes use of a Procfie. While
369 not strictly necessary, KarmaWorld can use the same basic Procfile which is
370 convenient and consistent.
371
372 To use the Procfile locally, we recommend using `foreman`. To install `foreman`
373 and other Heroku tools, install the
374 [Heroku toolbelt](https://toolbelt.heroku.com/).
375
376 Ensure environment variables are available to `foreman` by copying
377 `.env.example` to `.env` and update those variables as appropriate for your
378 local system.
379
380 ## pdf2htmlEX
381
382 This project uses [pdf2htmlEX](https://github.com/coolwanglu/pdf2htmlEX) as
383 a dependency. pdf2htmlEX is used to convert uploaded PDF notes into HTML. It
384 needs to be installed on the same system that KarmaWorld is running on.
385
386 ### using their source
387
388 See their instructions at
389 [https://github.com/coolwanglu/pdf2htmlEX/wiki/Building](https://github.com/coolwanglu/pdf2htmlEX/wiki/Building).
390
391 Make sure to [patch](https://github.com/FinalsClub/pdf2htmlEX/commit/3c19f6abd8d59d1b58cf254b7160b332b3f5b517)
392 the source code to expose two variables.
393
394 ### using our fork
395
396 You can use FinalsClub's [outdated version of pdf2htmlEX](https://github.com/FinalsClub/pdf2htmlEX).
397 See their installation instructions above, but don't worry about patching.
398
399 ### using their PPA
400
401 You can use [their upstream PPA](https://launchpad.net/~coolwanglu/+archive/ubuntu/pdf2htmlex).
402
403         apt-add-repository ppa:coolwanglu/pdf2htmlex
404         apt-get update
405         apt-get install pdf2htmlex
406
407 Then patch the javascript on your system by running this code in the shell.
408
409         cat >> `dpkg -L pdf2htmlex | grep pdf2htmlEX.js` <<PDF2HTMLEXHACK
410         Viewer.prototype['rescale'] = Viewer.prototype.rescale;
411         Viewer.prototype['scroll_to'] = Viewer.prototype.scroll_to;
412         PDF2HTMLEXHACK
413
414 ## Install
415
416   1. `virtualenv venv`
417   1. `source venv/bin/activate`
418   1. `pip install -r requirements.txt`
419     * on Debian systems, some packages are required for pip to succeed:
420     * `apt-get install python-dev libpython-dev python-psycopg2 libmemcached-dev libffi-dev libssl-dev postgresql-server-dev-X.Y`
421   1. `pip install -r requirements-dev.txt`
422
423 ## Configuration
424
425 Make sure [External Service Dependencies](#external_service_dependencies) are
426 satisfied. This includes running a local database and RabbitMQ instance as
427 desired.
428
429   1. configure `.env` as per [instructions](#external_service_dependencies)
430   1. `foreman run python manage.py syncdb --migrate --noinput`
431   1. `foreman run python manage.py createsuperuser`
432   1. `foreman run python manage.py fetch_usde_csv ./schools.csv`
433   1. `foreman run python manage.py import_usde_csv ./schools.csv`
434   1. `foreman run python manage.py sanitize_usde_schools`
435
436 * `fetch_usde_csv` downloads school records and stores them to `./schools.csv`. This file name
437      and location is arbitrary. As long as the same file is passed into `import_usde_csv` for
438      reading, everything should be fine.
439
440 * `fetching_usde_csv` requires `7zip` to be installed for processing compressed
441      archives. On Debian-based systems, this entails `apt-get install p7zip-full`
442
443 ## Run
444
445 Make sure you are inside your virtual environment (`source venv/bin/activate`).
446
447 If the code has changed or this is the first run, make sure any modified static
448 files get compressed with `foreman run python manage.py compress`. Static files
449 then need to be uploaded correctly with `foreman run python manage.py
450 collectstatic`.
451
452 Run `foreman start`.  `foreman` will load the `.env` file and manage running all
453 processes in a way that is similar to that of Heroku. This allows better
454 consistency with local, staging, and production deployments.
455
456 To run web-only, but no celery or beat, run `foreman start web` to specify
457 strictly the web worker.
458
459 Press ctrl-C to kill foreman. Foreman will run Django's runserver command.
460 If you wish to have more control over how this is done, you can do
461 `foreman run python manage.py runserver <options>`. For running any other
462 `manage.py` commands, you should also precede them with `foreman run` like just shown.
463 This simply ensures that the environment variables from `.env` are present.
464
465 # Heroku Install
466
467 KarmaNotes runs on Heroku as a webapp. This section addresses what was done
468 for KarmaNotes so that other implementations of KarmaWorld can be run on
469 Heroku.
470
471 Before anything else, download the [Heroku toolbelt](https://toolbelt.heroku.com/).
472
473 To run KarmaWorld on Heroku, do `heroku create` and `git push heroku master` as typical
474 for a Heroku application. Set your the variable `BUILDPACK_URL` to
475 `https://github.com/FinalsClub/heroku-buildpack-karmanotes` to use a buildpack
476 designed to support KarmaNotes.
477
478 You will need to import the US Department of Education's list of accredited schools.
479    1. Fetch USDE schools with
480       `heroku run python manage.py fetch_usde_csv ./schools.csv`
481    1. Upload the schools into the database with
482       `heroku run python /manage.py import_usde_csv ./schools.csv`
483    1. Clean up redundant information with
484       `heroku run python /manage.py sanitize_usde_schools`
485
486
487 # Django Database management
488
489 ## South
490
491 We have setup Django to use
492 [south](http://south.aeracode.org/wiki/QuickStartGuide) for migrations. When
493 changing models, it is important to run
494 `foreman run python manage.py schemamigration` which will create a migration
495  to reflect the model changes into the database. These changes can be pulled
496 into the database with `foreman run python manage.py migrate`.
497
498 Sometimes the database already has a migration performed on it, but that
499 information wasn't told to south. There are subtleties to the process which
500 require looking at the south docs. As a tip, start by looking at the `--fake`
501 flag.
502
503 # Assets from Third Parties
504
505 A number of assets have been added to the repository which come from external
506 sources. It would be difficult to keep a complete list in this README and keep
507 it up to date. Software which originally came from outside parties can
508 generally be found in `karmaworld/assets`.
509
510 Additionally, all third party Python projects (downloaded and installed with
511 pip) are listed in these files:
512
513 * `requirements.txt`
514 * `requirements-dev.txt`
515
516 # Thanks
517
518 * KarmaNotes.org is a project of the FinalsClub Foundation with generous funding from the William and Flora Hewlett Foundation
519
520 * Also thanks to [rdegges](https://github.com/rdegges/django-skel) for the django-skel template