├── __init__.py
├── blog
├── __init__.py
├── admin.py
└── models.py
├── help
├── __init__.py
├── views.py
├── models.py
└── tests.py
├── wiki
├── __init__.py
├── forms
│ ├── __init__.py
│ ├── messages.py
│ └── courses.py
├── utils
│ ├── __init__.py
│ ├── users.py
│ ├── constants.py
│ ├── tools.py
│ ├── currents.py
│ ├── history.py
│ ├── decorators.py
│ └── pages.py
├── management
│ ├── __init__.py
│ └── commands
│ │ ├── __init__.py
│ │ └── remarkdown.py
├── templatetags
│ ├── __init__.py
│ ├── extras.py
│ └── wikinotes_markup.py
├── admin
│ ├── __init__.py
│ ├── faculties.py
│ ├── departments.py
│ ├── pages.py
│ ├── series.py
│ └── courses.py
├── context_processors.py
├── models
│ ├── __init__.py
│ ├── faculties.py
│ ├── departments.py
│ ├── history.py
│ ├── series.py
│ └── users.py
└── tests
│ ├── __init__.py
│ ├── series.py
│ ├── users.py
│ ├── pages.py
│ └── pagetypes.py
├── views
├── __init__.py
├── news.py
└── messages.py
├── assets
├── favicon.ico
├── img
│ ├── 404.png
│ ├── pin.png
│ ├── email.png
│ ├── github.png
│ ├── gplus.png
│ ├── grid.png
│ ├── logo.png
│ ├── cc-by-nc.png
│ ├── facebook.png
│ ├── twitter.png
│ ├── grid-18px.png
│ ├── social
│ │ ├── fb.png
│ │ ├── g+.png
│ │ └── yahoo.png
│ ├── wikinotes.png
│ ├── digital-ocean.png
│ ├── faculty
│ │ ├── arts.png
│ │ ├── science.png
│ │ └── engineering.png
│ ├── pages
│ │ ├── summary.png
│ │ ├── past-exam.png
│ │ ├── vocab-list.png
│ │ ├── course-quiz.png
│ │ └── lecture-notes.png
│ ├── department
│ │ ├── ANAT.png
│ │ ├── ANTH.png
│ │ ├── ARCH.png
│ │ ├── BIEN.png
│ │ ├── BIOC.png
│ │ ├── BIOL.png
│ │ ├── BMDE.png
│ │ ├── CHEE.png
│ │ ├── CHEM.png
│ │ ├── CIVE.png
│ │ ├── COMP.png
│ │ ├── EAST.png
│ │ ├── ECON.png
│ │ ├── ECSE.png
│ │ ├── ENGL.png
│ │ ├── EPSC.png
│ │ ├── FACC.png
│ │ ├── GEOG.png
│ │ ├── INTD.png
│ │ ├── MATH.png
│ │ ├── MECH.png
│ │ ├── MIME.png
│ │ ├── MIMM.png
│ │ ├── MPMC.png
│ │ ├── NSCI.png
│ │ ├── PHAR.png
│ │ ├── PHGY.png
│ │ ├── PHIL.png
│ │ ├── PHYS.png
│ │ ├── POLI.png
│ │ ├── PSYC.png
│ │ ├── URBD.png
│ │ ├── URBP.png
│ │ ├── ANAT_large.png
│ │ ├── ANTH_large.png
│ │ ├── ARCH_large.png
│ │ ├── BIEN_large.png
│ │ ├── BIOC_large.png
│ │ ├── BIOL_large.png
│ │ ├── BMDE_large.png
│ │ ├── CHEE_large.png
│ │ ├── CHEM_large.png
│ │ ├── CIVE_large.png
│ │ ├── COMP_large.png
│ │ ├── EAST_large.png
│ │ ├── ECON_large.png
│ │ ├── ECSE_large.png
│ │ ├── ENGL_large.png
│ │ ├── EPSC_large.png
│ │ ├── FACC_large.png
│ │ ├── GEOG_large.png
│ │ ├── INTD_large.png
│ │ ├── MATH_large.png
│ │ ├── MECH_large.png
│ │ ├── MIME_large.png
│ │ ├── MIMM_large.png
│ │ ├── MPMC_large.png
│ │ ├── NSCI_large.png
│ │ ├── PHAR_large.png
│ │ ├── PHGY_large.png
│ │ ├── PHIL_large.png
│ │ ├── PHYS_large.png
│ │ ├── POLI_large.png
│ │ ├── PSYC_large.png
│ │ ├── URBD_large.png
│ │ └── URBP_large.png
│ └── edit_buttons
│ │ ├── url.png
│ │ ├── image.png
│ │ ├── list.png
│ │ ├── math.png
│ │ ├── quote.png
│ │ └── table.png
├── apple-touch-icon-precomposed.png
├── apple-touch-icon-72x72-precomposed.png
├── apple-touch-icon-114x114-precomposed.png
├── js
│ └── sectionedit.js
└── css
│ ├── prettify.css
│ ├── bootstrap.less
│ ├── variables.less
│ ├── scaffolding.less
│ ├── type.less
│ ├── pygments.less
│ ├── tables.less
│ ├── reset.less
│ └── chosen.less
├── templates
├── pages
│ ├── summary
│ │ ├── cell.html
│ │ ├── list_header.html
│ │ └── list_body.html
│ ├── course-quiz
│ │ ├── cell.html
│ │ ├── list_header.html
│ │ └── list_body.html
│ ├── vocab-list
│ │ ├── cell.html
│ │ ├── list_header.html
│ │ └── list_body.html
│ ├── past-exam
│ │ ├── cell.html
│ │ ├── list_header.html
│ │ └── list_body.html
│ ├── lecture-notes
│ │ ├── list_header.html
│ │ ├── cell.html
│ │ └── list_body.html
│ ├── subject_field.html
│ ├── subject_data.html
│ ├── professor_id_data.html
│ ├── link_field.html
│ ├── field_templates.html
│ ├── link_data.html
│ ├── content.html
│ ├── exam_field.html
│ ├── professor_id_field.html
│ ├── semester_field.html
│ ├── create_popup.html
│ ├── create.html
│ ├── edit.html
│ ├── series_listing.html
│ ├── printview.html
│ ├── date_field.html
│ ├── history.html
│ ├── form.html
│ ├── edit_buttons.html
│ ├── show.html
│ └── commit.html
├── main
│ ├── markdown.html
│ ├── course_search.html
│ ├── ucp.html
│ ├── login_error.html
│ ├── recent.html
│ ├── contributions.html
│ └── registration.html
├── about
│ ├── history.md
│ └── licensing.md
├── help
│ ├── overview.md
│ └── lexers.md
├── courses
│ ├── get_all.html
│ ├── popular.html
│ ├── faculty_browse.html
│ ├── professor_browse.html
│ ├── department_overview.html
│ ├── department_browse.html
│ ├── create.html
│ ├── semester_overview.html
│ ├── all_browse.html
│ ├── category_overview.html
│ ├── professor_overview.html
│ ├── recent.html
│ └── faculty_overview.html
├── 500.html
├── ucp
│ ├── overview.html
│ ├── preferences.html
│ ├── account.html
│ └── profile.html
├── news
│ ├── view.html
│ └── main.html
├── messages
│ ├── base.html
│ ├── inbox.html
│ ├── outbox.html
│ ├── view.html
│ └── compose.html
├── 403.html
├── search
│ └── results.html
├── 404.html
└── static.html
├── .gitignore
├── requirements.txt
├── .travis.yml
├── manage.py
├── fabfile.py
├── mdx
├── mdx_mathjax.py
├── mdx_mentions.py
├── mdx_downheader.py
├── mdx_plotly.py
├── mdx_subscript.py
├── mdx_superscript.py
├── mdx_urlize.py
├── mdx_wiki_def_list.py
└── mdx_wiki_tables.py
├── readme.md
└── urls.py
/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/blog/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/help/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/wiki/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/wiki/forms/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/wiki/utils/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/wiki/management/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/views/__init__.py:
--------------------------------------------------------------------------------
1 | import main
2 |
--------------------------------------------------------------------------------
/wiki/templatetags/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/wiki/management/commands/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/help/views.py:
--------------------------------------------------------------------------------
1 | # Create your views here.
2 |
--------------------------------------------------------------------------------
/help/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | # Create your models here.
4 |
--------------------------------------------------------------------------------
/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/favicon.ico
--------------------------------------------------------------------------------
/assets/img/404.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/404.png
--------------------------------------------------------------------------------
/assets/img/pin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/pin.png
--------------------------------------------------------------------------------
/assets/img/email.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/email.png
--------------------------------------------------------------------------------
/assets/img/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/github.png
--------------------------------------------------------------------------------
/assets/img/gplus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/gplus.png
--------------------------------------------------------------------------------
/assets/img/grid.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/grid.png
--------------------------------------------------------------------------------
/assets/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/logo.png
--------------------------------------------------------------------------------
/templates/pages/summary/cell.html:
--------------------------------------------------------------------------------
1 | {{ page.subject }}
2 |
--------------------------------------------------------------------------------
/assets/img/cc-by-nc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/cc-by-nc.png
--------------------------------------------------------------------------------
/assets/img/facebook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/facebook.png
--------------------------------------------------------------------------------
/assets/img/twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/twitter.png
--------------------------------------------------------------------------------
/templates/main/markdown.html:
--------------------------------------------------------------------------------
1 | {% load wikinotes_markup %}
2 | {{ content|wikinotes_markdown|safe }}
3 |
--------------------------------------------------------------------------------
/templates/pages/course-quiz/cell.html:
--------------------------------------------------------------------------------
1 | {{ page.subject }}
2 |
--------------------------------------------------------------------------------
/templates/pages/vocab-list/cell.html:
--------------------------------------------------------------------------------
1 | {{ page.subject }}
2 |
--------------------------------------------------------------------------------
/assets/img/grid-18px.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/grid-18px.png
--------------------------------------------------------------------------------
/assets/img/social/fb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/social/fb.png
--------------------------------------------------------------------------------
/assets/img/social/g+.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/social/g+.png
--------------------------------------------------------------------------------
/assets/img/wikinotes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/wikinotes.png
--------------------------------------------------------------------------------
/templates/pages/past-exam/cell.html:
--------------------------------------------------------------------------------
1 | {{ page.title.title }}
2 |
--------------------------------------------------------------------------------
/assets/img/digital-ocean.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/digital-ocean.png
--------------------------------------------------------------------------------
/assets/img/faculty/arts.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/faculty/arts.png
--------------------------------------------------------------------------------
/assets/img/pages/summary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/pages/summary.png
--------------------------------------------------------------------------------
/assets/img/social/yahoo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/social/yahoo.png
--------------------------------------------------------------------------------
/assets/img/department/ANAT.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/ANAT.png
--------------------------------------------------------------------------------
/assets/img/department/ANTH.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/ANTH.png
--------------------------------------------------------------------------------
/assets/img/department/ARCH.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/ARCH.png
--------------------------------------------------------------------------------
/assets/img/department/BIEN.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/BIEN.png
--------------------------------------------------------------------------------
/assets/img/department/BIOC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/BIOC.png
--------------------------------------------------------------------------------
/assets/img/department/BIOL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/BIOL.png
--------------------------------------------------------------------------------
/assets/img/department/BMDE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/BMDE.png
--------------------------------------------------------------------------------
/assets/img/department/CHEE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/CHEE.png
--------------------------------------------------------------------------------
/assets/img/department/CHEM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/CHEM.png
--------------------------------------------------------------------------------
/assets/img/department/CIVE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/CIVE.png
--------------------------------------------------------------------------------
/assets/img/department/COMP.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/COMP.png
--------------------------------------------------------------------------------
/assets/img/department/EAST.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/EAST.png
--------------------------------------------------------------------------------
/assets/img/department/ECON.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/ECON.png
--------------------------------------------------------------------------------
/assets/img/department/ECSE.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/ECSE.png
--------------------------------------------------------------------------------
/assets/img/department/ENGL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/ENGL.png
--------------------------------------------------------------------------------
/assets/img/department/EPSC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/EPSC.png
--------------------------------------------------------------------------------
/assets/img/department/FACC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/FACC.png
--------------------------------------------------------------------------------
/assets/img/department/GEOG.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/GEOG.png
--------------------------------------------------------------------------------
/assets/img/department/INTD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/INTD.png
--------------------------------------------------------------------------------
/assets/img/department/MATH.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/MATH.png
--------------------------------------------------------------------------------
/assets/img/department/MECH.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/MECH.png
--------------------------------------------------------------------------------
/assets/img/department/MIME.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/MIME.png
--------------------------------------------------------------------------------
/assets/img/department/MIMM.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/MIMM.png
--------------------------------------------------------------------------------
/assets/img/department/MPMC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/MPMC.png
--------------------------------------------------------------------------------
/assets/img/department/NSCI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/NSCI.png
--------------------------------------------------------------------------------
/assets/img/department/PHAR.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/PHAR.png
--------------------------------------------------------------------------------
/assets/img/department/PHGY.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/PHGY.png
--------------------------------------------------------------------------------
/assets/img/department/PHIL.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/PHIL.png
--------------------------------------------------------------------------------
/assets/img/department/PHYS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/PHYS.png
--------------------------------------------------------------------------------
/assets/img/department/POLI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/POLI.png
--------------------------------------------------------------------------------
/assets/img/department/PSYC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/PSYC.png
--------------------------------------------------------------------------------
/assets/img/department/URBD.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/URBD.png
--------------------------------------------------------------------------------
/assets/img/department/URBP.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/URBP.png
--------------------------------------------------------------------------------
/assets/img/edit_buttons/url.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/edit_buttons/url.png
--------------------------------------------------------------------------------
/assets/img/faculty/science.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/faculty/science.png
--------------------------------------------------------------------------------
/assets/img/pages/past-exam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/pages/past-exam.png
--------------------------------------------------------------------------------
/assets/img/pages/vocab-list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/pages/vocab-list.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | db.sqlite
3 | data
4 | content
5 | wiki/migrations
6 | assets/css/bootstrap.css
7 | *.swp
8 | *~
9 |
--------------------------------------------------------------------------------
/assets/img/edit_buttons/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/edit_buttons/image.png
--------------------------------------------------------------------------------
/assets/img/edit_buttons/list.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/edit_buttons/list.png
--------------------------------------------------------------------------------
/assets/img/edit_buttons/math.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/edit_buttons/math.png
--------------------------------------------------------------------------------
/assets/img/edit_buttons/quote.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/edit_buttons/quote.png
--------------------------------------------------------------------------------
/assets/img/edit_buttons/table.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/edit_buttons/table.png
--------------------------------------------------------------------------------
/assets/img/pages/course-quiz.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/pages/course-quiz.png
--------------------------------------------------------------------------------
/wiki/admin/__init__.py:
--------------------------------------------------------------------------------
1 | import courses
2 | import faculties
3 | import departments
4 | import pages
5 | import series
6 |
--------------------------------------------------------------------------------
/assets/img/department/ANAT_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/ANAT_large.png
--------------------------------------------------------------------------------
/assets/img/department/ANTH_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/ANTH_large.png
--------------------------------------------------------------------------------
/assets/img/department/ARCH_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/ARCH_large.png
--------------------------------------------------------------------------------
/assets/img/department/BIEN_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/BIEN_large.png
--------------------------------------------------------------------------------
/assets/img/department/BIOC_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/BIOC_large.png
--------------------------------------------------------------------------------
/assets/img/department/BIOL_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/BIOL_large.png
--------------------------------------------------------------------------------
/assets/img/department/BMDE_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/BMDE_large.png
--------------------------------------------------------------------------------
/assets/img/department/CHEE_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/CHEE_large.png
--------------------------------------------------------------------------------
/assets/img/department/CHEM_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/CHEM_large.png
--------------------------------------------------------------------------------
/assets/img/department/CIVE_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/CIVE_large.png
--------------------------------------------------------------------------------
/assets/img/department/COMP_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/COMP_large.png
--------------------------------------------------------------------------------
/assets/img/department/EAST_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/EAST_large.png
--------------------------------------------------------------------------------
/assets/img/department/ECON_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/ECON_large.png
--------------------------------------------------------------------------------
/assets/img/department/ECSE_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/ECSE_large.png
--------------------------------------------------------------------------------
/assets/img/department/ENGL_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/ENGL_large.png
--------------------------------------------------------------------------------
/assets/img/department/EPSC_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/EPSC_large.png
--------------------------------------------------------------------------------
/assets/img/department/FACC_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/FACC_large.png
--------------------------------------------------------------------------------
/assets/img/department/GEOG_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/GEOG_large.png
--------------------------------------------------------------------------------
/assets/img/department/INTD_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/INTD_large.png
--------------------------------------------------------------------------------
/assets/img/department/MATH_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/MATH_large.png
--------------------------------------------------------------------------------
/assets/img/department/MECH_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/MECH_large.png
--------------------------------------------------------------------------------
/assets/img/department/MIME_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/MIME_large.png
--------------------------------------------------------------------------------
/assets/img/department/MIMM_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/MIMM_large.png
--------------------------------------------------------------------------------
/assets/img/department/MPMC_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/MPMC_large.png
--------------------------------------------------------------------------------
/assets/img/department/NSCI_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/NSCI_large.png
--------------------------------------------------------------------------------
/assets/img/department/PHAR_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/PHAR_large.png
--------------------------------------------------------------------------------
/assets/img/department/PHGY_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/PHGY_large.png
--------------------------------------------------------------------------------
/assets/img/department/PHIL_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/PHIL_large.png
--------------------------------------------------------------------------------
/assets/img/department/PHYS_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/PHYS_large.png
--------------------------------------------------------------------------------
/assets/img/department/POLI_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/POLI_large.png
--------------------------------------------------------------------------------
/assets/img/department/PSYC_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/PSYC_large.png
--------------------------------------------------------------------------------
/assets/img/department/URBD_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/URBD_large.png
--------------------------------------------------------------------------------
/assets/img/department/URBP_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/department/URBP_large.png
--------------------------------------------------------------------------------
/assets/img/faculty/engineering.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/faculty/engineering.png
--------------------------------------------------------------------------------
/assets/img/pages/lecture-notes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/img/pages/lecture-notes.png
--------------------------------------------------------------------------------
/templates/about/history.md:
--------------------------------------------------------------------------------
1 | Page under construction. Some info on the old site (http://wikinotes.ca/wiki/wikinotes:About).
2 |
--------------------------------------------------------------------------------
/assets/apple-touch-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/apple-touch-icon-precomposed.png
--------------------------------------------------------------------------------
/templates/pages/course-quiz/list_header.html:
--------------------------------------------------------------------------------
1 |
2 | Subject
3 | Semester
4 |
5 |
--------------------------------------------------------------------------------
/templates/pages/summary/list_header.html:
--------------------------------------------------------------------------------
1 |
2 | Subject
3 | Semester
4 |
5 |
--------------------------------------------------------------------------------
/templates/pages/vocab-list/list_header.html:
--------------------------------------------------------------------------------
1 |
2 | Subject
3 | Semester
4 |
5 |
--------------------------------------------------------------------------------
/assets/apple-touch-icon-72x72-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/apple-touch-icon-72x72-precomposed.png
--------------------------------------------------------------------------------
/templates/pages/lecture-notes/list_header.html:
--------------------------------------------------------------------------------
1 | Date
2 | Professor
3 | Semester
4 |
--------------------------------------------------------------------------------
/templates/pages/past-exam/list_header.html:
--------------------------------------------------------------------------------
1 | Exam type
2 | Semester
3 | Professor
4 |
--------------------------------------------------------------------------------
/assets/apple-touch-icon-114x114-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dellsystem/wikinotes/HEAD/assets/apple-touch-icon-114x114-precomposed.png
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | Django==1.5.2
2 | Fabric==1.9.1
3 | GitPython==0.3.2.RC1
4 | Markdown==2.2.1
5 | Pygments==1.6
6 | django-gravatar==0.1.0
7 | mock==1.0.1
8 |
--------------------------------------------------------------------------------
/wiki/admin/faculties.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from wiki.models.faculties import Faculty
4 |
5 |
6 | admin.site.register(Faculty)
7 |
--------------------------------------------------------------------------------
/wiki/admin/departments.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from wiki.models.departments import Department
4 |
5 |
6 | admin.site.register(Department)
7 |
--------------------------------------------------------------------------------
/templates/pages/lecture-notes/cell.html:
--------------------------------------------------------------------------------
1 | {{ page.title }}
{% if page.subject %}{{ page.subject }}
{% endif %}
2 |
--------------------------------------------------------------------------------
/wiki/utils/users.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 |
4 | def validate_username(username):
5 | if re.match('^\w+$', username):
6 | return True
7 | else:
8 | return False
9 |
--------------------------------------------------------------------------------
/wiki/utils/constants.py:
--------------------------------------------------------------------------------
1 | from wiki.utils.currents import current_year
2 |
3 | terms = ['winter', 'summer', 'fall']
4 | years = range(current_year, 2002, -1)
5 | exam_types = ['midterm', 'final']
6 |
--------------------------------------------------------------------------------
/templates/pages/summary/list_body.html:
--------------------------------------------------------------------------------
1 | {{ page.subject }}
2 | {{ page.course_sem.get_semester }}
3 |
--------------------------------------------------------------------------------
/templates/pages/course-quiz/list_body.html:
--------------------------------------------------------------------------------
1 | {{ page.subject }}
2 | {{ page.course_sem.get_semester }}
3 |
--------------------------------------------------------------------------------
/templates/pages/subject_field.html:
--------------------------------------------------------------------------------
1 | Subject:
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/templates/pages/vocab-list/list_body.html:
--------------------------------------------------------------------------------
1 | {{ page.subject }}
2 | {{ page.course_sem.get_semester }}
3 |
--------------------------------------------------------------------------------
/templates/main/course_search.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/wiki/context_processors.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 |
3 |
4 | def config(request):
5 | return {
6 | 'compile_less': settings.COMPILE_LESS,
7 | 'site_url': settings.SITE_URL,
8 | }
9 |
--------------------------------------------------------------------------------
/blog/admin.py:
--------------------------------------------------------------------------------
1 | from blog.models import BlogPost
2 | from django.contrib import admin
3 |
4 | class BlogAdmin(admin.ModelAdmin):
5 | prepopulated_fields = {"slug": ("title",)}
6 |
7 | admin.site.register(BlogPost, BlogAdmin)
8 |
--------------------------------------------------------------------------------
/templates/help/overview.md:
--------------------------------------------------------------------------------
1 | Although this section of the website is still under construction, you can check out our mostly up-to-date and fairly comprehensive [formatting docs](/help/formatting) to learn how to use the markup on this site.
2 |
--------------------------------------------------------------------------------
/templates/pages/subject_data.html:
--------------------------------------------------------------------------------
1 |
2 |
Subject
3 |
4 | {% if subject %}{{ subject }}{% else %}N/A{% endif %}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/templates/pages/professor_id_data.html:
--------------------------------------------------------------------------------
1 |
2 |
Professor
3 |
4 | {% if professor %}{{ professor }}{% else %}N/A{% endif %}
5 |
6 |
7 |
--------------------------------------------------------------------------------
/templates/pages/link_field.html:
--------------------------------------------------------------------------------
1 | Link:
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/wiki/models/__init__.py:
--------------------------------------------------------------------------------
1 | from courses import *
2 | from departments import *
3 | from faculties import *
4 | from page_types import * # not real django models BUT must be imported before pages
5 | from pages import *
6 | from history import *
7 | from users import *
8 | from series import *
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - "2.7"
4 | install:
5 | - pip install -r requirements.txt
6 | before:
7 | - python manage.py syncdb
8 | - python manage.py loaddata faculties departments courses professors coursesemesters
9 | script: python -Wall manage.py test wiki
10 |
--------------------------------------------------------------------------------
/templates/pages/past-exam/list_body.html:
--------------------------------------------------------------------------------
1 | {{ page.title.title }}
2 | {{ page.course_sem.get_semester }}
3 | {{ page.professor }}
4 |
--------------------------------------------------------------------------------
/wiki/utils/tools.py:
--------------------------------------------------------------------------------
1 | class Struct:
2 | """Used for testing, so that arbitrary attributes for an object created
3 | on-the-fly can be accessed using dot notation. See wiki/tests/views.py for
4 | more details."""
5 | def __init__(self, entries):
6 | self.__dict__.update(entries)
7 |
--------------------------------------------------------------------------------
/wiki/admin/pages.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from wiki.models.pages import Page, ExternalPage
4 |
5 |
6 | class PageAdmin(admin.ModelAdmin):
7 | list_display = ('get_title', 'page_type', 'course_sem')
8 |
9 |
10 | admin.site.register(Page, PageAdmin)
11 | admin.site.register(ExternalPage)
12 |
--------------------------------------------------------------------------------
/templates/courses/get_all.html:
--------------------------------------------------------------------------------
1 | {% for course in courses %}{{ course }} - {{ course.name }} {% endfor %}
2 | {% comment %}
3 | Cannot use parentheses to show the course name because then chosen won't allow you to search for it properly
4 | {% endcomment %}
5 |
--------------------------------------------------------------------------------
/wiki/tests/__init__.py:
--------------------------------------------------------------------------------
1 | from wiki.tests.markdown import *
2 | from wiki.tests.pages import *
3 | from wiki.tests.series import *
4 | from wiki.tests.users import *
5 | from wiki.tests.urls import *
6 | from wiki.tests.views import *
7 | from wiki.tests.pagetypes import *
8 |
9 | """
10 | MORE TESTS TO COME, EVENTUALLY
11 | """
12 |
--------------------------------------------------------------------------------
/templates/pages/field_templates.html:
--------------------------------------------------------------------------------
1 |
2 | {% for field_template in field_templates %}
3 |
4 | {% include field_template %}
5 |
6 | {% endfor %}
7 |
8 |
--------------------------------------------------------------------------------
/wiki/admin/series.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from wiki.models.series import Series, SeriesPage, SeriesBanner
4 |
5 |
6 | class SeriesAdmin(admin.ModelAdmin):
7 | prepopulated_fields = {"slug": ("name",)}
8 |
9 |
10 | admin.site.register(Series, SeriesAdmin)
11 | admin.site.register(SeriesPage)
12 | admin.site.register(SeriesBanner)
13 |
--------------------------------------------------------------------------------
/templates/pages/link_data.html:
--------------------------------------------------------------------------------
1 |
2 |
Link
3 |
4 |
{% if link %}{{ link }}{% else %}N/A{% endif %}
5 |
6 | Something not correct? Contact admin@wikinotes.ca
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/templates/pages/lecture-notes/list_body.html:
--------------------------------------------------------------------------------
1 | {{ page.title }}
{% if page.subject %}{{ page.subject }}
{% endif %}
2 | {{ page.professor }}
3 | {{ page.course_sem.get_semester }}
4 |
--------------------------------------------------------------------------------
/wiki/utils/currents.py:
--------------------------------------------------------------------------------
1 | from datetime import datetime
2 |
3 | now = datetime.now()
4 |
5 | # Figure out the term from the month ... let's hope McGill doesn't change this anytime soon
6 | month = now.month
7 | if month < 5:
8 | current_term = 'winter'
9 | elif month < 9:
10 | current_term = 'summer'
11 | else:
12 | current_term = 'fall'
13 |
14 | current_year = now.year
15 |
--------------------------------------------------------------------------------
/templates/500.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block content %}
4 |
5 |
6 | Error
7 | Something is broken! Please contact develop@wikinotes.ca, and let us know what you were doing before you received this error message, if possible. We apologise for the inconvenience.
8 |
9 |
10 | {% endblock %}
11 |
--------------------------------------------------------------------------------
/templates/pages/content.html:
--------------------------------------------------------------------------------
1 |
2 | {{ page.content|safe }}
3 |
8 |
9 |
--------------------------------------------------------------------------------
/help/tests.py:
--------------------------------------------------------------------------------
1 | """
2 | This file demonstrates writing tests using the unittest module. These will pass
3 | when you run "manage.py test".
4 |
5 | Replace this with more appropriate tests for your application.
6 | """
7 |
8 | from django.test import TestCase
9 |
10 |
11 | class SimpleTest(TestCase):
12 | def test_basic_addition(self):
13 | """
14 | Tests that 1 + 1 always equals 2.
15 | """
16 | self.assertEqual(1 + 1, 2)
17 |
--------------------------------------------------------------------------------
/templates/pages/exam_field.html:
--------------------------------------------------------------------------------
1 | Exam type:
2 |
9 |
--------------------------------------------------------------------------------
/wiki/admin/courses.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from wiki.models.courses import Course, CourseSemester, Professor
4 |
5 |
6 | class CourseAdmin(admin.ModelAdmin):
7 | exclude = ('num_watchers', 'latest_activity', 'watchers')
8 |
9 |
10 | class ProfessorAdmin(admin.ModelAdmin):
11 | prepopulated_fields = {'slug': ('name',)}
12 |
13 |
14 | admin.site.register(Course, CourseAdmin)
15 | admin.site.register(CourseSemester)
16 | admin.site.register(Professor, ProfessorAdmin)
17 |
--------------------------------------------------------------------------------
/templates/ucp/overview.html:
--------------------------------------------------------------------------------
1 |
2 | Welcome to your user control panel, {{ user }}. You can edit your login
3 | details in the Account section,
4 | your profile details in the
5 | Profile section, and your site preferences in the Preferences section.
7 |
8 |
9 | You have been a member since {{ user.date_joined|date:"F j, Y" }}.
10 |
--------------------------------------------------------------------------------
/views/news.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render, get_object_or_404
2 |
3 | from blog.models import BlogPost
4 | from wiki.utils.decorators import show_object_detail
5 |
6 |
7 | def main(request):
8 | data = {
9 | 'title': 'News',
10 | 'blog_posts': BlogPost.objects.all(),
11 | }
12 |
13 | return render(request, 'news/main.html', data)
14 |
15 |
16 | @show_object_detail(BlogPost)
17 | def view(request, post):
18 | return {
19 | 'title': str(post),
20 | 'post': post,
21 | }
22 |
--------------------------------------------------------------------------------
/templates/news/view.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% load wikinotes_markup %}
5 |
6 |
7 |
8 |
{{ post.title }}
9 |
10 | {{ post.timestamp }}
11 | {{ post.get_num_comments }} comment{{ post.get_num_comments|pluralize }}
12 | {{ post.body|wikinotes_markdown|safe }}
13 |
14 |
15 |
16 |
17 | {% endblock %}
18 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | from django.core.management import execute_manager
3 | import imp
4 | try:
5 | imp.find_module('settings') # Assumed to be in the same directory.
6 | except ImportError:
7 | import sys
8 | sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n" % __file__)
9 | sys.exit(1)
10 |
11 | import settings
12 |
13 | if __name__ == "__main__":
14 | execute_manager(settings)
15 |
--------------------------------------------------------------------------------
/wiki/templatetags/extras.py:
--------------------------------------------------------------------------------
1 | import itertools
2 |
3 | from django import template
4 |
5 | register = template.Library()
6 |
7 |
8 | @register.filter
9 | def chunks(value, chunk_length):
10 | """
11 | Breaks a list up into a list of lists of size .
12 | From StackOverflow (http://stackoverflow.com/a/7374167)
13 | """
14 | clen = int(chunk_length)
15 | i = iter(value)
16 | while True:
17 | chunk = list(itertools.islice(i, clen))
18 | if chunk:
19 | yield chunk
20 | else:
21 | break
22 |
--------------------------------------------------------------------------------
/assets/js/sectionedit.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function () {
2 | var baseURL = window.location.pathname;
3 | var headers = $('.header');
4 | var i, header, numHeaders, anchor, editLink;
5 | for (i = 0, numHeaders = headers.length; i < numHeaders; i++) {
6 | header = headers[i];
7 | // Get the name of the anchor for this header
8 | anchor = header.children[1].name;
9 | // Append an element
10 | editLink = 'edit ';
11 | $(header).append(editLink);
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/wiki/forms/messages.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 |
3 | from wiki.models.users import PrivateMessage
4 |
5 |
6 | class PrivateMessageForm(forms.ModelForm):
7 | class Meta:
8 | model = PrivateMessage
9 | fields = ('recipient', 'subject', 'message')
10 |
11 | def __init__(self, *args, **kwargs):
12 | super(PrivateMessageForm, self).__init__(*args, **kwargs)
13 | self.fields['subject'].widget.attrs['class'] = 'xxlarge'
14 | self.fields['message'].widget.attrs['class'] = 'xxlarge'
15 | self.fields['recipient'].widget.attrs['class'] = 'chosen'
16 |
--------------------------------------------------------------------------------
/wiki/management/commands/remarkdown.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand, CommandError
2 |
3 | from wiki.models import Page
4 | from wiki.templatetags.wikinotes_markup import wikinotes_markdown
5 |
6 |
7 | class Command(BaseCommand):
8 | help = "Refreshes the content field of pages by re-processing all the markdown"
9 |
10 | def handle(self, *args, **options):
11 | pages = Page.objects.all()
12 | for page in pages:
13 | content = page.load_content()
14 | page.content = wikinotes_markdown(content)
15 | page.save()
16 | self.stdout.write("Refreshed %s\n" % page)
17 |
--------------------------------------------------------------------------------
/templates/messages/base.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 | Private messages :: {{ this_mode|capfirst }}
7 |
14 |
15 | {% block inner_content %}{% endblock %}
16 |
17 |
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/templates/main/ucp.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 | User control panel
7 |
16 | {% include template %}
17 |
18 |
19 | {% endblock %}
20 |
--------------------------------------------------------------------------------
/assets/css/prettify.css:
--------------------------------------------------------------------------------
1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
--------------------------------------------------------------------------------
/templates/pages/professor_id_field.html:
--------------------------------------------------------------------------------
1 | Professor:
2 |
3 |
4 |
5 |
6 | Select a professor (optional)
7 | {% for professor in professors %}
8 | {{ professor }}
9 | {% endfor %}
10 |
11 | Can't find your professor in the list? Send us an email at admin@wikinotes.ca.
12 |
13 |
--------------------------------------------------------------------------------
/fabfile.py:
--------------------------------------------------------------------------------
1 | from fabric.api import *
2 |
3 |
4 | def less():
5 | local("lessc -x assets/css/bootstrap.less > assets/css/bootstrap.css")
6 |
7 |
8 | def broadcast():
9 | local("python manage.py runserver 0.0.0.0:8000")
10 |
11 |
12 | def up():
13 | local("python manage.py runserver --insecure")
14 |
15 |
16 | def test():
17 | local("python manage.py test wiki")
18 |
19 |
20 | def refresh():
21 | local("python manage.py remarkdown")
22 |
23 |
24 | def sh():
25 | local("python manage.py shell")
26 |
27 |
28 | def backup():
29 | local("python manage.py dumpdata > backup.json")
30 |
31 |
32 | def restart():
33 | local("kill -HUP `cat /tmp/gunicorn.pid`")
34 |
--------------------------------------------------------------------------------
/templates/main/login_error.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 | Login error
7 |
8 |
The username and password combination you entered is invalid.
9 |
10 | If you've forgotten your password, send an email to
11 | admin@wikinotes.ca and we'll reset it for you.
12 |
13 |
14 | Haven't registered yet?
15 |
16 |
17 |
18 |
19 | {% endblock %}
20 |
--------------------------------------------------------------------------------
/templates/news/main.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% load wikinotes_markup %}
5 |
6 |
7 |
8 | {% for post in blog_posts %}
9 |
10 |
11 |
{{ post.timestamp }}
12 |
{{ post.get_num_comments }} comment{{ post.get_num_comments|pluralize }}
13 | {{ post.body|wikinotes_markdown|safe }}
14 |
15 | {% endfor %}
16 |
17 |
18 |
19 |
20 |
21 | {% endblock %}
22 |
--------------------------------------------------------------------------------
/templates/pages/semester_field.html:
--------------------------------------------------------------------------------
1 | Associated semester
2 |
14 |
--------------------------------------------------------------------------------
/assets/css/bootstrap.less:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap @VERSION
3 | *
4 | * Copyright 2011 Twitter, Inc
5 | * Licensed under the Apache License v2.0
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Designed and built with all the love in the world @twitter by @mdo and @fat.
9 | * Date: @DATE
10 | */
11 |
12 | // CSS Reset
13 | @import "reset.less";
14 |
15 | // Core variables and mixins
16 | @import "variables.less";
17 | @import "mixins.less";
18 |
19 | // Grid system and page structure
20 | @import "scaffolding.less";
21 |
22 | // Styled patterns and elements
23 | @import "type.less";
24 | @import "forms.less";
25 | @import "tables.less";
26 | @import "patterns.less";
27 |
28 | @import "markdown.less";
29 |
30 | @import "wikinotes.less";
31 | @import "pygments.less";
32 |
33 | @import "chosen.less";
34 |
--------------------------------------------------------------------------------
/mdx/mdx_mathjax.py:
--------------------------------------------------------------------------------
1 | """
2 | From https://github.com/mayoff/python-markdown-mathjax
3 | """
4 |
5 | import markdown
6 |
7 | class MathJaxPattern(markdown.inlinepatterns.Pattern):
8 |
9 | def __init__(self):
10 | markdown.inlinepatterns.Pattern.__init__(self, r'(?
5 |
6 | Unauthorised access
7 | Unfortunately, it seems that you do not have permission to access this page.
8 | {% if user.is_authenticated %}
9 | If you have permission to access this page under a different account, please log out and sign in under that account.
10 | {% else %}
11 | If you have an account which does have permission to access this page, please sign in.
12 | {% endif %}
13 |
14 | If you have any questions about why we're suddenly restricting access or what pages we've restricted, please contact us (admin at the wikinotes domain). More information on this will be available soon.
15 |
16 |
17 | {% endblock %}
18 |
--------------------------------------------------------------------------------
/templates/messages/inbox.html:
--------------------------------------------------------------------------------
1 | {% extends "messages/base.html" %}
2 |
3 | {% block inner_content %}
4 | {% if messages.count %}
5 |
23 | {% else %}
24 | You have no messages.
25 | {% endif %}
26 | {% endblock %}
27 |
--------------------------------------------------------------------------------
/templates/messages/outbox.html:
--------------------------------------------------------------------------------
1 | {% extends "messages/base.html" %}
2 |
3 | {% block inner_content %}
4 | {% if messages.count %}
5 |
23 | {% else %}
24 | You have no sent messages.
25 | {% endif %}
26 | {% endblock %}
27 |
--------------------------------------------------------------------------------
/templates/pages/create_popup.html:
--------------------------------------------------------------------------------
1 |
17 |
--------------------------------------------------------------------------------
/mdx/mdx_mentions.py:
--------------------------------------------------------------------------------
1 | """
2 | To mention a user: @theirusername
3 |
4 | Will add doctests later
5 | """
6 |
7 | import markdown
8 |
9 | # Global Vars
10 | MENTION_RE = r'(?\w+)'
11 | # '[@' + username + '](/user/' + username + ')'
12 |
13 | class MentionPattern(markdown.inlinepatterns.Pattern):
14 | def handleMatch(self, m):
15 | username = m.group('username')
16 |
17 | el = markdown.util.etree.Element('a')
18 | el.text = '@' + username
19 | el.set('href', '/users/' + username)
20 | return el
21 |
22 | class MentionExtension(markdown.Extension):
23 |
24 | def extendMarkdown(self, md, md_globals):
25 | md.inlinePatterns['mention'] = MentionPattern(MENTION_RE, md)
26 |
27 | def makeExtension(configs=None):
28 | return MentionExtension(configs=configs)
29 |
30 | if __name__ == "__main__":
31 | import doctest
32 | doctest.testmod()
33 |
--------------------------------------------------------------------------------
/templates/pages/create.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
7 |
Creating a page :: {{ page_type.long_name }}
8 |
13 | {% if does_not_exist %}
14 |
The page you requested does not exist! Create it now?
15 | {% endif %}
16 | {% include "pages/form.html" %}
17 |
18 |
19 |
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/wiki/tests/series.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | from wiki.models.courses import Course
4 | from wiki.models.pages import Page
5 | from wiki.models.series import Series
6 |
7 |
8 | class TestGetNextPosition(TestCase):
9 | fixtures = ['test']
10 |
11 | def setUp(self):
12 | self.series = Series.objects.create(course=Course.objects.get(pk=1),
13 | name='new', position=2, slug='new')
14 |
15 | def test_empty_series(self):
16 | self.assertEqual(self.series.get_next_position(), 1)
17 |
18 | def test_nonempty_series(self):
19 | page_1 = Page.objects.get(pk=1)
20 | page_2 = Page.objects.get(pk=2)
21 | self.series.seriespage_set.create(page=page_1, position=1)
22 | self.assertEqual(self.series.get_next_position(), 2)
23 | self.series.seriespage_set.create(page=page_2, position=2)
24 | self.assertEqual(self.series.get_next_position(), 3)
25 |
--------------------------------------------------------------------------------
/wiki/models/departments.py:
--------------------------------------------------------------------------------
1 | from django.core.urlresolvers import reverse
2 | from django.db import models
3 |
4 |
5 | class Department(models.Model):
6 | short_name = models.CharField(max_length=4, primary_key=True)
7 | long_name = models.CharField(max_length=255)
8 | faculty = models.ForeignKey('Faculty')
9 | url_fields = {
10 | 'department': 'short_name__iexact',
11 | }
12 |
13 | class Meta:
14 | app_label = 'wiki'
15 | ordering = ['short_name']
16 |
17 | def __unicode__(self):
18 | return "Department of %s (%s)" % (self.long_name, self.short_name)
19 |
20 | def get_absolute_url(self):
21 | return reverse('courses_department_overview', args=[self.pk])
22 |
23 | def get_image(self):
24 | return "/static/img/department/%s.png" % self.short_name
25 |
26 | def get_large_image(self):
27 | return "/static/img/department/%s_large.png" % self.short_name
28 |
--------------------------------------------------------------------------------
/templates/pages/edit.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
7 |
Editing {{ page.get_title }}
8 |
15 | {% include "pages/form.html" %}
16 |
17 |
18 |
19 | {% endblock %}
20 |
--------------------------------------------------------------------------------
/templates/search/results.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 | Search results for {{ query }}
7 | Courses
8 | {% if course_results %}
9 |
14 | {% else %}
15 | No courses found containing {{ query }} in their name, number or description.
16 |
17 | {% endif %}
18 |
19 |
20 |
21 | The search feature is still under construction. Got a suggestion for
22 | how search should behave?
23 | Let us know!
24 |
25 |
26 |
27 | {% endblock %}
28 |
--------------------------------------------------------------------------------
/templates/pages/series_listing.html:
--------------------------------------------------------------------------------
1 | {% with series_pages=page.seriespage_set.all %}
2 | {% if series_pages %}
3 |
4 |
5 | {% for series_page in series_pages %}
6 | {% with position=series_page.position series=series_page.series previous=series_page.get_previous_page next=series_page.get_next_page %}
7 | {% if previous %}« Previous :: {% endif %}{{ position }} of {{ series.get_num_total }} in {{ series.name }} {% if next %} :: Next » {% endif %}
8 | {% endwith %}
9 | {% endfor %}
10 |
11 | {% endif %}
12 | {% endwith %}
13 |
--------------------------------------------------------------------------------
/mdx/mdx_downheader.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | import markdown
3 | import re
4 |
5 | def makeExtension(configs=None) :
6 | return DownHeaderExtension(configs=configs)
7 |
8 | class DownHeaderExtension(markdown.Extension):
9 | def extendMarkdown(self, md, md_globals):
10 | if 'downheader' in md.treeprocessors.keys():
11 | md.treeprocessors['downheader'].offset += 1
12 | else:
13 | md.treeprocessors.add('downheader', DownHeaderProcessor(), '_end')
14 |
15 | class DownHeaderProcessor(markdown.treeprocessors.Treeprocessor):
16 | def __init__(self, offset=1):
17 | markdown.treeprocessors.Treeprocessor.__init__(self)
18 | self.offset = offset
19 | def run(self, node):
20 | expr = re.compile('h(\d)')
21 | for child in node.getiterator():
22 | match = expr.match(child.tag)
23 | if match:
24 | child.tag = 'h' + str(min(6, int(match.group(1))+self.offset))
25 | return node
26 |
--------------------------------------------------------------------------------
/templates/404.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 |
3 | {% block content %}
4 |
5 |
6 |
7 |
8 |
9 |
10 | We can't seem to find the page you're looking for. Sorry! Please
11 | keep in mind that this site is still under development, and so not
12 | all the pages and features are complete. Feel free to contact us by
13 | email, Facebook or
14 | Twitter if you have questions, comments, or suggestions relating
15 | to the site.
16 |
17 |
18 | If you're trying to access a course that we don't have in our
19 | database, you can always create it yourself &endash;
20 | Create a course
21 |
22 |
23 |
24 | {% endblock %}
25 |
--------------------------------------------------------------------------------
/blog/models.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.models import User
2 | from django.core.urlresolvers import reverse
3 | from django.db import models
4 |
5 |
6 | class BlogPost(models.Model):
7 | author = models.ForeignKey(User)
8 | title = models.CharField(max_length=50)
9 | timestamp = models.DateTimeField()
10 | body = models.TextField()
11 | summary = models.CharField(max_length=100)
12 | slug = models.SlugField()
13 | url_fields = {
14 | 'slug': 'slug',
15 | }
16 |
17 | class Meta:
18 | ordering = ['-timestamp']
19 |
20 | def __unicode__(self):
21 | return "%s (%s)" % (self.title, self.timestamp.strftime("%B %d, %Y"))
22 |
23 | def get_absolute_url(self):
24 | return reverse('news_view', args=[self.slug])
25 |
26 | def get_num_comments(self):
27 | return self.blogcomment_set.count()
28 |
29 |
30 | class BlogComment(models.Model):
31 | author = models.ForeignKey(User)
32 | post = models.ForeignKey(BlogPost)
33 | body = models.TextField()
34 |
--------------------------------------------------------------------------------
/wiki/forms/courses.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from django.utils.safestring import mark_safe
3 |
4 | from wiki.models.courses import Course
5 |
6 |
7 | class CourseForm(forms.ModelForm):
8 | class Meta:
9 | model = Course
10 | exclude = ('watchers', 'num_watchers', 'latest_activity')
11 |
12 | def clean(self):
13 | # Make sure we don't already have this course
14 | cleaned_data = super(CourseForm, self).clean()
15 | department = cleaned_data.get('department')
16 | number = cleaned_data.get('number')
17 | matching = Course.objects.filter(department=department, number=number)
18 |
19 | if matching.exists():
20 | course = matching[0]
21 | course_url = course.get_absolute_url()
22 | course_link = '%s ' % (course_url, course)
23 | raise forms.ValidationError(mark_safe("The course you're trying to"
24 | " create already exists: %s." % course_link))
25 |
26 | return cleaned_data
27 |
--------------------------------------------------------------------------------
/templates/courses/popular.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
9 |
10 |
11 |
Shows the courses, listed by popularity (defined by number of watchers maybe)
12 | {% for dept in departments %}
13 |
14 | {% if dept.courses %}
15 |
16 | {% for course in dept.courses %}
17 | {{ course }}
18 | {% endfor %}
19 |
20 | {% else %}
21 |
No courses in this department
22 | {% endif %}
23 | {% endfor %}
24 |
25 |
26 |
27 |
28 | {% endblock %}
29 |
--------------------------------------------------------------------------------
/templates/courses/faculty_browse.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
9 |
10 |
11 |
Shows all the courses, listed alphabetically under the relevant faculty.
12 | {% for faculty, courses in faculties %}
13 |
14 | {% if courses %}
15 |
16 | {% for course in courses %}
17 | {{ course }}
18 | {% endfor %}
19 |
20 | {% else %}
21 |
No courses in this faculty
22 | {% endif %}
23 | {% endfor %}
24 |
25 |
26 |
27 |
28 | {% endblock %}
29 |
--------------------------------------------------------------------------------
/templates/messages/view.html:
--------------------------------------------------------------------------------
1 | {% extends "messages/base.html" %}
2 |
3 | {% load wikinotes_markup %}
4 | {% load url from future %}
5 |
6 | {% block inner_content %}
7 | {% if show_reply %}
8 |
11 | {% endif %}
12 |
13 |
14 |
15 | From:
16 | {{ message.sender }}
17 |
18 |
19 | To:
20 | {{ message.recipient }}
21 |
22 |
23 | Subject:
24 | {{ message.subject }}
25 |
26 |
27 | Sent on:
28 | {{ message.timestamp }}
29 |
30 |
31 | Message:
32 | {{ message.message|wikinotes_markdown|safe }}
33 |
34 |
35 | {% endblock %}
36 |
--------------------------------------------------------------------------------
/templates/pages/printview.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ page }} - WikiNotes
6 |
7 |
8 |
16 |
17 |
18 |
19 |
{{ page.get_title }}
20 | {% if page.subject %}{{ page.subject }} {% endif %}
21 |
22 |
23 | {{ page_type.long_name }} for {{ page.course_sem }}, available for
24 | free on WikiNotes under a Creative Commons license (CC-BY-NC). View
25 | the current version at {{ site_url }}/{{ page.get_absolute_url }}.
26 |
27 |
28 | {{ page.content|safe }}
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/mdx/mdx_plotly.py:
--------------------------------------------------------------------------------
1 | """Plot.ly extension for Markdown.
2 |
3 | Expected format: {plot dellsystem 0}
4 | """
5 |
6 | import markdown
7 |
8 | PLOTLY_RE = r'\{plot ([^ ]+) (\d+)\}'
9 | WIDTH = 940
10 | HEIGHT = 500
11 |
12 | class PlotLyPattern(markdown.inlinepatterns.Pattern):
13 | def handleMatch(self, m):
14 | username = m.group(2)
15 | plot_id = m.group(3)
16 |
17 | el = markdown.util.etree.Element('iframe')
18 | el.attrib['width'] = str(WIDTH)
19 | el.attrib['height'] = str(HEIGHT)
20 | el.attrib['scrolling'] = 'no'
21 | el.attrib['seamless'] = 'seamless'
22 | el.attrib['src'] = 'https://plot.ly/~%s/%s/%d/%d' % (username,
23 | plot_id,
24 | WIDTH,
25 | HEIGHT)
26 | return el
27 |
28 | class PlotLyExtension(markdown.Extension):
29 | """Plot.ly extension for Python-Markdown. """
30 |
31 | def extendMarkdown(self, md, md_globals):
32 | md.inlinePatterns['plotly'] = PlotLyPattern(PLOTLY_RE, md)
33 |
34 | def makeExtension(configs=None):
35 | return PlotLyExtension(configs=configs)
36 |
--------------------------------------------------------------------------------
/wiki/utils/history.py:
--------------------------------------------------------------------------------
1 | import datetime
2 |
3 |
4 | # Put here because, why not
5 | def get_date_x_days_ago(num_days):
6 | return datetime.datetime.now() - datetime.timedelta(days=num_days)
7 |
8 |
9 | # Used by HistoryItem to output a human-readable timestamp
10 | # More vague than the built-in timesince filter, which is good
11 | # Written by Joey Bratton http://www.joeyb.org/blog/2009/10/08/custom-django-template-filter-for-humanized-timesince
12 | def humanise_timesince(start_time):
13 | delta = datetime.datetime.now() - start_time
14 |
15 | plural = lambda x: 's' if x != 1 else ''
16 |
17 | num_years = delta.days / 365
18 | if (num_years > 0):
19 | return "%d year%s" % (num_years, plural(num_years))
20 |
21 | num_weeks = delta.days / 7
22 | if (num_weeks > 0):
23 | return "%d week%s" % (num_weeks, plural(num_weeks))
24 |
25 | if (delta.days > 0):
26 | return "%d day%s" % (delta.days, plural(delta.days))
27 |
28 | num_hours = delta.seconds / 3600
29 | if (num_hours > 0):
30 | return "%d hour%s" % (num_hours, plural(num_hours))
31 |
32 | num_minutes = delta.seconds / 60
33 | if (num_minutes > 0):
34 | return "%d minute%s" % (num_minutes, plural(num_minutes))
35 |
36 | return "a few seconds"
37 |
--------------------------------------------------------------------------------
/wiki/templatetags/wikinotes_markup.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 | import markdown
4 | from django import template
5 | from django.utils.html import escape
6 |
7 | register = template.Library()
8 |
9 | """
10 | Extensions are either part of the standard markdown library or located in the root directory, as mdx_{extension name}.py
11 |
12 | Standard extensions used, unmodified:
13 | * footnotes
14 | * nl2br
15 |
16 | All extensions beginning with wiki_ are modified version of standard extensions.
17 |
18 | mentions converts all @mentions to [@mention](/user/mention) (though in straight HTML), doesn't check if the user exists or not because it's not that smart but otherwise it shouldn't be too problematic
19 | """
20 |
21 | md = markdown.Markdown(extensions=['mentions', 'wiki_footnotes', 'wiki_toc', 'downheader', 'wiki_tables', 'wiki_codehilite', 'wiki_fenced_code', 'wiki_def_list', 'nl2br', 'subscript', 'superscript', 'mathjax', 'urlize', 'wikilinks', 'plotly'], safe_mode='escape', output_format='xhtml1')
22 |
23 |
24 | # NEEDS TESTS
25 | @register.filter()
26 | def wikinotes_markdown(value):
27 | # Must reset it to clear the footnotes and maybe other stuff too
28 | md.reset()
29 | # Replace \$ with \\$ so that markdown doesn't do anything else to (in conjunction with mathjax's processEscapes)
30 | return md.convert(value)
31 |
--------------------------------------------------------------------------------
/templates/courses/professor_browse.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
9 |
10 |
11 |
Shows all the courses, listed alphabetically under the relevant professor.
12 | {% for professor in professors %}
13 |
18 | {% with courses=professor.get_courses %}
19 | {% if courses.count %}
20 |
21 | {% for course in courses %}
22 | {{ course }}
23 | {% endfor %}
24 |
25 | {% else %}
26 |
This professor has no associated courses.
27 | {% endif %}
28 | {% endwith %}
29 | {% endfor %}
30 |
31 |
32 |
33 |
34 | {% endblock %}
35 |
--------------------------------------------------------------------------------
/templates/courses/department_overview.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
18 |
19 | Courses
20 | {% if courses %}
21 |
22 | {% for course in courses %}
23 | {{ course }}
24 | {% endfor %}
25 |
26 | {% endif %}
27 | Active contributors
28 | List of people who have made a lot of edits to courses (maybe order in terms of deltas) in this department
29 | Recent activity
30 | List of recent edits/etc to courses in this department
31 |
32 |
33 |
34 | {% endblock %}
35 |
--------------------------------------------------------------------------------
/templates/courses/department_browse.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
9 |
10 |
11 |
Shows all the courses, listed alphabetically under the relevant department.
12 | {% for dept in departments %}
13 |
18 | {% with courses=dept.course_set.all %}
19 | {% if courses.count %}
20 |
27 | {% else %}
28 |
No courses in this department
29 | {% endif %}
30 | {% endwith %}
31 | {% endfor %}
32 |
33 |
34 |
35 |
36 | {% endblock %}
37 |
--------------------------------------------------------------------------------
/templates/messages/compose.html:
--------------------------------------------------------------------------------
1 | {% extends "messages/base.html" %}
2 |
3 | {% block inner_content %}
4 |
5 |
51 | {% endblock %}
52 |
--------------------------------------------------------------------------------
/templates/static.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% load wikinotes_markup %}
5 |
6 |
7 |
8 |
9 |
10 |
{{ mode.title }} {{ page.title }}
11 |
12 | {% if markdown_file %}
13 | {% filter wikinotes_markdown %}{% include markdown_file %}{% endfilter %}
14 | {% else %}
15 | {% if html_file %}
16 | {% include html_file %}
17 | {% else %}
18 |
Coming soon
19 | {% endif %}
20 | {% endif %}
21 |
22 |
23 |
24 |
25 |
{{ mode.title }}
26 |
37 |
38 |
39 |
40 |
41 |
42 | {% endblock %}
43 |
--------------------------------------------------------------------------------
/templates/ucp/preferences.html:
--------------------------------------------------------------------------------
1 |
2 |
28 |
29 |
Configure if you want logged-in users to be able to see your email I guess. That's all I have for now.
30 |
31 |
32 |
--------------------------------------------------------------------------------
/mdx/mdx_subscript.py:
--------------------------------------------------------------------------------
1 | """Subscript extension for Markdown.
2 |
3 | To subscript something, place a tilde symbol, '~', before and after the
4 | text that you would like in subscript: C~6~H~12~O~6~
5 | The numbers in this example will be subscripted. See below for more:
6 |
7 | Examples:
8 |
9 | >>> import markdown
10 | >>> md = markdown.Markdown(extensions=['subscript'])
11 | >>> md.convert('This is sugar: C~6~H~12~O~6~')
12 | u'This is sugar: C6 H12 O6
'
13 |
14 | Paragraph breaks will nullify subscripts across paragraphs. Line breaks
15 | within paragraphs will not.
16 | """
17 |
18 | import markdown
19 |
20 | # Global Vars
21 | SUBSCRIPT_RE = r'(\~)([^\~]*)\2' # the number is subscript~2~
22 |
23 | class SubscriptPattern(markdown.inlinepatterns.Pattern):
24 | """ Return a subscript Element: `C~6~H~12~O~6~' """
25 | def handleMatch(self, m):
26 | subsc = m.group(3)
27 |
28 | text = subsc
29 |
30 | el = markdown.util.etree.Element("sub")
31 | el.text = markdown.util.AtomicString(text)
32 | return el
33 |
34 | class SubscriptExtension(markdown.Extension):
35 | """ Subscript Extension for Python-Markdown. """
36 |
37 | def extendMarkdown(self, md, md_globals):
38 | """ Replace subscript with SubscriptPattern """
39 | md.inlinePatterns['subscript'] = SubscriptPattern(SUBSCRIPT_RE, md)
40 |
41 | def makeExtension(configs=None):
42 | return SubscriptExtension(configs=configs)
43 |
44 | if __name__ == "__main__":
45 | import doctest
46 | doctest.testmod()
47 |
--------------------------------------------------------------------------------
/templates/courses/create.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
9 |
10 |
11 |
The department you want isn't in our database? Email the admins (admin at the wikinotes domain).
12 |
13 |
14 | {% if form.errors %}
15 |
16 |
Please correct the following errors:
17 |
18 | {% for field in form %}
19 | {% if field.errors %}
20 | {{ field.label_tag|striptags }} :{{ field.errors|striptags }}
21 | {% endif %}
22 | {% endfor %}
23 |
24 | {{ form.non_field_errors }}
25 |
26 | {% endif %}
27 |
28 |
44 |
45 |
46 | {% endblock %}
47 |
--------------------------------------------------------------------------------
/templates/courses/semester_overview.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block og_image %}
4 |
5 | {% endblock %}
6 | {% block content %}
7 |
8 |
9 |
10 |
14 | {{ course_sem.get_semester }}
15 |
16 | {% if pages %}
17 |
18 |
19 |
20 |
21 | Page
22 | Category
23 | Professor
24 |
25 |
26 |
27 | {% for page in pages %}
28 |
29 | {% include page.get_type.get_cell_template %}
30 | {{ page.get_type.long_name }}
31 | {% if page.professor %}{{ page.professor }} {% else %}N/A{% endif %}
32 |
33 | {% endfor %}
34 |
35 |
36 | {% endif %}
37 |
38 |
39 | {% endblock %}
40 |
--------------------------------------------------------------------------------
/wiki/tests/users.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.models import User
2 | from django.test import TestCase
3 |
4 | from wiki.models.users import UserProfile
5 | from wiki.models.pages import Page
6 | from wiki.models.history import HistoryItem
7 | from wiki.models.courses import Course
8 |
9 |
10 | class TestUserProfile(TestCase):
11 | fixtures = ['test']
12 |
13 | def setUp(self):
14 | self.user = User.objects.get(pk=1)
15 | self.profile = self.user.get_profile()
16 |
17 | def test_get_recent_pages(self):
18 | pages = Page.objects.all()
19 | course = Course.objects.get(pk=1)
20 |
21 | # First, edit page 1 twice
22 | HistoryItem.objects.create(user=self.user, action='edited', page=pages[0], course=course)
23 | HistoryItem.objects.create(user=self.user, action='edited', page=pages[0], course=course)
24 | # Then edit page 2 once
25 | HistoryItem.objects.create(user=self.user, action='edited', page=pages[1], course=course)
26 | # Then edit page 4 once
27 | HistoryItem.objects.create(user=self.user, action='edited', page=pages[3], course=course)
28 | # Then edit page 2 once
29 | HistoryItem.objects.create(user=self.user, action='edited', page=pages[1], course=course)
30 | # Then edit page 3 once
31 | HistoryItem.objects.create(user=self.user, action='edited', page=pages[2], course=course)
32 |
33 | self.assertEqual(self.profile.get_recent_pages(5), [pages[2], pages[1], pages[3], pages[0]])
34 | self.assertEqual(self.profile.get_recent_pages(3), [pages[2], pages[1], pages[3]])
35 |
36 | def tearDown(self):
37 | self.user.delete()
38 |
--------------------------------------------------------------------------------
/templates/courses/all_browse.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
10 | {% if courses %}
11 |
12 |
13 |
14 | Course
15 | Department
16 | Faculty
17 | Current professor(s)
18 | Watching
19 | Latest activity
20 |
21 |
22 |
23 | {% for course in courses %}
24 |
25 | {{ course }}
26 | {{ course.department.long_name }}
27 | {{ course.department.faculty }}
28 | None
29 | {{ course.num_watchers }}
30 | {{ course.latest_activity.timestamp|date:"F j Y f" }}
31 |
32 | {% endfor %}
33 |
34 |
35 | {% endif %}
36 |
37 |
38 | {% endblock %}
39 |
--------------------------------------------------------------------------------
/templates/ucp/account.html:
--------------------------------------------------------------------------------
1 |
2 |
39 |
40 |
You can change your password from this page.
41 |
42 |
43 |
--------------------------------------------------------------------------------
/wiki/tests/pages.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | from wiki.utils.pages import get_section_start_end
4 |
5 |
6 | class TestSectionEdit(TestCase):
7 | lines = [
8 | '# lol', # 0
9 | '## lol', # 1
10 | '# lol', # 2
11 | '# text', # 3
12 | 'blah blah blah', # 4
13 | '## Some subsection', # 5
14 | 'blah blah', # 6
15 | '### Another subsection', # 7
16 | '# Going back up', # 8
17 | 'text', # 9
18 | '```', # 10
19 | '# text', # 11
20 | '```', # 12
21 | '# Text', # 13
22 | ]
23 | tests = {
24 | # The first section
25 | 'lol': (0, 2),
26 | # The first subsection'
27 | 'lol_1': (1, 2),
28 | # A non-existent section
29 | 'header': (0, 14),
30 | # Another section
31 | 'lol_2': (2, 3),
32 | # Another non-existent section
33 | 'lol_3': (0, 14),
34 | # A longer section
35 | 'text': (3, 8),
36 | # Another subsection
37 | 'some-subsection': (5, 8),
38 | # Deeper subsection
39 | 'another-subsection': (7, 8),
40 | # Another section
41 | 'going-back-up': (8, 13),
42 | # Ignoring code blocks
43 | 'text_1': (13, 14),
44 | }
45 |
46 | def runTest(self):
47 | for anchor, expected in self.tests.iteritems():
48 | actual = get_section_start_end(self.lines, anchor)
49 | self.assertEqual(actual, expected)
50 |
--------------------------------------------------------------------------------
/wiki/utils/decorators.py:
--------------------------------------------------------------------------------
1 | from django.http import Http404
2 | from django.shortcuts import render
3 |
4 |
5 | def show_object_detail(model, show_custom_404=False,
6 | always_pass_groups=False):
7 | def wrapper(view):
8 | def new_view(request, **groups):
9 | filters = {}
10 | for group_name, field_name in model.url_fields.iteritems():
11 | # groups as in regex groups
12 | filters[field_name] = groups[group_name]
13 |
14 | try:
15 | instance = model.objects.get(**filters)
16 | kwargs = groups if always_pass_groups else {}
17 | except model.DoesNotExist:
18 | # If show_custom_404 is set, pass it None as the instance,
19 | # and pass the groups dictionary as well
20 | if show_custom_404:
21 | instance = None
22 | kwargs = groups
23 | else:
24 | raise Http404
25 |
26 | # Call the function to obtain the context dictionary. If it returns
27 | # something else (say, a redirect object), just return that.
28 | context = view(request, instance, **kwargs)
29 | if type(context) is not dict:
30 | return context
31 |
32 | # Figure out the template name based on the function name
33 | parent_module = view.__module__.split('.')[-1]
34 | function_name = view.func_name
35 | template_filename = '%s/%s.html' % (parent_module,
36 | function_name)
37 |
38 | return render(request, template_filename, context)
39 |
40 | return new_view
41 | return wrapper
42 |
--------------------------------------------------------------------------------
/templates/pages/date_field.html:
--------------------------------------------------------------------------------
1 | Date:
2 |
3 | Monday Tuesday Wednesday Thursday Friday January February March April May June July August September October November December 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
4 |
5 |
--------------------------------------------------------------------------------
/templates/help/lexers.md:
--------------------------------------------------------------------------------
1 | Here you can find a list of the more common languages we support syntax highlighting for, as well as some languages which we don't support directly but which can be highlighted using another language's lexer. For some of the languages, you will also find a short code sample for each language, highlighted with the relevant lexer.
2 |
3 | To see the entire list of languages, take a look at the [Pygments documentation](http://pygments.org/docs/lexers/).
4 |
5 | # Common languages
6 |
7 | **Format:**
8 |
9 | Name of language
10 | : short name (i.e. what to enter in the code block to make it highlight; if there are multiple short names, they are separated by a comma, and using any is acceptable)
11 |
12 | For example, if the short name were `somelang`, you can select that lexer by doing
13 |
14 | ```somelang
15 | [...]
16 | ```
17 |
18 | Bash
19 | : bash, sh, ksh
20 | Bash session
21 | : console
22 | C
23 | : c
24 | C++
25 | : c++, cpp
26 | CSS
27 | : css
28 | HTML
29 | : html
30 | Java
31 | : java
32 | Javascript
33 | : js, javascript
34 | Makefile
35 | : make, makefile, mf, bsdmake[^bsdmake]
36 | MATLAB
37 | : matlab
38 | MATLAB session
39 | : matlabsession
40 | MIPS
41 | : gas[^gas]
42 | PHP
43 | : php, php3, php4, php5
44 | Python console
45 | : pycon
46 | Python
47 | : python, py
48 | Python traceback
49 | : pytb
50 | Ruby console
51 | : rbcon, irb
52 | Ruby
53 | : rb, ruby, duby
54 | SML
55 | : ocaml[^ocaml]
56 | SQL
57 | : sql
58 | TeX
59 | : tex, latex
60 |
61 | # Code samples
62 |
63 | Later
64 |
65 | [^gas]: There is no actual lexer for MIPS, but the [gas lexer](http://en.wikipedia.org/wiki/GNU_Assembler) comes close.
66 | [^bsdmake]: For BSD makefiles.
67 | [^ocaml]: Sadly, there is no lexer for Standard ML. The OCaml lexer comes close, though.
68 |
--------------------------------------------------------------------------------
/templates/courses/category_overview.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block og_image %}
4 |
5 | {% endblock %}
6 |
7 | {% block content %}
8 |
9 |
10 |
14 |
17 | Viewing category :: {{ category.long_name }}
18 |
19 |
20 | {% if pages %}
21 |
22 |
23 |
24 | Page
25 | Semester
26 | Professor
27 |
28 |
29 |
30 | {% for page in pages %}
31 |
32 | {% include page.get_type.get_cell_template %}
33 | {{ page.course_sem.get_semester }}
34 | {% if page.professor %}{{ page.professor }} {% else %}N/A{% endif %}
35 |
36 | {% endfor %}
37 |
38 |
39 | {% else %}
40 | No pages in this category.
41 | {% endif %}
42 |
43 |
44 | {% endblock %}
45 |
--------------------------------------------------------------------------------
/templates/courses/professor_overview.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
9 |
10 | {% if professor.link %}
11 | Personal webpage : {{ professor.link }}
12 | {% endif %}
13 |
14 |
Associated pages
15 | {% if pages %}
16 |
17 |
18 |
19 | Department
20 | Course
21 | Semester
22 | Page
23 |
24 |
25 |
26 | {% for page in pages %}
27 | {% with course=page.course_sem.course %}
28 |
29 |
30 |
31 |
32 | {{ course }} ({{ course.name }})
33 |
34 |
35 | {{ page.course_sem.get_semester }}
36 | {{ page }}
37 |
38 | {% endwith %}
39 | {% endfor %}
40 |
41 |
42 | {% else %}
43 | There are no pages associated with this professor.
44 | {% endif %}
45 |
46 |
47 | {% endblock %}
48 |
--------------------------------------------------------------------------------
/wiki/models/history.py:
--------------------------------------------------------------------------------
1 | from django.core.urlresolvers import reverse
2 | from django.contrib.auth.models import User
3 | from django.db import models
4 |
5 | from wiki.utils.history import get_date_x_days_ago, humanise_timesince
6 |
7 |
8 | class HistoryManager(models.Manager):
9 | # Returns all the HistoryItems with a timestamp between now and x days ago
10 | def get_since_x_days(self, num_days, show_all):
11 | # If show_all is False, ignore watch actions (that's all it means)
12 | cutoff_date = get_date_x_days_ago(int(num_days))
13 | query_set = self.filter(timestamp__gt=cutoff_date).order_by('-timestamp')
14 |
15 | if not show_all:
16 | query_set = query_set.exclude(page__isnull=True)
17 | return query_set
18 |
19 |
20 | class HistoryItem(models.Model):
21 | objects = HistoryManager()
22 | user = models.ForeignKey(User)
23 | action = models.CharField(max_length=30)
24 | timestamp = models.DateTimeField(auto_now=True)
25 | page = models.ForeignKey('Page', null=True)
26 | message = models.CharField(max_length=255, null=True)
27 | course = models.ForeignKey('Course')
28 | hexsha = models.CharField(max_length=40, null=True) # only used for page editing
29 |
30 | class Meta:
31 | app_label = 'wiki'
32 |
33 | def __unicode__(self):
34 | return 'timestamp: %s, course: %s' % (self.timestamp, self.course)
35 |
36 | def get_absolute_url(self):
37 | if self.page:
38 | if self.hexsha:
39 | url_args = self.page.get_url_args() + (self.hexsha,)
40 | return reverse('pages_commit', args=url_args)
41 | else:
42 | return self.page.get_history_url()
43 | else:
44 | return self.course.get_recent_url()
45 |
46 | def get_timesince(self):
47 | return humanise_timesince(self.timestamp)
48 |
49 | def get_short_hexsha(self):
50 | if self.hexsha:
51 | return self.hexsha[:7]
52 | else:
53 | return ''
54 |
--------------------------------------------------------------------------------
/templates/courses/recent.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% load gravatar %}
5 |
6 |
7 |
11 | Recent activity
12 |
13 | {% if history %}
14 |
15 |
16 |
17 | User(s)
18 | Activity
19 | Commit
20 | Time
21 |
22 |
23 |
24 | {% for item in history %}
25 |
26 | {% gravatar_img_for_user item.user 20 %} {{ item.user.username }} {% if not item.page and item.group_count %} and {{ item.group_count }} other{{ item.group_count|pluralize }}{% endif %}
27 | {{ item.action }} {% if item.page %}{{ item.page }} {% if item.group_count %}{% if item.group_count == 1 %}twice{% else %}{{ item.group_count|add:"1" }} times{% endif %}{% endif %}{% endif %}
28 |
29 | {% if item.hexsha %}
30 |
31 | {{ item.get_short_hexsha }}
32 |
33 | {% else %}
34 | --
35 | {% endif %}
36 |
37 | {{ item.get_timesince}} ago
38 |
39 | {% endfor %}
40 |
41 |
42 | {% endif %}
43 |
44 |
45 | {% endblock %}
46 |
--------------------------------------------------------------------------------
/mdx/mdx_superscript.py:
--------------------------------------------------------------------------------
1 | """Superscipt extension for Markdown. From https://github.com/sgraber/markdown.superscript
2 |
3 | To superscript something, place a carat symbol, '^', before and after the
4 | text that you would like in superscript: 6.02 x 10^23^
5 | The '23' in this example will be superscripted. See below.
6 |
7 | Examples:
8 |
9 | >>> import markdown
10 | >>> md = markdown.Markdown(extensions=['superscript'])
11 | >>> md.convert('This is a reference to a footnote^1^.')
12 | u'This is a reference to a footnote1 .
'
13 |
14 | >>> md.convert('This is scientific notation: 6.02 x 10^23^')
15 | u'This is scientific notation: 6.02 x 1023
'
16 |
17 | >>> md.convert('This is scientific notation: 6.02 x 10^23. Note lack of second carat.')
18 | u'This is scientific notation: 6.02 x 10^23. Note lack of second carat.
'
19 |
20 | >>> md.convert('Scientific notation: 6.02 x 10^23. Add carat at end of sentence.^')
21 | u'Scientific notation: 6.02 x 1023. Add a carat at the end of sentence. .
'
22 |
23 | Paragraph breaks will nullify superscripts across paragraphs. Line breaks
24 | within paragraphs will not.
25 |
26 | """
27 |
28 | import markdown
29 |
30 | # Global Vars
31 | SUPERSCRIPT_RE = r'(\^)([^\^]*)\2' # the number is a superscript^2^
32 |
33 | class SuperscriptPattern(markdown.inlinepatterns.Pattern):
34 | """ Return a superscript Element (`word^2^`). """
35 | def handleMatch(self, m):
36 | supr = m.group(3)
37 |
38 | text = supr
39 |
40 | el = markdown.util.etree.Element("sup")
41 | el.text = markdown.util.AtomicString(text)
42 | return el
43 |
44 | class SuperscriptExtension(markdown.Extension):
45 | """ Superscript Extension for Python-Markdown. """
46 |
47 | def extendMarkdown(self, md, md_globals):
48 | """ Replace superscript with SuperscriptPattern """
49 | md.inlinePatterns['superscript'] = SuperscriptPattern(SUPERSCRIPT_RE, md)
50 |
51 | def makeExtension(configs=None):
52 | return SuperscriptExtension(configs=configs)
53 |
54 | if __name__ == "__main__":
55 | import doctest
56 | doctest.testmod()
57 |
--------------------------------------------------------------------------------
/assets/css/variables.less:
--------------------------------------------------------------------------------
1 | /* Variables.less
2 | * Variables to customize the look and feel of Bootstrap
3 | * ----------------------------------------------------- */
4 |
5 |
6 | // Links
7 | @linkColor: #2F8DA8;
8 | @linkColorHover: darken(@linkColor, 15);
9 |
10 | // Grays
11 | @black: #000;
12 | @grayDark: lighten(@black, 25%);
13 | @gray: lighten(@black, 50%);
14 | @grayLight: lighten(@black, 75%);
15 | @grayLighter: lighten(@black, 90%);
16 | @white: #fff;
17 |
18 | // Accent Colors
19 | @blue: #5bc0de;
20 | @blueDark: #339bb9;
21 | @green: #46a546;
22 | @red: #9d261d;
23 | @yellow: #ffc40d;
24 | @orange: #f89406;
25 | @pink: #c3325f;
26 | @purple: #7a43b6;
27 |
28 | // Baseline grid
29 | @basefont: 13px;
30 | @baseline: 18px;
31 |
32 | // Griditude
33 | // Modify the grid styles in mixins.less
34 | @gridColumns: 16;
35 | @gridColumnWidth: 40px;
36 | @gridGutterWidth: 20px;
37 | @extraSpace: (@gridGutterWidth * 2); // For our grid calculations
38 | @siteWidth: (@gridColumns * @gridColumnWidth) + (@gridGutterWidth * (@gridColumns - 1));
39 |
40 | // Color Scheme
41 | // Use this to roll your own color schemes if you like (unused by Bootstrap by default)
42 | @baseColor: @blue; // Set a base color
43 | @complement: spin(@baseColor, 180); // Determine a complementary color
44 | @split1: spin(@baseColor, 158); // Split complements
45 | @split2: spin(@baseColor, -158);
46 | @triad1: spin(@baseColor, 135); // Triads colors
47 | @triad2: spin(@baseColor, -135);
48 | @tetra1: spin(@baseColor, 90); // Tetra colors
49 | @tetra2: spin(@baseColor, -90);
50 | @analog1: spin(@baseColor, 22); // Analogs colors
51 | @analog2: spin(@baseColor, -22);
52 |
53 |
54 |
55 | // More variables coming soon:
56 | // - @basefont to @baseFontSize
57 | // - @baseline to @baseLineHeight
58 | // - @baseFontFamily
59 | // - @primaryButtonColor
60 | // - anything else? File an issue on GitHub
61 |
--------------------------------------------------------------------------------
/templates/courses/faculty_overview.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
16 |
17 | Departments
18 |
19 | {% for dept in departments %}
20 |
24 | {% if forloop.counter|divisibleby:8 %}
25 |
26 |
27 | {% endif %}
28 | {% empty %}
29 |
This faculty has no departments
30 | {% endfor %}
31 |
32 | Courses
33 |
34 | {% for course in courses %}
35 |
39 | {% if forloop.counter|divisibleby:8 %}
40 |
41 |
42 | {% endif %}
43 | {% empty %}
44 |
This faculty also has no courses
45 | {% endfor %}
46 |
47 | Active contributors
48 | List of people who have made a lot of edits to courses (maybe order in terms of deltas) in this faculty
49 | Recent activity
50 | List of recent edits/etc to courses in this faculty
51 |
52 |
53 |
54 | {% endblock %}
55 |
--------------------------------------------------------------------------------
/mdx/mdx_urlize.py:
--------------------------------------------------------------------------------
1 | """A more liberal autolinker
2 |
3 | Inspired by Django's urlize function.
4 |
5 | Positive examples:
6 |
7 | >>> import markdown
8 | >>> md = markdown.Markdown(extensions=['urlize'])
9 |
10 | >>> md.convert('http://example.com/')
11 | u'http://example.com/
'
12 |
13 | >>> md.convert('go to http://example.com')
14 | u'go to http://example.com
'
15 |
16 | >>> md.convert('example.com')
17 | u'example.com
'
18 |
19 | >>> md.convert('example.net')
20 | u'example.net
'
21 |
22 | >>> md.convert('www.example.us')
23 | u'www.example.us
'
24 |
25 | >>> md.convert('(www.example.us/path/?name=val)')
26 | u'(www.example.us/path/?name=val )
'
27 |
28 | >>> md.convert('go to now!')
29 | u'go to http://example.com now!
'
30 |
31 | Negative examples:
32 |
33 | >>> md.convert('del.icio.us')
34 | u'del.icio.us
'
35 |
36 | """
37 |
38 | import markdown
39 |
40 | # Global Vars
41 | URLIZE_RE = '(%s)' % '|'.join([
42 | r'<(?:f|ht)tps?://[^>]*>',
43 | r'\b(?:f|ht)tps?://[^)<>\s]+[^.,)<>\s]',
44 | r'\bwww\.[^)<>\s]+[^.,)<>\s]',
45 | r'[^(<\s]+\.(?:com|net|org|ca)\b',
46 | ])
47 |
48 | class UrlizePattern(markdown.inlinepatterns.Pattern):
49 | """ Return a link Element given an autolink (`http://example/com`). """
50 | def handleMatch(self, m):
51 | url = m.group(2)
52 |
53 | if url.startswith('<'):
54 | url = url[1:-1]
55 |
56 | text = url
57 |
58 | if not url.split('://')[0] in ('http','https','ftp'):
59 | if '@' in url and not '/' in url:
60 | url = 'mailto:' + url
61 | else:
62 | url = 'http://' + url
63 |
64 | el = markdown.util.etree.Element("a")
65 | el.set('href', url)
66 | el.text = markdown.util.AtomicString(text)
67 | return el
68 |
69 | class UrlizeExtension(markdown.Extension):
70 | """ Urlize Extension for Python-Markdown. """
71 |
72 | def extendMarkdown(self, md, md_globals):
73 | """ Replace autolink with UrlizePattern """
74 | md.inlinePatterns['autolink'] = UrlizePattern(URLIZE_RE, md)
75 |
76 | def makeExtension(configs=None):
77 | return UrlizeExtension(configs=configs)
78 |
79 | if __name__ == "__main__":
80 | import doctest
81 | doctest.testmod()
82 |
--------------------------------------------------------------------------------
/templates/main/recent.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% load gravatar %}
5 |
63 | {% endblock %}
64 |
--------------------------------------------------------------------------------
/templates/pages/history.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% load url from future %}
3 |
4 | {% block content %}
5 | {% load gravatar %}
6 |
7 |
8 |
15 | Viewing history :: {{ page }}
16 |
17 | {% if commit_history %}
18 |
19 |
20 |
21 | Author
22 | Edit message
23 | Date
24 | Stats
25 | Options
26 |
27 |
28 |
29 | {% for commit in commit_history %}
30 |
31 | {% gravatar_img_for_user commit.author_name 20 %}
32 |
33 | {{ commit.author_name }}
34 |
35 |
36 | {{ commit.message|truncatechars:70|escape }}
37 | {{ commit.get_date|date:"D, j M, Y H:i" }}
38 |
39 |
45 | {{ commit.num_lines }} lines
46 | (+{{ commit.num_insertions }},
47 | -{{ commit.num_deletions }})
48 |
49 |
50 |
51 | View details
52 |
53 |
54 |
55 | {% endfor %}
56 |
57 |
58 | {% endif %}
59 |
60 |
61 | {% endblock %}
62 |
--------------------------------------------------------------------------------
/wiki/utils/pages.py:
--------------------------------------------------------------------------------
1 | import inspect
2 | import re
3 |
4 | from markdown.extensions.headerid import slugify
5 |
6 | from wiki.models import page_types as types
7 |
8 |
9 | # A dictionary for reverse lookup of page type by the short name
10 | # So, given "course-quiz", find the CourseQuiz object etc
11 | page_types = {}
12 | for name, obj in inspect.getmembers(types):
13 | if inspect.isclass(obj):
14 | # Because it returns a tuple. There is probably a better way of doing it but issubclass() doesn't work so don't try it
15 | if obj.__bases__ == (types.PageType,):
16 | page_types[obj.short_name] = obj()
17 |
18 | page_type_choices = tuple([(name, obj.long_name) for name, obj in page_types.iteritems()])
19 |
20 |
21 | def get_section_start_end(lines, anchor_name):
22 | """
23 | THIS NEEDS TESTS
24 | """
25 | # If there's an underscore + a number at the end of the slug
26 | section_number_match = re.match('[^_]*_(\d+)', anchor_name)
27 | if section_number_match:
28 | section_number = int(section_number_match.group(1))
29 | # Strip the underscore + number
30 | section_name = re.match('[^_]*', anchor_name).group()
31 | else:
32 | section_number = 0
33 | section_name = anchor_name
34 |
35 | # Start going through the lines, one by one, looking for perfect headers
36 | in_code_block = False
37 | num_found = 0
38 | last_depth = 5
39 | start = 0
40 | end = len(lines)
41 | looking_for_end = False
42 |
43 | # Set up some regular expressions
44 | code_block_re = re.compile('[~`]{3,}')
45 | header_re = re.compile('(#{1,5}) ?(.+)')
46 |
47 | for line_number, line in enumerate(lines):
48 | # Ignore headers inside code blocks
49 | code_block_match = code_block_re.match(line)
50 | if code_block_match:
51 | in_code_block = not in_code_block
52 |
53 | if in_code_block:
54 | continue
55 |
56 | header_match = header_re.match(line)
57 | if header_match:
58 | # Figure out the depth (needed to determine the end of the section)
59 | header_depth = len(header_match.group(1))
60 | if header_depth <= last_depth and looking_for_end:
61 | end = line_number
62 | looking_for_end = False
63 |
64 | # Save the name of the section here
65 | header = unicode(header_match.group(2))
66 | if slugify(header, '-') == section_name:
67 | # This is a potential header!
68 | if num_found == section_number:
69 | # This is the right one. Start looking for the end
70 | looking_for_end = True
71 | start = line_number
72 | last_depth = header_depth
73 |
74 | num_found += 1
75 |
76 | return (start, end)
77 |
--------------------------------------------------------------------------------
/templates/pages/form.html:
--------------------------------------------------------------------------------
1 |
77 |
--------------------------------------------------------------------------------
/templates/pages/edit_buttons.html:
--------------------------------------------------------------------------------
1 |
7 |
24 |
--------------------------------------------------------------------------------
/templates/about/licensing.md:
--------------------------------------------------------------------------------
1 | All of the course-related content on WikiNotes is available under a [Creative Commons non-commercial license](http://creativecommons.org/licenses/by-nc/3.0/). By course-related content, we mean the editable pages on this site associated with a specific course. This [BIOL 111 organism chart](/BIOL_111/summary/fall-2011/organism-chart), this [guide on solving propositional logic problems for MATH 318](/MATH_318/summary/fall-2011/htsefp-propositional-logic) and this [guide on solving combinational logic problems for COMP 273](/COMP_273/summary/winter-2012/htsefp-digital-logic-combinational-logic) are all examples of student-created, course-related pages whose content is made available under [CC-BY-NC-3.0](http://creativecommons.org/licenses/by-nc/3.0/).
2 |
3 | # Why this license?
4 |
5 | The notions of copyright and ownership can become a bit blurry in the context of a collaborative environment like WikiNotes. In this vein, we've adopted the same sort of policy as [Wikipedia](http://en.wikipedia.org/wiki/Wikipedia:Copyrights) (although we're using a different CC license and we're not co-licensing our content under the GFDL, purely to keep things simple). Our main goal is to ensure that all the information on this site remains freely accessible to anyone who wants to access it. We don't plan on ever restricting access by forcing users to pay or otherwise jump through hoops, and our choice of license is one way of showing our commitment to free-as-in-libre content. (We also don't intend on commercialising this site through advertisements or any other means.)
6 |
7 | # What does this mean for me?
8 |
9 | ## As a contributor
10 |
11 | If you contribute course content, you are making them available under the same [CC-BY-NC](http://creativecommons.org/licenses/by-nc/3.0/) license that all of our course content uses. Of course, you still retain copyright to your content - you are simply granting WikiNotes a license to display your content publicly. If you are not comfortable with this but still wish to contribute, [contact us](/about#contact) and we'll work something out.
12 |
13 | ## As a reader
14 |
15 | You are free to modify and redistribute any of the CC-licensed content on our website. Printing it out for personal use, sharing it with a friend, posting it on another website, or even mirroring the content on your own website (see paragraph below) are not only acceptable by the terms of the license, but encouraged. As long as you abide by the terms of the license - which really just means attributing the content to WikiNotes and refraining from using it for commercial purposes - then it's totally fine with us.
16 |
17 | On the other hand, please do _not_ use our content for commercial purposes or without attribution. This includes selling the notes, posting it on your website and passing it off as your own, or posting it on a website from which you derive ad revenue.
18 |
19 | If you modify the content substantially without intending to post the changes on WikiNotes, that's okay too, although we do hope that your improvements find their way back to our site eventually.
20 |
--------------------------------------------------------------------------------
/templates/pages/show.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% load url from future %}
3 |
4 | {% block og_image %}
5 |
6 | {% endblock %}
7 |
8 | {% block meta_description %}A student-created resource for the course {{ course }} - {{ course.name }} at McGill University. Available for free on WikiNotes.{% endblock %}
9 |
10 | {% block content %}
11 |
12 |
13 |
19 |
27 | {{ page.get_title }}
28 |
29 |
30 | {% with metadata=page.get_metadata %}
31 | {% if metadata %}
32 |
33 | {% for field, content in metadata.iteritems %}
34 | {{ field.title }} : {% if content %}{% if content.get_absolute_url %}{{ content }} {% else %}{{ content|urlize }}{% endif %}{% endif %}
35 | {% endfor %}
36 |
37 | {% else %}
38 | {% if page.seriespage_set.count > 0 %} {% endif %}
39 | {% endif %}
40 | {% endwith %}
41 |
42 |
43 | {% include "pages/series_listing.html" %}
44 |
45 |
46 |
47 | {% load wikinotes_markup %}
48 | {% for series in page.seriespage_set.all %}
49 | {% if series.get_banner_markdown %}
50 |
51 | {{ series.get_banner_markdown|wikinotes_markdown|safe }}
52 |
53 | {% endif %}
54 | {% endfor %}
55 | {% include "pages/content.html" %}
56 |
57 | {% include "pages/series_listing.html" %}
58 |
59 |
60 |
61 |
62 |
63 | {% endblock %}
64 |
--------------------------------------------------------------------------------
/templates/pages/commit.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 | {% load gravatar %}
5 |
6 |
7 |
15 | Commit {{ commit.hexsha }}
16 |
17 |
18 |
19 |
26 |
27 |
28 | Timestamp: {{ commit.get_date|date:"F j Y, H:i" }}
29 | Statistics:
30 | {{ commit.num_lines}}
31 | line{{ commit.num_lines|pluralize }} changed
32 | ({{ commit.num_deletions }}
33 | deletion{{ commit.num_deletions|pluralize }},
34 | {{ commit.num_insertions }}
35 | insertion{{ commit.num_insertions|pluralize }})
36 |
37 | Edit message: {{ commit.message }}
38 |
39 |
40 |
41 |
42 | Diff
43 |
44 |
45 | {% for section in commit.get_diff %}
46 | Starting from line {{ section.first_line }}. {{ section.lines_before }} line{{ section.lines_before|pluralize }} in the previous commit, {{ section.lines_after }} line{{ section.lines_after|pluralize }} after.
47 | {% for diff_line in section.lines %}{{ diff_line|slice:"1:" }}{% if diff_line.0 == '-' %} {% endif %} {% endfor %}
48 |
49 | {% empty %}
50 | This was the first commit. See raw below for the changes made.
51 | {% endfor %}
52 |
53 | Raw
54 |
55 |
56 | {% with content=commit.get_content %}
57 | {{ commit.get_content }}
58 |
59 | Preview
60 |
61 |
62 | {% include "main/markdown.html" %}
63 |
64 | {% endwith %}
65 |
66 |
67 | {% endblock %}
68 |
--------------------------------------------------------------------------------
/wiki/models/series.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class SeriesManager(models.Manager):
5 | """
6 | This custom manager is defined solely for the purpose of allowing hidden series
7 | """
8 | def visible(self, user, **kwargs):
9 | if user.is_staff:
10 | return self.filter(**kwargs)
11 | else:
12 | return self.filter(is_hidden=False, **kwargs)
13 |
14 |
15 | class Series(models.Model):
16 | objects = SeriesManager()
17 | course = models.ForeignKey('Course')
18 | name = models.CharField(max_length=255)
19 | position = models.IntegerField()
20 | slug = models.SlugField()
21 | banner = models.ForeignKey('SeriesBanner', null=True, blank=True)
22 | is_hidden = models.BooleanField(default=False)
23 |
24 | class Meta:
25 | app_label = 'wiki'
26 | unique_together = (('course', 'position'), ('course', 'slug'))
27 | verbose_name_plural = 'Series'
28 |
29 | def __unicode__(self):
30 | return "%s (%s)" % (self.name, self.course)
31 |
32 | def get_absolute_url(self):
33 | """This can't use `reverse` because it includes an anchor link."""
34 | return self.course.get_absolute_url() + '#series-' + self.slug
35 |
36 | def can_view(self, user):
37 | return not self.is_hidden or user.is_staff
38 |
39 | def get_num_total(self):
40 | return self.seriespage_set.count()
41 |
42 | def get_next_position(self):
43 | query = self.seriespage_set.all().aggregate(models.Max('position'))
44 | max_position = query['position__max']
45 | if max_position:
46 | return max_position + 1
47 | else:
48 | return 1
49 |
50 |
51 | class SeriesPage(models.Model):
52 | page = models.ForeignKey('Page')
53 | series = models.ForeignKey('Series')
54 | position = models.IntegerField('position')
55 |
56 | class Meta:
57 | app_label = 'wiki'
58 | # Each page can only be in a series once, each series can have only one page per position
59 | unique_together = (('position', 'series'), ('page', 'series'))
60 | ordering = ['series', 'position']
61 |
62 | def __unicode__(self):
63 | return "%s - %s (%d)" % (self.page, self.series, self.position)
64 |
65 | def get_previous_page(self):
66 | if self.position > 1:
67 | return SeriesPage.objects.get(series=self.series, position=self.position - 1).page
68 |
69 | def get_next_page(self):
70 | if self.position < self.series.get_num_total():
71 | return SeriesPage.objects.get(series=self.series, position=self.position + 1).page
72 |
73 | def get_banner_markdown(self):
74 | if self.series.banner:
75 | page = self.page
76 | course_sem = page.course_sem
77 | raw_text = self.series.banner.text
78 | text = raw_text % {
79 | 'series_number': self.position,
80 | 'maintainer': '@%s' % page.maintainer,
81 | 'edit_link': page.get_absolute_url() + '/edit',
82 | 'course': course_sem.course,
83 | 'semester': '%s %d' % (course_sem.term.title(), course_sem.year)
84 | }
85 |
86 | return text
87 | else:
88 | return ''
89 |
90 |
91 | class SeriesBanner(models.Model):
92 | name = models.CharField(max_length=255)
93 | text = models.TextField()
94 |
95 | class Meta:
96 | app_label = 'wiki'
97 |
98 | def __unicode__(self):
99 | return self.name
100 |
--------------------------------------------------------------------------------
/assets/css/scaffolding.less:
--------------------------------------------------------------------------------
1 | /*
2 | * Scaffolding
3 | * Basic and global styles for generating a grid system, structural layout, and page templates
4 | * ------------------------------------------------------------------------------------------- */
5 |
6 |
7 | // STRUCTURAL LAYOUT
8 | // -----------------
9 |
10 | html, body {
11 | background-color: @white;
12 | }
13 | body {
14 | margin: 0;
15 | #font > .sans-serif(normal,@basefont,@baseline);
16 | color: @grayDark;
17 | }
18 |
19 | // Container (centered, fixed-width layouts)
20 | .container {
21 | .fixed-container();
22 | }
23 |
24 | // Fluid layouts (left aligned, with sidebar, min- & max-width content)
25 | .container-fluid {
26 | position: relative;
27 | min-width: 940px;
28 | padding-left: 20px;
29 | padding-right: 20px;
30 | .clearfix();
31 | > .sidebar {
32 | float: left;
33 | width: 220px;
34 | }
35 | // TODO in v2: rename this and .popover .content to be more specific
36 | > .content {
37 | margin-left: 240px;
38 | }
39 | }
40 |
41 |
42 | // BASE STYLES
43 | // -----------
44 |
45 | // Links
46 | a {
47 | color: @linkColor;
48 | text-decoration: none;
49 | line-height: inherit;
50 | font-weight: inherit;
51 | &:hover {
52 | color: @linkColorHover;
53 | text-decoration: underline;
54 | }
55 | }
56 |
57 | // Quick floats
58 | .pull-right {
59 | float: right;
60 | }
61 | .pull-left {
62 | float: left;
63 | }
64 |
65 | // Toggling content
66 | .hide {
67 | display: none;
68 | }
69 | .show {
70 | display: block;
71 | }
72 |
73 |
74 | // GRID SYSTEM
75 | // -----------
76 | // To customize the grid system, bring up the variables.less file and change the column count, size, and gutter there
77 |
78 | .row {
79 | .clearfix();
80 | margin-left: -1 * @gridGutterWidth;
81 | }
82 |
83 | // Find all .span# classes within .row and give them the necessary properties for grid columns (supported by all browsers back to IE7)
84 | // Credit to @dhg for the idea
85 | [class*="span"] {
86 | .gridColumn();
87 | }
88 |
89 | // Default columns
90 | .span1 { .columns(1); }
91 | .span2 { .columns(2); }
92 | .span3 { .columns(3); }
93 | .span4 { .columns(4); }
94 | .span5 { .columns(5); }
95 | .span6 { .columns(6); }
96 | .span7 { .columns(7); }
97 | .span8 { .columns(8); }
98 | .span9 { .columns(9); }
99 | .span10 { .columns(10); }
100 | .span11 { .columns(11); }
101 | .span12 { .columns(12); }
102 | .span13 { .columns(13); }
103 | .span14 { .columns(14); }
104 | .span15 { .columns(15); }
105 | .span16 { .columns(16); }
106 |
107 | // For optional 24-column grid
108 | .span17 { .columns(17); }
109 | .span18 { .columns(18); }
110 | .span19 { .columns(19); }
111 | .span20 { .columns(20); }
112 | .span21 { .columns(21); }
113 | .span22 { .columns(22); }
114 | .span23 { .columns(23); }
115 | .span24 { .columns(24); }
116 |
117 | // Offset column options
118 | .offset1 { .offset(1); }
119 | .offset2 { .offset(2); }
120 | .offset3 { .offset(3); }
121 | .offset4 { .offset(4); }
122 | .offset5 { .offset(5); }
123 | .offset6 { .offset(6); }
124 | .offset7 { .offset(7); }
125 | .offset8 { .offset(8); }
126 | .offset9 { .offset(9); }
127 | .offset10 { .offset(10); }
128 | .offset11 { .offset(11); }
129 | .offset12 { .offset(12); }
130 |
131 | // Unique column sizes for 16-column grid
132 | .span-one-third { width: 300px; }
133 | .span-two-thirds { width: 620px; }
134 | .offset-one-third { margin-left: 340px; }
135 | .offset-two-thirds { margin-left: 660px; }
136 |
--------------------------------------------------------------------------------
/assets/css/type.less:
--------------------------------------------------------------------------------
1 | /* Typography.less
2 | * Headings, body text, lists, code, and more for a versatile and durable typography system
3 | * ---------------------------------------------------------------------------------------- */
4 |
5 |
6 | // BODY TEXT
7 | // ---------
8 |
9 | p {
10 | #font > .shorthand(normal,@basefont,@baseline);
11 | padding-bottom: @baseline / 2; // Was @baseline / 2
12 | small {
13 | font-size: @basefont - 2;
14 | color: @grayLight;
15 | }
16 | }
17 |
18 |
19 | // HEADINGS
20 | // --------
21 |
22 | h1, h2, h3, h4, h5, h6 {
23 | font-weight: bold;
24 | color: @grayDark;
25 | small {
26 | color: @grayLight;
27 | }
28 | }
29 | h1 {
30 | padding-bottom: @baseline;
31 | font-size: 32px;
32 | line-height: @baseline * 2;
33 | small {
34 | font-size: 18px;
35 | }
36 | }
37 | h2 {
38 | font-size: 24px;
39 | line-height: 50px;
40 | small {
41 | font-size: 14px;
42 | }
43 | }
44 | h3, h4, h5, h6 {
45 | line-height: @baseline * 2;
46 | }
47 | h3 {
48 | font-size: 18px;
49 | small {
50 | font-size: 14px;
51 | }
52 | }
53 | h4 {
54 | font-size: 16px;
55 | small {
56 | font-size: 12px;
57 | }
58 | }
59 | h5 {
60 | font-size: 14px;
61 | }
62 | h6 {
63 | font-size: 13px;
64 | color: @grayLight;
65 | text-transform: uppercase;
66 | }
67 |
68 |
69 | // COLORS
70 | // ------
71 |
72 | // Unordered and Ordered lists
73 | ul, ol {
74 | margin: 0 0 @baseline 25px;
75 | }
76 | ul ul,
77 | ul ol,
78 | ol ol,
79 | ol ul {
80 | padding-bottom: 0;
81 | }
82 | ul {
83 | list-style: disc;
84 | }
85 | ol {
86 | list-style: decimal;
87 | }
88 | li {
89 | line-height: @baseline;
90 | //color: @gray;
91 | }
92 | ul.unstyled {
93 | list-style: none;
94 | margin-left: 0;
95 | }
96 |
97 | // Description Lists
98 | dl {
99 | padding-bottom: @baseline;
100 | dt, dd {
101 | line-height: @baseline;
102 | }
103 | dt {
104 | font-weight: bold;
105 | }
106 | dd {
107 | margin-left: @baseline / 2;
108 | }
109 | }
110 |
111 | // MISC
112 | // ----
113 |
114 | // Horizontal rules
115 | hr {
116 | margin: 0 0 0px;
117 | border: 0;
118 | border-bottom: 1px solid @grayLighter - #111;
119 | }
120 |
121 | // Emphasis
122 | strong {
123 | font-style: inherit;
124 | font-weight: bold;
125 | }
126 | em {
127 | font-style: italic;
128 | font-weight: inherit;
129 | line-height: inherit;
130 | }
131 | .muted {
132 | color: @grayLight;
133 | }
134 |
135 | // Blockquotes
136 | blockquote {
137 | border-left: 5px solid #eee;
138 | padding-left: 15px;
139 | p {
140 | padding-bottom: 0;
141 | }
142 | small {
143 | display: block;
144 | #font > .shorthand(300,12px,@baseline);
145 | color: @grayLight;
146 | &:before {
147 | content: '\2014 \00A0';
148 | }
149 | }
150 | }
151 |
152 | // Addresses
153 | address {
154 | display: block;
155 | line-height: @baseline;
156 | padding-bottom: @baseline;
157 | }
158 |
159 | // Inline and block code styles
160 | code, pre {
161 | padding: 0 3px 2px;
162 | #font > .monospace;
163 | .border-radius(3px);
164 | }
165 | code {
166 | background-color: lighten(@orange, 40%);
167 | color: rgba(0,0,0,.75);
168 | padding: 1px 3px;
169 | }
170 | pre {
171 | background-color: #f5f5f5;
172 | display: block;
173 | padding: (@baseline - 1) / 2;
174 | margin: 0 0 @baseline;
175 | line-height: @baseline;
176 | font-size: 12px;
177 | border: 1px solid #ccc;
178 | border: 1px solid rgba(0,0,0,.15);
179 | .border-radius(3px);
180 | white-space: pre;
181 | white-space: pre-wrap;
182 | word-wrap: break-word;
183 |
184 | }
185 |
--------------------------------------------------------------------------------
/views/messages.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.decorators import login_required
2 | from django.contrib.auth.models import User
3 | from django.core.exceptions import PermissionDenied
4 | from django.shortcuts import render, get_object_or_404, redirect
5 |
6 | from wiki.forms.messages import PrivateMessageForm
7 | from wiki.models.users import PrivateMessage
8 |
9 |
10 | class ViewMessage(Exception):
11 | def __init__(self, message_id):
12 | self.message_id = message_id
13 |
14 |
15 | def base_view(function):
16 | @login_required
17 | def inner_view(request, *args, **kwargs):
18 | name = function.__name__
19 | template_file = 'messages/%s.html' % name
20 | try:
21 | data = function(request, *args, **kwargs)
22 | data['this_mode'] = name
23 |
24 | # If the title is not set in the context, use a generic one.
25 | if 'title' not in data:
26 | data['title'] = "Private messages (%s)" % name
27 |
28 | modes = ['inbox', 'outbox', 'compose']
29 | data['modes'] = [(mode, 'messages_%s' % mode) for mode in modes]
30 | return render(request, template_file, data)
31 | except PermissionDenied:
32 | return redirect('messages_inbox')
33 | except ViewMessage, e:
34 | return redirect('messages_view', message_id=e.message_id)
35 |
36 | return inner_view
37 |
38 |
39 | @base_view
40 | def inbox(request):
41 | return {
42 | 'messages': request.user.received_messages.all(),
43 | 'num_new': request.user.received_messages.new().count(),
44 | }
45 |
46 |
47 | @base_view
48 | def view(request, message_id):
49 | message = get_object_or_404(PrivateMessage, pk=message_id)
50 |
51 | if request.user == message.sender or request.user == message.recipient:
52 | if not message.is_read and request.user == message.recipient:
53 | message.is_read = True
54 | message.save()
55 |
56 | if request.user == message.sender:
57 | from_or_to = "to"
58 | user = message.recipient
59 | else:
60 | from_or_to = "from"
61 | user = message.sender
62 |
63 | return {
64 | 'title': 'Viewing private message %s %s' % (from_or_to, user),
65 | 'message': message,
66 | 'show_reply': request.user == message.recipient,
67 | }
68 | else:
69 | # Trying to view someone else's message ... return to inbox
70 | raise PermissionDenied
71 |
72 |
73 | @base_view
74 | def outbox(request):
75 | return {
76 | 'messages': request.user.sent_messages.all()
77 | }
78 |
79 |
80 | @base_view
81 | def compose(request):
82 | if request.method == 'POST':
83 | message = PrivateMessage()
84 | form = PrivateMessageForm(request.POST, instance=message)
85 | if form.is_valid():
86 | message.sender = request.user
87 | form.save()
88 | raise ViewMessage(message.id)
89 | else:
90 | message = PrivateMessage()
91 |
92 | # If we want to send a message to a specific person
93 | recipient_name = request.GET.get('to', '')
94 | try:
95 | message.recipient = User.objects.get(username__iexact=recipient_name)
96 | except User.DoesNotExist:
97 | pass
98 |
99 | # Pre-filled subject (reply to)
100 | reply_to = request.GET.get('reply_to', '')
101 | if reply_to:
102 | message.subject = 'Re: %s' % reply_to
103 |
104 | form = PrivateMessageForm(instance=message)
105 |
106 | return {'form': form}
107 |
--------------------------------------------------------------------------------
/mdx/mdx_wiki_def_list.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env Python
2 | """
3 | Definition List Extension for Python-Markdown
4 | =============================================
5 |
6 | Added parsing of Definition Lists to Python-Markdown.
7 |
8 | A simple example:
9 |
10 | Apple
11 | : Pomaceous fruit of plants of the genus Malus in
12 | the family Rosaceae.
13 | : An american computer company.
14 | Orange
15 | : The fruit of an evergreen tree of the genus Citrus.
16 |
17 | Copyright 2008 - [Waylan Limberg](http://achinghead.com)
18 |
19 | """
20 |
21 | import re
22 | import markdown
23 | from markdown.util import etree
24 |
25 |
26 | class DefListProcessor(markdown.blockprocessors.BlockProcessor):
27 | """ Process Definition Lists. """
28 |
29 | RE = re.compile(r'(^|\n)[ ]{0,3}:[ ]{1,3}(.*?)(\n|$)')
30 |
31 | def test(self, parent, block):
32 | return bool(self.RE.search(block))
33 |
34 | def run(self, parent, blocks):
35 | block = blocks.pop(0)
36 | m = self.RE.search(block)
37 | terms = [l for l in block[:m.start()].split('\n') if l.strip()]
38 | block = block[m.end():]
39 | d, theRest = self.detab(block)
40 | # Got rid of the noindent thing (basically set it to false always)
41 | if d:
42 | d = '%s\n%s' % (m.group(2), d)
43 | else:
44 | d = m.group(2)
45 | sibling = self.lastChild(parent)
46 | if not terms and sibling.tag == 'p':
47 | # The previous paragraph contains the terms
48 | state = 'looselist'
49 | terms = sibling.text.split('\n')
50 | parent.remove(sibling)
51 | # Aquire new sibling
52 | sibling = self.lastChild(parent)
53 | else:
54 | state = 'list'
55 |
56 | if sibling and sibling.tag == 'dl':
57 | # This is another item on an existing list
58 | dl = sibling
59 | if len(dl) and dl[-1].tag == 'dd' and len(dl[-1]):
60 | state = 'looselist'
61 | else:
62 | # This is a new list
63 | dl = etree.SubElement(parent, 'dl')
64 | # Add terms
65 | for term in terms:
66 | dt = etree.SubElement(dl, 'dt')
67 | dt.text = term
68 | # Add definition
69 | self.parser.state.set(state)
70 | dd = etree.SubElement(dl, 'dd')
71 | self.parser.parseBlocks(dd, [d])
72 | self.parser.state.reset()
73 |
74 | if theRest:
75 | blocks.insert(0, theRest)
76 |
77 | class DefListIndentProcessor(markdown.blockprocessors.ListIndentProcessor):
78 | """ Process indented children of definition list items. """
79 |
80 | ITEM_TYPES = ['dd']
81 | LIST_TYPES = ['dl']
82 |
83 | def create_item(self, parent, block):
84 | """ Create a new dd and parse the block with it as the parent. """
85 | dd = markdown.etree.SubElement(parent, 'dd')
86 | self.parser.parseBlocks(dd, [block])
87 |
88 |
89 | class DefListExtension(markdown.Extension):
90 | """ Add definition lists to Markdown. """
91 |
92 | def extendMarkdown(self, md, md_globals):
93 | """ Add an instance of DefListProcessor to BlockParser. """
94 | md.parser.blockprocessors.add('defindent',
95 | DefListIndentProcessor(md.parser),
96 | '>indent')
97 | md.parser.blockprocessors.add('deflist',
98 | DefListProcessor(md.parser),
99 | '>ulist')
100 |
101 |
102 | def makeExtension(configs={}):
103 | return DefListExtension(configs=configs)
104 |
105 |
--------------------------------------------------------------------------------
/wiki/tests/pagetypes.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | from wiki.utils.pages import page_types
4 |
5 |
6 | class _TestPageType(TestCase):
7 | """Parent class for testing various methods on the PageType subclasses."""
8 | def setUp(self):
9 | self.page_type = page_types[self.short_name]
10 |
11 | def test_slug(self):
12 | generated_slug = self.page_type._generate_slug(self.data)
13 | self.assertEqual(generated_slug, self.expected_slug)
14 |
15 | def test_title(self):
16 | generated_title = self.page_type._generate_title(self.data)
17 | self.assertEqual(generated_title, self.expected_title)
18 |
19 | def test_validation(self):
20 | """Tests the find_errors() method on the base class, including the
21 | custom validators."""
22 | initial_data = {
23 | 'term': 'winter',
24 | 'year': '2014',
25 | 'content': 'test',
26 | }
27 |
28 | for invalid_data in self.invalid_inputs:
29 | # Basically incorporate all the possible context values
30 | data = {}
31 | data.update(initial_data)
32 | data.update(self.data)
33 | data.update(invalid_data)
34 |
35 | errors = self.page_type.find_errors(data)
36 | self.assertEqual(len(errors), 1)
37 |
38 | # Make sure the regular self.data dict doesn't trigger errors
39 | default_data = {}
40 | default_data.update(initial_data)
41 | default_data.update(self.data)
42 | self.assertFalse(self.page_type.find_errors(default_data))
43 |
44 |
45 | class TestLectureNotes(_TestPageType):
46 | short_name = 'lecture-notes'
47 | data = {
48 | 'date_weekday': 'tuesday',
49 | 'date_month': 'april',
50 | 'date_date': '15',
51 | 'year': '2014',
52 | }
53 | expected_slug = 'tuesday-april-15'
54 | expected_title = 'Tuesday, April 15, 2014'
55 | invalid_inputs = [
56 | {
57 | 'date_weekday': 'saturday',
58 | },
59 | {
60 | 'date_month': 'not a month',
61 | },
62 | {
63 | 'date_date': 'lol',
64 | },
65 | {
66 | 'date_date': '0',
67 | },
68 | {
69 | 'date_weekday': 'monday', # it's actually a tuesday
70 | 'date_month': 'april',
71 | 'date_date': '15',
72 | 'date_year': '2014',
73 | },
74 | ]
75 |
76 |
77 | class TestPastExam(_TestPageType):
78 | short_name = 'past-exam'
79 | data = {
80 | 'term': 'winter',
81 | 'year': '2014',
82 | 'exam_type': 'final',
83 | }
84 | expected_slug = 'final'
85 | expected_title = 'Winter 2014 Final'
86 | invalid_inputs = [{
87 | 'exam_type': 'not a type',
88 | }]
89 |
90 |
91 | class TestCourseSummary(_TestPageType):
92 | short_name = 'summary'
93 | data = {
94 | 'subject': 'HTSEFP',
95 | }
96 | expected_slug = 'htsefp'
97 | expected_title = None
98 | invalid_inputs = [{
99 | 'subject': '',
100 | }]
101 |
102 |
103 | class TestVocabList(_TestPageType):
104 | short_name = 'vocab-list'
105 | data = {
106 | 'subject': 'Vocabulary list',
107 | }
108 | expected_slug = 'vocabulary-list'
109 | expected_title = None
110 | invalid_inputs = [{
111 | 'subject': '',
112 | }]
113 |
114 |
115 | class TestCourseQuiz(_TestPageType):
116 | short_name = 'course-quiz'
117 | data = {
118 | 'subject': 'Course quiz',
119 | }
120 | expected_slug = 'course-quiz'
121 | expected_title = None
122 | invalid_inputs = [{
123 | 'subject': '',
124 | }]
125 |
--------------------------------------------------------------------------------
/wiki/models/users.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.models import User
2 | from django.core.urlresolvers import reverse
3 | from django.db import models
4 | from django.db.models.signals import post_save
5 |
6 |
7 | class UserProfile(models.Model):
8 | user = models.OneToOneField(User)
9 | twitter = models.CharField(max_length=15, null=True) # max length of a twitter username
10 | courses = models.ManyToManyField('Course')
11 | pinned_courses = models.ManyToManyField('Course', related_name='pinners')
12 | website = models.CharField(max_length=255, null=True)
13 | bio = models.CharField(max_length=300, null=True)
14 | facebook = models.CharField(max_length=72, null=True) # apparently that's the limit
15 | github = models.CharField(max_length=30, null=True) # no idea
16 | gplus = models.CharField(max_length=21, null=True) # i think, all numbers but char just in case
17 | major = models.CharField(max_length=100, null=True)
18 | show_email = models.BooleanField(default=False)
19 | url_fields = {
20 | 'username': 'user__username',
21 | }
22 |
23 | class Meta:
24 | app_label = 'wiki'
25 |
26 | def start_watching(self, course):
27 | self.courses.add(course)
28 | course.increase_num_watchers_by(1)
29 | course.add_event(self.user, action='started watching')
30 |
31 | def stop_watching(self, course):
32 | self.courses.remove(course)
33 | course.increase_num_watchers_by(-1)
34 |
35 | def is_watching(self, course):
36 | return self.courses.filter(pk=course.pk).exists()
37 |
38 | def has_pinned(self, course):
39 | return self.pinned_courses.filter(pk=course.pk).exists()
40 |
41 | def get_recent_pages(self, n, created=False):
42 | """
43 | Return the last n pages that the user has edited.
44 | """
45 | pages = []
46 | i = 0
47 | history_items = self.user.historyitem_set.order_by('-timestamp')
48 |
49 | # If we want to limit it to pages that the user has created (false by default)
50 | if created:
51 | history_items = history_items.filter(action='created')
52 |
53 | for history_item in history_items:
54 | page = history_item.page
55 | if page is not None and page not in pages:
56 | pages.append(page)
57 | i += 1
58 |
59 | if i == n:
60 | break
61 |
62 | return pages
63 |
64 | def get_absolute_url(self):
65 | return reverse('main_profile', args=[self.user.username])
66 |
67 |
68 | """
69 | A simple private messaging system. Useful because not everyone provides
70 | contact information.
71 | """
72 | class PrivateMessageManager(models.Manager):
73 | def new(self, **kwargs):
74 | return self.filter(is_read=False, **kwargs)
75 |
76 |
77 | class PrivateMessage(models.Model):
78 | objects = PrivateMessageManager()
79 | sender = models.ForeignKey(User, related_name="sent_messages")
80 | recipient = models.ForeignKey(User, related_name="received_messages")
81 | subject = models.CharField(max_length=100, blank=True, null=True)
82 | message = models.TextField(blank=True, null=True)
83 | is_read = models.BooleanField(default=False)
84 | timestamp = models.DateTimeField(auto_now_add=True)
85 |
86 | class Meta:
87 | app_label = 'wiki'
88 | ordering = ['-pk']
89 |
90 | def get_absolute_url(self):
91 | return reverse('messages_view', args=[self.id])
92 |
93 |
94 | def create_user_profile(sender, instance, created, **kwargs):
95 | if created:
96 | UserProfile.objects.create(user=instance)
97 |
98 |
99 | # Register a handler for the post_save signal
100 | # Otherwise the user profile does not get created
101 | post_save.connect(create_user_profile, sender=User)
102 |
--------------------------------------------------------------------------------
/assets/css/pygments.less:
--------------------------------------------------------------------------------
1 | .codehilite .c, .codehilite .cm { color: #BEBEBE; font-style: italic } /* Comment */
2 | .codehilite .err { color: #a61717; background-color: #e3d2d2 } /* Error */
3 | .codehilite .k { color: #FF6600; font-weight: bold } /* Keyword */
4 | .codehilite .javascript .k { color: #CCCC66; font-weight: bold } /* Keyword */
5 | .codehilite .o { color: #FFFFFF; font-weight: bold } /* Operator */
6 | .codehilite .cp { color: #3A6EF2; font-weight: bold } /* Comment.Preproc */
7 | .codehilite .c1 { color: #3A6EF2; font-style: italic } /* Comment.Single */
8 | .codehilite .cs { color: #3A6EF2; font-weight: bold; font-style: italic } /* Comment.Special */
9 | .codehilite .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
10 | .codehilite .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
11 | .codehilite .ge { font-style: italic } /* Generic.Emph */
12 | .codehilite .gr { color: #aa0000 } /* Generic.Error */
13 | .codehilite .gh { color: #999999 } /* Generic.Heading */
14 | .codehilite .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
15 | .codehilite .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
16 | .codehilite .go { color: #888888 } /* Generic.Output */
17 | .codehilite .gp { color: #555555 } /* Generic.Prompt */
18 | .codehilite .gs { font-weight: bold } /* Generic.Strong */
19 | .codehilite .gu { color: #aaaaaa } /* Generic.Subheading */
20 | .codehilite .gt { color: #aa0000 } /* Generic.Traceback */
21 | .codehilite .kc { font-weight: bold } /* Keyword.Constant */
22 | .codehilite .kd { font-weight: bold } /* Keyword.Declaration */
23 | .codehilite .kp { font-weight: bold } /* Keyword.Pseudo */
24 | .codehilite .kr { font-weight: bold } /* Keyword.Reserved */
25 | .codehilite .kt { color: #5E76BE; font-weight: bold } /* Keyword.Type */
26 | .codehilite .m { color: #009999 } /* Literal.Number */
27 | .codehilite .s { color: #66FF00 } /* Literal.String */
28 | .codehilite .na { color: #99CC99 } /* Name.Attribute */
29 | .codehilite .nb { } /* Name.Builtin */
30 | .codehilite .nc { color: #FFFFFF; font-weight: bold } /* Name.Class */
31 | .codehilite .no { color: #FFFFFF } /* Name.Constant */
32 | .codehilite .ni { color: #339999 } /* Name.Entity */
33 | .codehilite .ne { color: #FF0000; font-weight: bold } /* Name.Exception */
34 | .codehilite .nf { color: #FFCC00; font-weight: bold } /* Name.Function */
35 | .codehilite .nn { color: #AAAAAA } /* Name.Namespace */
36 | .codehilite .nt { color: #FF6600 } /* Name.Tag */
37 | .codehilite .nv { color: #008080 } /* Name.Variable */
38 | .codehilite .ow { font-weight: bold } /* Operator.Word */
39 | .codehilite .w { color: #bbbbbb } /* Text.Whitespace */
40 | .codehilite .mf { color: #CCFF33 } /* Literal.Number.Float */
41 | .codehilite .mh { color: #CCFF33 } /* Literal.Number.Hex */
42 | .codehilite .mi { color: #CCFF33 } /* Literal.Number.Integer */
43 | .codehilite .mo { color: #CCFF33 } /* Literal.Number.Oct */
44 | .codehilite .sb { background: #CCCC33; color: #000000 } /* Literal.String.Backtick */
45 | .codehilite .sc { color: #66FF00 } /* Literal.String.Char */
46 | .codehilite .sd { color: #66FF00 } /* Literal.String.Doc */
47 | .codehilite .s2 { color: #66FF00 } /* Literal.String.Double */
48 | .codehilite .se { color: #66FF00 } /* Literal.String.Escape */
49 | .codehilite .sh { color: #66FF00 } /* Literal.String.Heredoc */
50 | .codehilite .si { color: #d555555 } /* Literal.String.Interpol */
51 | .codehilite .sx { color: #66FF00 } /* Literal.String.Other */
52 | .codehilite .sr { color: #009926 } /* Literal.String.Regex */
53 | .codehilite .s1 { color: #66FF00 } /* Literal.String.Single */
54 | .codehilite .ss { color: #339999 } /* Literal.String.Symbol */
55 | .codehilite .bp { color: #999999 } /* Name.Builtin.Pseudo */
56 | .codehilite .vc { color: #008080 } /* Name.Variable.Class */
57 | .codehilite .vg { color: #008080 } /* Name.Variable.Global */
58 | .codehilite .vi { color: #008080 } /* Name.Variable.Instance */
59 | .codehilite .il { color: #009999 } /* Literal.Number.Integer.Long */
60 |
--------------------------------------------------------------------------------
/templates/main/contributions.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
84 | {% endblock %}
85 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | WikiNotes is a wiki-based note-sharing platform created to facilitate student
4 | collaboration. Although it is being created primarily to replace our old
5 | MediaWiki-backed website for McGill students, we are releasing the code under
6 | the [GPLv3][gpl] so that non-McGill students (or anyone, really) can benefit
7 | from it as well. Although this platform is still under development, we are now
8 | using it to power our main website at www.wikinotes.ca.
9 |
10 | Want to find out more about us? Visit our [about page][about], join our IRC
11 | channel ([#wikinotes on freenode][irc]) or drop us a line at
12 | .
13 |
14 | Contributing
15 | ------------
16 |
17 | We'd love to have you contribute, whether it be through adding features, filing
18 | bug reports, writing tests or whatever takes your fancy. Contributing code is
19 | easy - just fork this repository, make your changes, and send us a pull request.
20 | To see what needs to be done, check out the [list of outstanding
21 | issues][issues]. If you notice something else that needs to be done, feel free
22 | to [open an issue][open] for it.
23 |
24 | See also our [development wiki][wiki] for things like what style conventions we
25 | use, development notes, and how the code is organised.
26 |
27 | We're using [Travis][travis] for continuous integration and Django's
28 | unit-testing framework for the tests. Current build status of the master branch:
29 |
30 | [![Build status][status]][ci]
31 |
32 | Dependencies
33 | ------------
34 |
35 | To run it on your local machine, you'll need Python 2.7+, and Git. If you're on
36 | Windows, you might run into some issues which I won't be able to help debug, so
37 | I'd recommend using Linux if possible. You'll also need a bunch of Python
38 | modules, which can be installed with [pip]:
39 |
40 | ```console
41 | pip install -r requirements.txt
42 | ```
43 |
44 | If you don't have pip, either install it using your system's package manager or
45 | make use of [virtualenv] \(which is a good idea in any case\).
46 |
47 | Configuration
48 | -------------
49 |
50 | If you're running it for the first time, here's what you have to do:
51 |
52 | * Run `python manage.py syncdb`. Make sure to create the superuser when
53 | prompted. You will be able to use the credentials you choose for the
54 | superuser account to log on to the site, and to access the administration
55 | panel.
56 | * Run `python manage.py runserver` (or `fab up` if you have [Fabric][fabric]
57 | installed) to start the development server. By default, this makes the
58 | platform accessible at ; add `0.0.0.0:8000` as an
59 | argument if you want to make it publicly accessible through your IP address
60 | (at port 8000), or run `fab broadcast`. To actually deploy it properly on a
61 | server, you'll probably want to use something like [gunicorn].
62 |
63 | Initially, there won't be any courses on the site. You can create them through
64 | the admin panel (sign in using the superuser account details through the login
65 | box in the header, then click the "admin" button), or write a script to import
66 | them if you have a list of all the courses/departments/faculties to create.
67 |
68 | If you have questions, send me an email (ilostwaldo, gmail).
69 |
70 | Testing
71 | -------
72 |
73 | To run the unit tests, run `python manage.py test wiki` or `fab test`. You can
74 | view the history of the tests run for commits pushed to the master branch on
75 | [Travis][ci].
76 |
77 | [gpl]: http://opensource.org/licenses/GPL-3.0
78 | [about]: http://www.wikinotes.ca/about
79 | [irc]: http://webchat.freenode.net/?channels=wikinotes
80 | [issues]: https://github.com/dellsystem/wikinotes/issues
81 | [open]: https://github.com/dellsystem/wikinotes/issues/new
82 | [wiki]: https://github.com/dellsystem/wikinotes/wiki
83 | [travis]: http://travis-ci.org
84 | [status]: https://secure.travis-ci.org/dellsystem/wikinotes.png?branch=master
85 | [ci]: http://travis-ci.org/dellsystem/wikinotes
86 | [pip]: http://www.pip-installer.org/en/latest/index.html
87 | [virtualenv]: http://www.virtualenv.org/en/latest/index.html
88 | [fabric]: http://fabfile.org
89 | [gunicorn]: https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/gunicorn/
90 |
--------------------------------------------------------------------------------
/templates/ucp/profile.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {% csrf_token %}
6 | Edit profile information
7 | {% if success %}
8 |
15 | {% endif %}
16 |
17 |
Bio:
18 |
19 | {% if profile.bio %}{{ profile.bio }}{% endif %}
20 |
21 | A short description of yourself. Limit it to 300 characters or so. Markdown is not parsed.
22 |
23 |
24 |
25 |
26 |
Major:
27 |
28 |
29 |
30 |
31 |
32 |
Website:
33 |
34 |
35 |
36 |
37 |
38 |
Twitter username:
39 |
40 |
41 |
42 |
43 |
44 |
Github username:
45 |
46 |
47 |
48 |
49 |
50 |
Facebook username:
51 |
52 |
53 |
54 |
55 |
56 |
Google plus ID:
57 |
58 |
59 |
60 |
61 |
62 | Reset
63 |
64 |
65 |
66 |
67 |
68 |
All fields are optional.
69 |
70 |
71 | Edit your bio
72 | Edit your major
73 | Link to website
74 | Twitter
75 | Github
76 | Facebook
77 | Google plus
78 |
79 |
80 |
You can view your profile by clicking on your gravatar in the header (or by clicking here ).
81 |
82 |
83 |
--------------------------------------------------------------------------------
/templates/main/registration.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 |
3 | {% block content %}
4 |
5 |
6 |
9 |
10 |
11 | {% if errors %}
12 |
13 |
14 |
Something went wrong! Please fix the errors and try again.
15 |
16 | {% for error in errors %}
17 | {{ error }}
18 | {% endfor %}
19 |
20 |
21 | {% else %}
22 |
23 |
Already have an account? Sign in using the login bar above.
24 |
25 | {% endif %}
26 |
27 |
28 | {% csrf_token %}
29 |
30 |
Username:
31 |
32 |
33 |
34 |
35 |
36 |
Email (optional)
37 |
38 |
39 |
40 |
41 |
42 |
Password:
43 |
44 |
45 |
46 |
47 |
48 |
Confirm password:
49 |
50 |
51 |
52 |
53 |
54 |
55 |
University name? (anti-spam measure)
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
Why register?
69 |
You absolutely don't need to register to be able to access the content on WikiNotes! We believe that the content on this site should be available freely to anyone who wants to see it, regardless of whether they have an account or not. Registration is mostly useful if you want to contribute, as we do require edits to be made by logged-in users, or if you want an an easy way of staying up-to-date with the content on this site for your courses.
70 |
What will you do with my information?
71 |
Rest assured that your account details are safe with us - we will not share, sell, or do other bad things to your email address. At the moment, entering your email is optional, although if you have a gravatar, your email will be used to display it, and in the future we will provide user-configurable email notifications and use your email to update you of important site-related news.
72 |
73 |
74 |
76 |
77 |
78 | {% endblock %}
79 |
--------------------------------------------------------------------------------
/assets/css/tables.less:
--------------------------------------------------------------------------------
1 | /*
2 | * Tables.less
3 | * Tables for, you guessed it, tabular data
4 | * ---------------------------------------- */
5 |
6 |
7 | // BASELINE STYLES
8 | // ---------------
9 |
10 | table {
11 | width: 100%;
12 | margin-bottom: @baseline;
13 | padding: 0;
14 | border-collapse: separate; // Done so we can round those corners!
15 | *border-collapse: collapse; /* IE7, collapse table to remove spacing */
16 | font-size: @basefont;
17 | border: 1px solid #ddd;
18 | .border-radius(4px);
19 | th, td {
20 | padding: 10px 10px 9px;
21 | line-height: @baseline;
22 | text-align: left;
23 | }
24 | th {
25 | padding-top: 9px;
26 | font-weight: bold;
27 | vertical-align: middle;
28 | border-bottom: 1px solid #ddd;
29 | }
30 | td {
31 | vertical-align: top;
32 | }
33 | th + th,
34 | td + td {
35 | border-left: 1px solid #ddd;
36 | }
37 | tr + tr td {
38 | border-top: 1px solid #ddd;
39 | }
40 | tbody tr:first-child td:first-child {
41 | .border-radius(4px 0 0 0);
42 | }
43 | tbody tr:first-child td:last-child {
44 | .border-radius(0 4px 0 0);
45 | }
46 | tbody tr:last-child td:first-child {
47 | .border-radius(0 0 0 4px);
48 | }
49 | tbody tr:last-child td:last-child {
50 | .border-radius(0 0 4px 0);
51 | }
52 | }
53 |
54 |
55 | // ZEBRA-STRIPING
56 | // --------------
57 |
58 | // Default zebra-stripe styles (alternating gray and transparent backgrounds)
59 | .zebra-striped {
60 | tbody {
61 | tr:nth-child(odd) td {
62 | background-color: #f9f9f9;
63 | }
64 | tr:hover td {
65 | background-color: #f5f5f5;
66 | }
67 | }
68 | }
69 |
70 | table {
71 | // Tablesorting styles w/ jQuery plugin
72 | .header {
73 | cursor: pointer;
74 | &:after {
75 | content: "";
76 | float: right;
77 | margin-top: 7px;
78 | border-width: 0 4px 4px;
79 | border-style: solid;
80 | border-color: #000 transparent;
81 | visibility: hidden;
82 | }
83 | }
84 | // Style the sorted column headers (THs)
85 | .headerSortUp,
86 | .headerSortDown {
87 | background-color: rgba(141,192,219,.25);
88 | text-shadow: 0 1px 1px rgba(255,255,255,.75);
89 | }
90 | // Style the ascending (reverse alphabetical) column header
91 | .header:hover {
92 | &:after {
93 | visibility:visible;
94 | }
95 | }
96 | // Style the descending (alphabetical) column header
97 | .headerSortDown,
98 | .headerSortDown:hover {
99 | &:after {
100 | visibility:visible;
101 | .opacity(60);
102 | }
103 | }
104 | // Style the ascending (reverse alphabetical) column header
105 | .headerSortUp {
106 | &:after {
107 | border-bottom: none;
108 | border-left: 4px solid transparent;
109 | border-right: 4px solid transparent;
110 | border-top: 4px solid #000;
111 | visibility:visible;
112 | .box-shadow(none); //can't add boxshadow to downward facing arrow :(
113 | .opacity(60);
114 | }
115 | }
116 | // Blue Table Headings
117 | .blue {
118 | color: @blue;
119 | border-bottom-color: @blue;
120 | }
121 | .headerSortUp.blue,
122 | .headerSortDown.blue {
123 | background-color: lighten(@blue, 40%);
124 | }
125 | // Green Table Headings
126 | .green {
127 | color: @green;
128 | border-bottom-color: @green;
129 | }
130 | .headerSortUp.green,
131 | .headerSortDown.green {
132 | background-color: lighten(@green, 40%);
133 | }
134 | // Red Table Headings
135 | .red {
136 | color: @red;
137 | border-bottom-color: @red;
138 | }
139 | .headerSortUp.red,
140 | .headerSortDown.red {
141 | background-color: lighten(@red, 50%);
142 | }
143 | // Yellow Table Headings
144 | .yellow {
145 | color: @yellow;
146 | border-bottom-color: @yellow;
147 | }
148 | .headerSortUp.yellow,
149 | .headerSortDown.yellow {
150 | background-color: lighten(@yellow, 40%);
151 | }
152 | // Orange Table Headings
153 | .orange {
154 | color: @orange;
155 | border-bottom-color: @orange;
156 | }
157 | .headerSortUp.orange,
158 | .headerSortDown.orange {
159 | background-color: lighten(@orange, 40%);
160 | }
161 | // Purple Table Headings
162 | .purple {
163 | color: @purple;
164 | border-bottom-color: @purple;
165 | }
166 | .headerSortUp.purple,
167 | .headerSortDown.purple {
168 | background-color: lighten(@purple, 40%);
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/assets/css/reset.less:
--------------------------------------------------------------------------------
1 | /* Reset.less
2 | * Props to Eric Meyer (meyerweb.com) for his CSS reset file. We're using an adapted version here that cuts out some of the reset HTML elements we will never need here (i.e., dfn, samp, etc).
3 | * ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
4 |
5 |
6 | // ERIC MEYER RESET
7 | // --------------------------------------------------
8 |
9 | html, body { margin: 0; padding: 0; }
10 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, cite, code, del, dfn, em, img, q, s, samp, small, strike, strong, sub, sup, tt, var, dd, dl, dt, li, ol, ul, fieldset, form, label, legend, button, table, caption, tbody, tfoot, thead, tr, th, td { margin: 0; padding: 0; border: 0; font-weight: normal; font-style: normal; font-size: 100%; line-height: 1; font-family: inherit; }
11 | table { border-collapse: collapse; border-spacing: 0; }
12 | ol, ul { list-style: none; }
13 | q:before, q:after, blockquote:before, blockquote:after { content: ""; }
14 |
15 |
16 | // Normalize.css
17 | // Pulling in select resets form the normalize.css project
18 | // --------------------------------------------------
19 |
20 | // Display in IE6-9 and FF3
21 | // -------------------------
22 | // Source: http://github.com/necolas/normalize.css
23 | html {
24 | overflow-y: scroll;
25 | font-size: 100%;
26 | -webkit-text-size-adjust: 100%;
27 | -ms-text-size-adjust: 100%;
28 | }
29 | // Focus states
30 | a:focus {
31 | outline: thin dotted;
32 | }
33 | // Hover & Active
34 | a:hover,
35 | a:active {
36 | outline: 0;
37 | }
38 |
39 | // Display in IE6-9 and FF3
40 | // -------------------------
41 | // Source: http://github.com/necolas/normalize.css
42 | article,
43 | aside,
44 | details,
45 | figcaption,
46 | figure,
47 | footer,
48 | header,
49 | hgroup,
50 | nav,
51 | section {
52 | display: block;
53 | }
54 |
55 | // Display block in IE6-9 and FF3
56 | // -------------------------
57 | // Source: http://github.com/necolas/normalize.css
58 | audio,
59 | canvas,
60 | video {
61 | display: inline-block;
62 | *display: inline;
63 | *zoom: 1;
64 | }
65 |
66 | // Prevents modern browsers from displaying 'audio' without controls
67 | // -------------------------
68 | // Source: http://github.com/necolas/normalize.css
69 | audio:not([controls]) {
70 | display: none;
71 | }
72 |
73 | // Prevents sub and sup affecting line-height in all browsers
74 | // -------------------------
75 | // Source: http://github.com/necolas/normalize.css
76 | sub,
77 | sup {
78 | font-size: 75%;
79 | line-height: 0;
80 | position: relative;
81 | vertical-align: baseline;
82 | }
83 | sup {
84 | top: -0.5em;
85 | }
86 | sub {
87 | bottom: -0.25em;
88 | }
89 |
90 | // Img border in a's and image quality
91 | // -------------------------
92 | // Source: http://github.com/necolas/normalize.css
93 | img {
94 | border: 0;
95 | -ms-interpolation-mode: bicubic;
96 | }
97 |
98 | // Forms
99 | // -------------------------
100 | // Source: http://github.com/necolas/normalize.css
101 |
102 | // Font size in all browsers, margin changes, misc consistency
103 | button,
104 | input,
105 | select,
106 | textarea {
107 | font-size: 100%;
108 | margin: 0;
109 | vertical-align: baseline;
110 | *vertical-align: middle;
111 | }
112 | button,
113 | input {
114 | line-height: normal; // FF3/4 have !important on line-height in UA stylesheet
115 | *overflow: visible; // Inner spacing ie IE6/7
116 | }
117 | button::-moz-focus-inner,
118 | input::-moz-focus-inner { // Inner padding and border oddities in FF3/4
119 | border: 0;
120 | padding: 0;
121 | }
122 | button,
123 | input[type="button"],
124 | input[type="reset"],
125 | input[type="submit"] {
126 | cursor: pointer; // Cursors on all buttons applied consistently
127 | -webkit-appearance: button; // Style clicable inputs in iOS
128 | }
129 | input[type="search"] { // Appearance in Safari/Chrome
130 | -webkit-appearance: textfield;
131 | -webkit-box-sizing: content-box;
132 | -moz-box-sizing: content-box;
133 | box-sizing: content-box;
134 | }
135 | input[type="search"]::-webkit-search-decoration {
136 | -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5
137 | }
138 | textarea {
139 | overflow: auto; // Remove vertical scrollbar in IE6-9
140 | vertical-align: top; // Readability and alignment cross-browser
141 | }
142 |
--------------------------------------------------------------------------------
/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls.defaults import patterns, include, url
2 | from django.contrib import admin
3 |
4 | admin.autodiscover()
5 |
6 | """
7 | Basic, reusable patterns
8 | """
9 | faculty = r'(?P\w+)'
10 | department = r'(?P\w{4})'
11 | number = '(?P\d{3}[DNJ]?[123]?)'
12 | course = department + '_' + number
13 | page_type = '(?P[^/]+)'
14 | semester = '(?P\w{4,6})-(?P\d{4})'
15 | slug = '(?P[^/]+)'
16 | page = course + '/' + page_type + '/' + semester + '/' + slug
17 | sha = '(?P[a-z0-9]{40})'
18 | professor = '(?P[a-z-]*)'
19 |
20 | """
21 | Begin mappings (URLs should be defined in order of descending priority (so highest priority first))
22 | """
23 | direct_to_view = (
24 | ('main', (
25 | ('login', 'login_logout'),
26 | ('recent', 'recent'),
27 | ('recent/(?P\d+)', 'recent'),
28 | ('recent/all', 'all_recent'),
29 | ('recent/all/(?P\d+)', 'all_recent'),
30 | ('ucp', 'ucp'),
31 | ('ucp/(?P\w*)', 'ucp'),
32 | ('users/(?P\w+)', 'profile'),
33 | ('users/(?P\w+)/contributions', 'contributions'),
34 | ('search', 'search'),
35 | ('markdown', 'markdown'),
36 | ('register', 'register')
37 | )),
38 | ('messages', (
39 | ('messages', 'inbox'),
40 | ('messages/inbox', 'inbox'),
41 | ('messages/outbox', 'outbox'),
42 | ('messages/compose', 'compose'),
43 | ('messages/view/(?P\d+)', 'view'),
44 | )),
45 | ('news', (
46 | ('news', 'main'),
47 | ('news/' + slug, 'view'),
48 | )),
49 | ('pages', (
50 | ('pages/random', 'random'),
51 | (course + '/create/' + page_type, 'create'),
52 | (page, 'show'),
53 | (page + '/edit', 'edit'),
54 | (page + '/history', 'history'),
55 | (page + '/print', 'printview'),
56 | #(page + '/raw', 'raw'),
57 | (page + '/commit/' + sha, 'commit'),
58 | #(page + '/inline', 'inline'),
59 | )),
60 | ('courses', (
61 | ('courses', 'index'),
62 | ('courses/create', 'create'),
63 | ('courses/all', 'all_browse'),
64 | ('courses/faculty', 'faculty_browse'),
65 | ('courses/department', 'department_browse'),
66 | ('courses/professor', 'professor_browse'),
67 | ('courses/popular', 'popular_browse'),
68 | ('courses/random', 'random'),
69 | ('courses/active', 'active_browse'),
70 | ('courses/get_all', 'get_all'),
71 | # Redirect department/number to department_number
72 | (department + '/' + number + '.*', 'remove_slash'),
73 | (course, 'overview'),
74 | (course + '/recent', 'recent'),
75 | (course + '/watch', 'watch'),
76 | (course + '/pin', 'pin'),
77 | (course + '/unpin', 'unpin'),
78 | (course + '/' + semester, 'semester_overview'),
79 | (course + '/' + page_type, 'category_overview'),
80 | (department, 'department_overview'),
81 | ('faculty/' + faculty, 'faculty_overview'),
82 | ('professor/' + professor, 'professor_overview'),
83 | )),
84 | )
85 |
86 | # Maps straight from about/history to the static view in main.py
87 | static_urls = {
88 | 'about': ['history', 'licensing', 'platform'], # the index one is implicit
89 | 'contributing': ['moderating', 'development', 'content', 'guidelines'],
90 | 'help': ['copyright', 'formatting', 'lexers'],
91 | }
92 |
93 | urlpatterns = patterns('',
94 | url(r'^admin/', include(admin.site.urls)),
95 | )
96 |
97 | """
98 | Begin code for mapping the mappings
99 | """
100 |
101 | # The index view has to be done separately
102 | urlpatterns += patterns('',
103 | url(r'^$', 'views.main.index', name='home'),
104 | )
105 |
106 | for prefix, filenames in static_urls.iteritems():
107 | index_url = url(r'^' + prefix + '(?:/overview)?/$', 'views.main.static',
108 | {'mode': prefix, 'page': 'overview'}, name=prefix)
109 | urls = [url(r'^' + prefix + '/' + filename + '/$', 'views.main.static',
110 | {'mode': prefix, 'page': filename},
111 | name=prefix + '_' + filename) for filename in filenames]
112 | urlpatterns += patterns('', index_url, *urls)
113 |
114 | for prefix, mapping in direct_to_view:
115 | urls = [url('^' + regex + '/$', view, name='%s_%s' % (prefix, view)) for regex, view in mapping]
116 | urlpatterns += patterns('views.' + prefix, *urls)
117 |
--------------------------------------------------------------------------------
/mdx/mdx_wiki_tables.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env Python
2 | """
3 | Tables Extension for Python-Markdown
4 | ====================================
5 |
6 | Added parsing of tables to Python-Markdown.
7 |
8 | A simple example:
9 |
10 | First Header | Second Header
11 | ------------- | -------------
12 | Content Cell | Content Cell
13 | Content Cell | Content Cell
14 |
15 | Copyright 2009 - [Waylan Limberg](http://achinghead.com)
16 | """
17 | import markdown
18 | from markdown.util import etree
19 |
20 |
21 | class TableProcessor(markdown.blockprocessors.BlockProcessor):
22 | """ Process Tables. """
23 | allowed_classes = ['sort', 'clear', 'autumn', 'lights', 'ribbon', 'fresh', 'iris', 'column'] # lol
24 |
25 | def test(self, parent, block):
26 | rows = block.split('\n')
27 | return (len(rows) > 2 and '|' in rows[0] and
28 | '|' in rows[1] and '-' in rows[1] and
29 | rows[1].strip()[0] in ['|', ':', '-'])
30 |
31 | def run(self, parent, blocks):
32 | """ Parse a table block and build table. """
33 | block = blocks.pop(0).split('\n')
34 | header = block[0].strip()
35 | separator = block[1].strip()
36 | rows = block[2:]
37 | # Get format type (bordered by pipes or not)
38 | border = False
39 | if header.startswith('|'):
40 | border = True
41 | # Get alignment of columns
42 | align = []
43 | for c in self._split_row(separator, border):
44 | if c.startswith(':') and c.endswith(':'):
45 | align.append('center')
46 | elif c.startswith(':'):
47 | align.append('left')
48 | elif c.endswith(':'):
49 | align.append('right')
50 | else:
51 | align.append(None)
52 | # Build table
53 | table = etree.SubElement(parent, 'table')
54 | thead = etree.SubElement(table, 'thead')
55 | self._build_row(header, thead, align, border)
56 | tbody = etree.SubElement(table, 'tbody')
57 |
58 | # Set any necessary classes on the table
59 | classes = self.__get_classes(separator)
60 | if classes:
61 | table.set('class', ' '.join(classes))
62 |
63 | for row in rows:
64 | self._build_row(row.strip(), tbody, align, border)
65 |
66 | def _build_row(self, row, parent, align, border):
67 | """ Given a row of text, build table cells. """
68 | tr = etree.SubElement(parent, 'tr')
69 | tag = 'td'
70 | if parent.tag == 'thead':
71 | tag = 'th'
72 | cells = self._split_row(row, border)
73 | # We use align here rather than cells to ensure every row
74 | # contains the same number of columns.
75 | span = 0
76 | for i, a in enumerate(align):
77 | try:
78 | if cells[i] == "":
79 | span += 1
80 | continue
81 | except:
82 | pass
83 | c = etree.SubElement(tr, tag)
84 |
85 | try:
86 | if span > 0:
87 | c.set('colspan',"%d" % (span+1))
88 | span = 0
89 | c.text = cells[i].strip()
90 | except IndexError:
91 | c.text = ""
92 | if a:
93 | c.set('class', a + '-align')
94 |
95 | def _split_row(self, row, border):
96 | """ split a row of text into list of cells. """
97 | if border:
98 | if row.startswith('|'):
99 | row = row[1:]
100 | if row.endswith('|'):
101 | row = row[:-1]
102 | return row.split('|')
103 |
104 | def __get_classes(self, separator):
105 | classes = []
106 | for possible_class in separator.split(' '):
107 | if not possible_class.startswith('-') and not possible_class.startswith('|'):
108 | if possible_class in self.allowed_classes:
109 | classes.append(possible_class)
110 | return classes
111 |
112 | class TableExtension(markdown.Extension):
113 | """ Add tables to Markdown. """
114 |
115 | def extendMarkdown(self, md, md_globals):
116 | """ Add an instance of TableProcessor to BlockParser. """
117 | md.parser.blockprocessors.add('table',
118 | TableProcessor(md.parser),
119 | '