Compare commits

...

815 Commits

Author SHA1 Message Date
Samuel FORESTIER 06c3d6ac11
r-strips the configured URL unconditionally
4 years ago
Samuel FORESTIER cd49dce78f
[PATCH v2] Removes potential '//' from email links (#420, #519, #523)
4 years ago
Andy c2cd06da52
add .drone.yml
4 years ago
ix5 d7eefbc072
admin: Set default order_by to 'created' (desc) (#649)
4 years ago
frenchvandal 2ba7217900
Dockerfile update (#644)
4 years ago
Lucas Cimon bdaa5240d1
Adding docs/extras/contribs.rst (#640)
4 years ago
Lucas Cimon 080ee36371
Adding a [server] proxy-fix-enable-x-prefix configuration option to take into consideration the `X-Forwarded-Prefix` HTTP header (#639)
4 years ago
Lucas Cimon a548fbf45b
Add warnings on Comments.vote failures (#635)
4 years ago
Lucas Cimon f70eaf315a
Using .access_route instead of .remote_addr to take into account HTTP_X_FORWARDED_FOR header (#636)
4 years ago
Lucas Cimon 04d138dc77
Adding contrib/dump_comments.py (#638)
4 years ago
Lucas Cimon c4373186f9
Fixing likes counter of replies not being displayed (#637)
4 years ago
Jelmer Vernooij 54f8fb7a7f
Drop python2 support. (#613)
4 years ago
Benoit Latinier bb9d947c76
Merge pull request #618 from frenchvandal/master
4 years ago
frenchvandal de8867a9d2
[i18n] Added the Brazilian Portuguese language
4 years ago
Jelmer Vernooij 86b65f817e
html: Add markdown render flag option (#616)
4 years ago
Jelmer Vernooij 2a4e8c231e
Add python 3.8 support. (#615)
4 years ago
Jelmer Vernooij 3e3ee8b641
Fix compatibility with werkzeug 1.0.0. Fixes #611 (#614)
4 years ago
Facundo Batista 1633d9261e New 'latest' endpoint to serve latest comments. Fixes #556. (#610)
4 years ago
Benjamin Pereto 1de758887a FIX: include admin.js in Python Package (#606)
4 years ago
jasdeepgill 5655f194b3 Various text improvements to documentation.
4 years ago
Shimmy Xu 7eed747e7a Use `html.escape` for Python versions where `cgi.escape` is removed (#600)
4 years ago
Charl P. Botha (X1E) 2e8cb81179
Add a approve-if-email-previously-approved setting.
5 years ago
Marcin Kurczewski 9eaaad4775 Fall back to author names in gravatars (#482)
5 years ago
Jonathan Watt 4944d595f6 Make Isso compatible with Content Security Policies without `script-src 'unsafe-inline'` (#597)
5 years ago
Michiel Scholten 472c9ed3de Set subject for notification about new comment, subject should not be empty (#589)
5 years ago
jasdeepgill 95b05bd3fe Improve grammar of index.rst. (#588)
5 years ago
Jonathan Watt 3be36fd8b0 Fix rendering of disabled.html for 'Sub URI' sites (#587)
5 years ago
JocelynDelalande 0f4e72c0e0 Mention official Debian repo instead of 3rd party (#581)
5 years ago
Alberto Mardegan c24ee69a1e contrib: Add Blogger importer tool (#529)
5 years ago
tdro f4b0376f1a Return 200 with empty array when there are no comments #301 (#565)
5 years ago
Andy 1f77ecc25e fix typo in i18n.js (#575)
5 years ago
Quentí b9e31bf6fe [i18n] Adds the Occitan language (#568)
5 years ago
Jelmer Vernooij 78997f4910
Remove shm hack.
5 years ago
Jelmer Vernooij b3ae160cff Ignore .eggs directories as well.
5 years ago
Jelmer Vernooij 0df8000144 Exclude .tox directory from flakes.
5 years ago
Jelmer Vernooij e2cfd6c08c
Run tests on Python 3.7.
5 years ago
Jelmer Vernooij bd39dd6788 Ignore backup files.
5 years ago
Jelmer Vernooij f51d9cc4f5 Fix flake8 errors.
5 years ago
Jelmer Vernooij e08c378900 Move flake8 configuration to setup.cfg.
5 years ago
Chris Warrick 1b13458e6a Implement #358 (Redirect to comment after moderation) (#534)
5 years ago
Jelmer Vernooij 77871a8bab
Merge pull request #543 from krtcom/feat_i18n_sk
5 years ago
krtcom 0d721f9ebe
Alphabetical order
5 years ago
Jelmer Vernooij 3eb7f349e6
Merge pull request #544 from krtcom/bug_fetch_comments
5 years ago
Michal Krnáč 9161983a05 cancel fetching comments if #isso-root is not available
5 years ago
Michal Krnáč 0d4d758099 add slovak translations
5 years ago
Jelmer Vernooij 31db6b61e7 Fix code-block syntax.
5 years ago
Jelmer Vernooij 8c82ffde9f
Merge pull request #535 from Kwpolska/patch-1
5 years ago
Chris Warrick 22abbcdbb4
Include user e-mails in admin notifications only
5 years ago
Jelmer Vernooij c2136ce10a
Merge pull request #532 from Kwpolska/update-polish-translation
5 years ago
Chris Warrick f1dcd17e37 Enable Polish locale and use Polish plural forms
5 years ago
Chris Warrick bcff21f06f
Add missing messages to Polish translation
5 years ago
Chris Warrick 86a88b5ea5
Fix Polish translation of Preview button
5 years ago
Jelmer Vernooij 6092881bb2
Merge pull request #528 from mardy/fcgi-doc
5 years ago
Alberto Mardegan 02bf0a0759 docs: update deployment info for FastCGI
5 years ago
Jelmer Vernooij b0d385b6b5
Start on 0.12.3.
5 years ago
Jelmer Vernooij 7be6a756a3
Preparing
5 years ago
Jelmer Vernooij 0748eedd30
Merge pull request #526 from posativ/revert-356-feature/postbox-input-labels-2
5 years ago
Jelmer Vernooij 8aeff4acb2
Revert "Use <label>s rather than placeholders"
5 years ago
Jelmer Vernooij 1d5d356237
Merge pull request #525 from lioman/patch-1
5 years ago
Lioman 771f6b7c95
fix typo
5 years ago
Jelmer Vernooij 4fe24296a2 Start on 0.12.2.
5 years ago
Jelmer Vernooij 534d35e3c6
Preparing 0.12.1.
5 years ago
Jelmer Vernooij 12766c1e88 Make check no longer exists, update releasing docs.
5 years ago
Jelmer Vernooij a0b637eb5a Update NEWS.
5 years ago
Jelmer Vernooij 161f2dfa20
Revert "Removes potential '//' from email links (#420)"
5 years ago
Jelmer Vernooij 2f54c9236b Start on 0.12.1.
5 years ago
Jelmer Vernooij 434d0341f6
Preparing 0.12.0
5 years ago
Jelmer Vernooij bd22b0017f
Fix compatibility with new XML API.
5 years ago
Jelmer Vernooij abba561a1d
Fix some typos.
5 years ago
Jelmer Vernooij 24aeb9e567
Merge pull request #520 from Matolivier-1/master
5 years ago
Matthieu Olivier b1ea9b2fb3 Fix missing letter
5 years ago
root e3d5741c51 Rollback quickstart + split documentation for advanced migrations
5 years ago
Jelmer Vernooij 57af7a782d
Merge pull request #356 from mpchadwick/feature/postbox-input-labels-2
5 years ago
Benoit Latinier 5cfbb3274c
Merge pull request #522 from silberzwiebel/patch-1
5 years ago
kartoffelsalat b2251e9201
German translation for reply notification in de.js
5 years ago
Matthieu Olivier acb1e25193 Code was not visible
5 years ago
Matthieu Olivier 97ceaa1748 Activate generic importer + document usage
5 years ago
Matthieu Olivier c47f705907 Activate generic importer + document usage
5 years ago
Jelmer Vernooij 5d15728eb0
Merge pull request #511 from fliiiix/improvement/docs
5 years ago
Jelmer Vernooij 06d49292a6
Merge pull request #510 from fliiiix/bugfix/disqus_import
5 years ago
fliiiix d2ced12f80 Consistency and link to client config
5 years ago
Jelmer Vernooij 5b44ca8fb2
Merge pull request #519 from HorlogeSkynet/master
5 years ago
Samuel FORESTIER 1a3f803b96
Removes potential '//' from email links (#420)
5 years ago
Benoit Latinier 784e08170a
Merge pull request #514 from WanderlandTravelers/override-translations
5 years ago
Jelmer Vernooij 2ca39dee82
Merge pull request #515 from SnorlaxYum/patch-3
5 years ago
Sim ad2b7b6233
Update faq.rst
5 years ago
Jelmer Vernooij 915c74dc1b
Merge pull request #513 from WanderlandTravelers/attr-data-isso-reply-notifications
5 years ago
Brad Pitcher ebefbe6a4a
fix inline code highlighting
5 years ago
Brad Pitcher 423d73664b fix typo in translation override docs
5 years ago
Brad Pitcher 47a5b2c84b override translation strings using data attributes
5 years ago
Brad Pitcher dfbb7fa413
Add data-isso-reply-notifications to attributes
5 years ago
fliiiix a3ac7b9081 Use default IP if none is found Fix #477
6 years ago
fliiiix 1f4ced626c Import disqus posts without Email Fix #477
6 years ago
Jelmer Vernooij 40d011e6bb
List Benoît and myself as co-maintainers.
6 years ago
Jelmer Vernooij a45ef339e6
Merge pull request #490 from vincentbernat/fix/css-notification
6 years ago
Jelmer Vernooij adc4f839fc
Merge pull request #504 from doenietzomoeilijk/patch-1
6 years ago
Max Roeleveld 8a46e13028
Add a missing closing brace
6 years ago
Jelmer Vernooij 966d403ebb
Merge pull request #499 from jelmer/admin-bool
6 years ago
Jelmer Vernooij afc90a05cc
Reject actual logins when admin is disabled.
6 years ago
Jelmer Vernooij 5d811e3a51
Document the admin configuration.
6 years ago
Jelmer Vernooij 77813de8f9
Don't open the admin page with a default password by default. Fixes #491
6 years ago
Jelmer Vernooij e6132580a9
Merge pull request #496 from vincentbernat/fix/feedlink-append
6 years ago
Vincent Bernat fd46a7d86e embed: fix feed link creation on older browsers
6 years ago
Jelmer Vernooij 1d16db53da
Merge pull request #495 from flortsch/master
6 years ago
Florian Latifi c5311e1d7d Properly handle to field in mail notifications when using uWSGI spooler
6 years ago
Jelmer Vernooij b88e6e870d
Start on 0.11.2.
6 years ago
Jelmer Vernooij 8ad5496585
Release 0.11.1
6 years ago
Jelmer Vernooij 1e9465e3fe
Support providing path to SASS.
6 years ago
Jelmer Vernooij 1957ae517e
Add notes about building js and css.
6 years ago
Vincent Bernat 80257353ba css: reduce size of the label for reply notifications
6 years ago
Vincent Bernat 527f287826 css: fix vertical alignment of notification checkbox
6 years ago
Jelmer Vernooij 5dc07b29e4
Start on 0.11.1.
6 years ago
Jelmer Vernooij e648bee33d
Preparing release 0.11.0.
6 years ago
Jelmer Vernooij 54c72f379a
Add notes on releasing new versions.
6 years ago
Jelmer Vernooij cc07f0b22f
Fix another python3-specific flake.
6 years ago
Jelmer Vernooij 20f2f2a1f5
Remove old pyflakes commands.
6 years ago
Jelmer Vernooij 63cc15a962
Fix current flakes.
6 years ago
Jelmer Vernooij 62ddcba701
Move flakes command into Makefile.
6 years ago
Jelmer Vernooij eb0052c53f
Fix rst syntax error.
6 years ago
Jelmer Vernooij 0456d68f29
Fix address anonimization function on Python 2.
6 years ago
Jelmer Vernooij 8801c6eec8
remove unused imports.
6 years ago
Jelmer Vernooij f2333d716d
Merge pull request #489 from agdg/patch-1
6 years ago
Antonio Guillen 9619f56269
Fix markdown
6 years ago
Benoît Latinier dfbc80d5b6
Merge pull request #486 from vincentbernat/fix/anchor-load
6 years ago
Vincent Bernat 463f76cb0b embed: do not jump to unrelated anchor on load
6 years ago
Jelmer Vernooij f6271a04a2
Merge pull request #485 from gloomy-ghost/bleach
6 years ago
gloomy-ghost 13426ca43c fix tests
6 years ago
Jelmer Vernooij f1a4478272 Use bleach to sanitize HTML; allows use with newer versions of html5lib.
6 years ago
Jelmer Vernooij 8e37a88d6d
Merge pull request #484 from gloomy-ghost/tests
6 years ago
gloomy-ghost c27e3d9838 do not use `NOT NULL` with `DEFAULT` at the same time
6 years ago
Benoît Latinier d214e53bb6
Merge pull request #480 from frenchvandal/master
6 years ago
Benoît Latinier 14303d0377
Merge pull request #479 from javier-lopez/patch-1
6 years ago
Philippe e993b498a0
Minor typographic tweaks in French translation
6 years ago
Javier López 32f98ce3f2
update es.js
6 years ago
Benoît Latinier 5bc176d85b
Merge pull request #473 from jtanx/inet
6 years ago
Jeremy Tan faaff1d4ac Use AF_INET if AF_UNIX isn't available (i.e. Windows)
6 years ago
Benoît Latinier 4c9692264f add: contributors & changes
6 years ago
Benoît Latinier e680c91f4a
Merge pull request #472 from Rocket1184/hotfix/i18n-fix-zh-optional-placeholder
6 years ago
Benoît Latinier c9230d5a52
Merge pull request #438 from vincentbernat/fix/rss-relative
6 years ago
Rocka 2f45f3f82e
i18n: fix zh_CN/TW 'optional' in postbox placeholder
6 years ago
Benoît Latinier 9c57ac22e5
Merge pull request #471 from pozitron57/patch-6
6 years ago
Sergey Lisakov 20ba003791
Make password form focused on page load
6 years ago
Benoît Latinier dc4b0a7baf
Merge pull request #468 from pozitron57/patch-5
6 years ago
Benoît Latinier 263305f718
Merge pull request #469 from Rocket1184/hotfix/i18n-zh-postbox-notification
6 years ago
Sergey Lisakov be1e81b109
typo
6 years ago
Rocka 6d62e91a77
i18n: zh_CN/TW translate for 'postbox-notification; use full-width brackets
6 years ago
Sergey Lisakov fe3088df2b
fix link to misaka extensions
6 years ago
Benoît Latinier 0a7b8ae7df
Merge pull request #447 from tribut/wsgi-docs
6 years ago
Benoît Latinier 5dad7bd353
Merge pull request #466 from pozitron57/patch-4
6 years ago
Sergey Lisakov b1bbf70fd8
add "postbox-notification"
6 years ago
Benoît Latinier b93e055677
Merge pull request #463 from Rocket1184/hotfix/admin-page-comment-style
6 years ago
Benoît Latinier c801d18bd9
Merge pull request #452 from Rocket1184/fetaure/client-async-comment-load
6 years ago
Rocka 7f2b4eec8c
update CONTRIBUTORS.txt
6 years ago
Rocka 858d64d092
doc: minor syntax changes about async comments loading
6 years ago
Benoît Latinier 1d9cea8831
Merge pull request #458 from craigphicks/host-subdir
6 years ago
Benoît Latinier 53d5ad441c
Reply notification (#443)
6 years ago
Pelle Nilsson d80f7c4224 Documentation for reply notifications
6 years ago
Pelle Nilsson 18b1d11007 Add client-side configuration setting reply-notifications
6 years ago
Pelle Nilsson 1dd95d5aad New setting general.reply-notifications
6 years ago
Pelle Nilsson 171fcfab72 Postpone notifications to users until comment has been approved by moderator
6 years ago
Craig P Hicks 96575323cd conform to public_endpoint config option with internal local host fallback
6 years ago
Craig P Hicks af023741d9 changes as requested by @blatinier
6 years ago
root b7e1666dd4 allow isso to be accessed/mounted on a server subdirectory, e.g., https://example.com/isso
6 years ago
Benoît Latinier 9c3a209850
Merge pull request #456 from farooqkz/patch-1
6 years ago
Farooq Karimi Zadeh 70f9aab7cb
a little improvements
6 years ago
Rocka 795035ff6c
template: admin: add id `isso-root` to comments wrapper
6 years ago
Rocka 61b3b69557
doc: add doc for dynamic comment loading
6 years ago
Rocka a87815fcba
client: define an global object `Isso`, for loading comments dynamically
6 years ago
Pelle Nilsson 3e45ccb7e5 Fix whitespace issue
6 years ago
Pelle Nilsson 9b2a56e467 Introduce public-endpoint setting
6 years ago
Felix Eckhofer 8360dacbb1
Update docs for mod_wsgi
6 years ago
Pelle Nilsson 717837b35a Correct hash in 'unsubscribe' API example
6 years ago
Pelle Nilsson 0063fd6e88 Make unsubscribe work with notifications for replies
6 years ago
Vincent Bernat 8e4f2ab1c7 feed: remove trailing / from base URL
6 years ago
Benoît Latinier 3d0fdffcb7
Merge pull request #415 from facundobatista/generic-importer
6 years ago
Benoît Latinier 2135743ea7
Merge branch 'master' into generic-importer
6 years ago
Benoît Latinier 893f35a4e4
Merge pull request #436 from JuliusPC/patch-1
6 years ago
JuliusPC 729a65f177
Fix spelling of "E-Mail" → https://www.duden.de/rechtschreibung/E_Mail
6 years ago
Benoît Latinier 9d92f59aac
Merge pull request #434 from Lucas-C/deprecated_scss
6 years ago
Benoît Latinier 2b7c6629ea
Merge pull request #435 from Lucas-C/env_vars_doc
6 years ago
Lucas Cimon b73255ec2e
Adding documentation on the ISSO_CORS_ORIGIN env variable - close #407
6 years ago
Lucas Cimon 575c433fda
Substituting scss command in Makefile by node-sass + adding comment with instructions on how to install Makefile dependencies
6 years ago
Benoît Latinier 97721c7eef
Merge pull request #425 from vincentbernat/fix/dockerfile-cffi
6 years ago
Benoît Latinier 5e65e46b59
Merge pull request #426 from vincentbernat/fix/feedlink-append
6 years ago
Benoît Latinier e745f326db
Merge pull request #428 from pozitron57/patch-2
6 years ago
Benoît Latinier 2064f3a29b
Merge pull request #427 from Rocket1184/hotfix/i18n-zh-postbox-preview
6 years ago
Sergey Lisakov 530b541f68
Correct translation for "preview" button
6 years ago
Rocka dda616eef3
i18n: fix zh_CN/TW translate of 'postbox-preview'
6 years ago
Pelle Nilsson f6f61c547a Merge remote-tracking branch 'posativ/master' into reply_notification
6 years ago
Vincent Bernat 311f65d52b embed: fix feed link creation on older browsers
6 years ago
Vincent Bernat 9b911f3257 docker: install cffi inside virtualenv
6 years ago
Benoît Latinier c26d59de08
Merge pull request #424 from posativ/misaka_2
6 years ago
Steffen Prince 7cdb47d875 Update renderer to match Misaka 2.0 API
6 years ago
Steffen Prince eef7ea261d Add `cffi` to `setup_requires`
6 years ago
Steffen Prince c38851a6cd Update to misaka 2.0
6 years ago
Benoît Latinier ce98f93934 update changelog
6 years ago
Benoît Latinier 94d031444d add: CONTRIBUTORS + pep8
6 years ago
Benoît Latinier b21f2e4aaa
Merge pull request #317 from benjhess/feature/gravatar-support
6 years ago
Benoît Latinier 6da91d4ace
Merge branch 'master' into feature/gravatar-support
6 years ago
Benoît Latinier 3754ba7596
Merge pull request #414 from vincentbernat/fix/no-eval
6 years ago
Benoît Latinier 3d1cded70f Merge branch 'master' of github.com:posativ/isso
6 years ago
Benoît Latinier 466654b50d update CONTRIBUTORS
6 years ago
Benoît Latinier 514c5d42b6
Merge pull request #422 from Lucas-C/master
6 years ago
Benoît Latinier c14f639e75 add: CONTRIBUTORS update
6 years ago
Benoît Latinier ad6e868ba5
Merge pull request #416 from vincentbernat/feature/preview
6 years ago
Benoît Latinier dc6157897f
Merge pull request #423 from posativ/fix-tests
6 years ago
Benoît Latinier 3d648c2d29
fix tests due to non predictive html rendering
6 years ago
Lucas Cimon 501bdc59bf Bugfix to support <a> elements in SVG diagrams - close #421
6 years ago
Vincent Bernat b0264bc807 js: add a preview button to see a rendered preview
6 years ago
Benoît Latinier 55dac39bdd
Merge pull request #418 from vincentbernat/feature/nofollow-links
6 years ago
Benoît Latinier b5c40bedf7
Merge pull request #419 from vincentbernat/feature/atom-feed
6 years ago
Vincent Bernat 01cf96eeb7 feed: ensure Markdown rendering is applied to feeds
6 years ago
Benoît Latinier 502747cb75
Merge pull request #411 from Rocket1184/hotfix/demo-and-admin-redirect
6 years ago
Benoît Latinier bb924ead86
Merge pull request #417 from vincentbernat/fix/css-cleanup
6 years ago
Vincent Bernat 45f6b1eda3 feed: make /feed API call configurable server and client-side
6 years ago
Vincent Bernat bceb69518b js: put a link to Atom feed on top of the main postbox
6 years ago
Vincent Bernat a89debbc9c api: add a simple test for /feed endpoint
6 years ago
Vincent Bernat 5c6e78b9c1 api: ensure /feed is easily cacheable by issuing etag/last-modified headers
6 years ago
Vincent Bernat ebca06059a api: add /feed API to get an Atom feed for an URI
6 years ago
Vincent Bernat 8d8f9c8c59 html: add nofollow/noopener to links
6 years ago
Vincent Bernat fcf576dd08 css: remove CSS code for avatar in postbox
6 years ago
Pelle Nilsson 36d4ceb2d9 Don't send notification when someone responds to his/her own comment
6 years ago
Facundo Batista 14195d3711 Used proper open and not check timing
6 years ago
Facundo Batista 3ee13ab9fc Removed debug line
6 years ago
Facundo Batista be5792cb79 Merged master in
6 years ago
Facundo Batista 04b6d70b01 Added a generic way to migrate from a json file
6 years ago
Benoît Latinier 07ce742b77
add documentation for uberspaces users (closes #409)
6 years ago
Benoît Latinier 93ea722992
add contributors
6 years ago
Benoît Latinier e285c91112
Merge pull request #412 from vincentbernat/feature/dockerfile
6 years ago
Vincent Bernat 9618c0f3a3 jade: avoid using eval once compiled
6 years ago
Benoît Latinier 47b14ab0c8
Merge pull request #413 from vincentbernat/fix/doc-isso-id
6 years ago
Vincent Bernat 30f0c7eeb8 docs: document data-isso-id
6 years ago
Vincent Bernat 2b7c17a361 Provide a multi-staged Dockerfile
6 years ago
Pelle Nilsson 22a36bdb7c Support notifications also for replies
6 years ago
Pelle Nilsson da6bb0cec7 Fix faulty check for parent comment
6 years ago
Rocka 30fef390f5
fix: admin and demo view redirect issue
6 years ago
Benoît Latinier d854ce8347
Merge pull request #410 from Rocket1184/hotfix/space-between-number-and-cjk-char
6 years ago
Rocka 4e2d2dfb20
i18n: add space between number and CJK character
6 years ago
Yuchen Pei 73c7933548 A quick dirty fix of #401 (#406)
6 years ago
Cimon Lucas (LCM) 361c596bf2 Adding support for ISSO_CORS_ORIGIN env variable to allow defining wildcard CORS origins
6 years ago
Jelmer Vernooij af3903e462
Merge pull request #399 from facundobatista/patch-1
6 years ago
Facundo Batista 28e154acfc
Small typo
6 years ago
Pelle Nilsson c9045f5b1f Implement opt-out for email notifications
6 years ago
Pelle Nilsson bc4bc55025 Include link to comment in email notifications
6 years ago
Pelle Nilsson 2e85ec653f Make SMTP connections thread safe
6 years ago
Pelle Nilsson 107b9be003 Add notification column to database if needed
6 years ago
Pelle Nilsson c30873e8a2 Merge remote-tracking branch 'tsileo/reply_notification' into reply_notification
6 years ago
Benoît Latinier 450291440f update doc
6 years ago
Benoît Latinier 0ff39017c6 drop wheezy testing which is EndOfLife (closes #385)
6 years ago
cclauss 7f55c81e08 autopep8 the code and then flake8
6 years ago
Benoît Latinier a68d392f9c add changes in CHANGES file to prepare release
6 years ago
Jelmer Vernooij 2cc564eeca
Merge pull request #380 from cclauss/drop-support-for-python-2.6-and-3.3
6 years ago
cclauss 343f24377f
Return to pyflakes
6 years ago
Martin Schenck 6ccebce041 Improved German translation
6 years ago
cclauss b569b19a7f compat.py passes pyflakes test
6 years ago
Benoît Latinier 2b56963f31 fix pyflakes error, make travis happy
6 years ago
Benoît Latinier d2b573a4d5
Merge pull request #256 from blatinier/issue-10/admin-interface
7 years ago
Jelmer Vernooij ea3507910f
Merge pull request #354 from mpchadwick/feature/comment-placeholder-color
7 years ago
Jelmer Vernooij 42bbe174cd
Merge pull request #357 from mpchadwick/feature/hu-order
7 years ago
Max Chadwick 3efe0c86d9 Put hu into correct alphabetical order
7 years ago
Max Chadwick be26948fff Use <label>s rather than placeholders
7 years ago
Jelmer Vernooij 0232051d1d
Merge pull request #355 from mpchadwick/fix/hu-translation
7 years ago
Max Chadwick 9ab23c0908 Fix hungarian translation
7 years ago
Max Chadwick 21983a61b6 Darken placeholder text
7 years ago
Jelmer Vernooij b7526ecab1
Merge pull request #350 from guthypeter/master
7 years ago
Peter Guthy 02eaffea21 Added hungarian translation
7 years ago
Martin Zimmermann 650c6cf126 Merge pull request #341 from macedigital/fix-identicon-hash-size
7 years ago
Martin Zimmermann 6a60f831b0 remove unused variable
7 years ago
Martin Zimmermann 9b0e3d29fe revert incorrect removal of the internal server startup CLI
7 years ago
Matthias Adler 43623f349b
Fix: Truncate key-length when generating identicons
7 years ago
Martin Zimmermann c3933bd9fd fix sphinx build
7 years ago
Martin Zimmermann c72946dc14 Run travis tests with python 3.5 & python 3.6
7 years ago
Martin Zimmermann 4c03a43c28 remove data-isso-id from documentation, it usually doesn't work as expected
7 years ago
Martin Zimmermann e3a8d0b93d fix db test with incorrect SQL id, that happened work with pre-3.6 dicts before
7 years ago
Jelmer Vernooij dc883e672a
Fix short title underline.
7 years ago
Jelmer Vernooij 539e6e4486 Merge pull request #336 from jelmer/flakes
7 years ago
Jelmer Vernooij 280b0d925a
Skip compat module when running flakes checks.
7 years ago
Jelmer Vernooij 39debdb011
Fix flakes errors.
7 years ago
Jelmer Vernooij 59b345b648
Run pyflakes on travis.
7 years ago
Jelmer Vernooij 8c33a84dd3 Merge pull request #253 from jGleitz/apidoc
7 years ago
Jelmer Vernooij b8adfe3f18 Merge pull request #316 from shengbinmeng/patch-1
7 years ago
Shengbin Meng 2f7d6aa09b Merge branch 'master' into patch-1
7 years ago
Jelmer Vernooij 71bda25568 Merge pull request #312 from pellenilsson/fix-require-email
7 years ago
Jelmer Vernooij c8e4e74514 Merge pull request #335 from philipcmonk/time
7 years ago
Jelmer Vernooij afbcb6413e
Add da entry to i18n.js.
7 years ago
Jelmer Vernooij 6006cd9e82
Merge Danish translation from https://github.com/MadsRC/isso
7 years ago
Philip Monk 26f0e06e78 display only complete units of time
7 years ago
Jelmer Vernooij 616c61ea88 Merge pull request #291 from ivegotasthma/ivegotasthma-patch-1
7 years ago
Jelmer Vernooij a23317818f Merge pull request #315 from ginggs/patch-1
7 years ago
Jelmer Vernooij 384673ebdb
Run travis tests with python 3.5 & python 3.6.
7 years ago
Jelmer Vernooij 7bfe36bfdf
Specify Python versions to use in travis.
7 years ago
Jelmer Vernooij 2f3cd0ac46 Merge pull request #325 from SilverRainZ/patch-1
7 years ago
Jelmer Vernooij fe4a1a11e9 Merge pull request #298 from kAworu/patch-2
7 years ago
谷月轩 fd0147e8ab Fixed typo in isso.conf
7 years ago
Jeremy Tan b14b1b51a9 validate->activate
7 years ago
Jeremy Tan cc8e61533f Add templates to MANIFEST.in
7 years ago
Benoît Latinier 84381f4f48 add: link to the thread
7 years ago
Benoît Latinier 2adb779fef add: edit author/email/website/message
7 years ago
Benoît Latinier e3fddf4ae8 add: orders in administration
7 years ago
Benoît Latinier 3212bf762f fix 500 error on pagination
7 years ago
Benoît Latinier 0b6a0e4d5f add: group by thread
7 years ago
Benoît Latinier 1516f56cbd fix: cursor pointer on links delete/validate
7 years ago
Benoît Latinier 7a79746f73 add: show author email
7 years ago
Benoît Latinier 0a93c866ff Add a basic admin interface (Fix issue #10)
7 years ago
benjhess e9eebf58e3 Refactored comments unittest to work with optional gravatar feature
7 years ago
benjhess 48a3bd72c8 Trigger
7 years ago
benjhess cbd4d90cb7 Added optional gravatar support
7 years ago
Shengbin Meng a9500e29dd Add language "zh" as alias of "zh_CN"
7 years ago
Shengbin Meng 4b7a32afac Make the Chinese translations actually work
7 years ago
Graham Inggs 88aafa60e5 add SOURCELINK_SUFFIX for compatibility with Sphinx 1.5
7 years ago
Pelle Nilsson 45a481daeb Fix require-email setting, #308
7 years ago
Martin Zimmermann d37b5bb030 Merge pull request #303 from MorrisJobke/highlight-links-in-text
7 years ago
Morris Jobke f33ca31320
Highlight links by underline in comments
7 years ago
Mads R. Havmand cd460ef152 Danish translation
7 years ago
Alexandre Perrin 03b0de2d81 api.rst: JSON and english typos
7 years ago
Martin Zimmermann e853442468 Merge pull request #295 from kAworu/patch-1
7 years ago
Alexandre Perrin 3d67f10c72 default isso.conf typo
7 years ago
Martin Zimmermann f3b1d0ba07 Merge pull request #293 from ckoepp/master
7 years ago
Christian Koepp 45316e535a added FreeBSD rc.d script
7 years ago
ivegotasthma 09b69feae9 fix: add missing i18n entry
8 years ago
Martin Zimmermann 750bcd4829 Merge commit 'f9a36c8'
8 years ago
Martin Zimmermann 6e56afdd02 Merge branch 'pr/281'
8 years ago
Martin Zimmermann 5e7f010241 add persian to i18n
8 years ago
Philip Monk f9a36c8b92 update doc to reflect 5ce48de
8 years ago
Aidin Gharibnavaz 5bd7de084f Adding Persian translation.
8 years ago
Martin Zimmermann a361ee3980 Back to development: 0.10.7
8 years ago
Martin Zimmermann ed6542c764 Preparing release 0.10.6
8 years ago
Martin Zimmermann 339318eb92 set require-author to false by default
8 years ago
Martin Zimmermann 80c1faeb82 Back to development: 0.10.6
8 years ago
Martin Zimmermann 9114275bca Preparing release 0.10.5
8 years ago
Martin Zimmermann bc244c9218 add changelog for 0.10.5
8 years ago
Martin Zimmermann 121b9aa3af update authors
8 years ago
Martin Zimmermann eeb091974d add bulgarian translation to i18n.js, #272
8 years ago
Martin Zimmermann 37b7690b2b append Github's .gitignore to .gitignore
8 years ago
Martin Zimmermann 2542acfca8 remove duplicated werkzeug compat middleware
8 years ago
Martin Zimmermann 4fc6d5ac33 Merge pull request #263 from gumblex/master
8 years ago
Martin Zimmermann a52a0862a8 Merge pull request #260 from panta82/vote-levels
8 years ago
Martin Zimmermann 3dff66c2de Merge pull request #268 from lynndotconfig/master
8 years ago
Liping Wang 12d85242dc correct offset localtime for comments ago
8 years ago
Dingyuan Wang c83346834e fix "optional" in zh translations
8 years ago
Martin Zimmermann 689f3b906c Merge remote-tracking branch 'tska/finnish'
8 years ago
Timo Kankare 75371bdd43 Ordered fi after en.
8 years ago
Ivan Pantic fd3f6f820d Documentation for vote levels
8 years ago
Ivan Pantic 4972433406 Vote levels features (custom classes based on the comment votes)
8 years ago
Ivan Pantic b0f8606b0f Hiding zero votes is now done through CSS instead of javascript.
8 years ago
Ivan Pantic b620f2c0b0 Bug when content is number 0.
8 years ago
Timo Kankare 14962ad51f Added fi to i18.n.js.
8 years ago
Timo Kankare cf20bc5687 Finnish translation. i18n/fi.js added.
8 years ago
Martin Zimmermann 46b2874b3d Merge pull request #252 from blatinier/issue-27/data-attr-overide
8 years ago
Martin Zimmermann bbff002bd6 Merge pull request #254 from jGleitz/preview
8 years ago
Martin Zimmermann 7cba8f9880 Merge pull request #257 from blatinier/issue-124/mandatory-name
8 years ago
Benoît Latinier 459611c0e7 Add an option for mandatory author (Fix issue #124)
8 years ago
Joshua Gleitze 3c9bbda252 preview endpoint
8 years ago
Joshua Gleitze 2a11c000d4 convert bad tabs to spaces
8 years ago
Joshua Gleitze 084f6e5cf0 apidoc settings
8 years ago
Joshua Gleitze 8a9fe29bce apidoc for count
8 years ago
Joshua Gleitze afd4107ac3 apidoc for like & dislike
8 years ago
Joshua Gleitze ded4927ae4 apidoc for moderate
8 years ago
Joshua Gleitze c3439e5c79 apidoc for "delete comment"
8 years ago
Joshua Gleitze 9b79a98851 apidoc for "edit comment"
8 years ago
Joshua Gleitze 1f804bcf8e apidoc for "view comment"
8 years ago
Joshua Gleitze b2d9c80b5f apidoc for "new comment"
8 years ago
Joshua Gleitze 5ca5d680fa apidoc for fetch
8 years ago
Joshua Gleitze aa373f798f + apidoc.json
8 years ago
Benoît Latinier 54a11c95f7 Update documentation
8 years ago
Benoît Latinier f1325ccaca Fix issue #27 on override thread discovery with custom data-attributes
8 years ago
Martin Zimmermann 4d3f6fa390 Back to development: 0.10.5
8 years ago
Martin Zimmermann 40ba1663aa Preparing release 0.10.4
8 years ago
Martin Zimmermann edf62b1c61 update changelog
8 years ago
Martin Zimmermann 0377c8bb20 fix reponse for OPTIONS response on Python 3, #242
8 years ago
Martin Zimmermann e2fba8af66 no longer install as zipped egg
8 years ago
Martin Zimmermann 2612fbc0f5 fix missing wrapper attribute
8 years ago
Martin Zimmermann c8311bdda7 Merge pull request #243 from pozitron57/patch-2
8 years ago
Sergey Lisakov 2a6aa1203b Fix pluralisation issues and inexact translation
8 years ago
Martin Zimmermann b5e7c78dcc Merge pull request #237 from jelmer/rjs
8 years ago
Martin Zimmermann 05bd6b3137 Merge pull request #236 from jelmer/man
8 years ago
Jelmer Vernooij ba43de3f9b
Add make variable for r.js, so it can easily be overriden.
8 years ago
Jelmer Vernooij 2dca30f46d
Create man page directory before moving files to them.
8 years ago
Martin Zimmermann 6971f14233 Back to development: 0.10.4
8 years ago
Martin Zimmermann 8d9ee1db14 Preparing release 0.10.3
8 years ago
Martin Zimmermann 3cd475ec31 follow redirects, fix #193
8 years ago
Martin Zimmermann 00bb42e831 add support for older setuptools (6.0 or maybe even older)
8 years ago
Martin Zimmermann 0e1b8b38b2 Back to development: 0.10.3
8 years ago
Martin Zimmermann 0e817a928a Preparing release 0.10.2
8 years ago
Martin Zimmermann 8b76a7a208 update changelog and fix wording
8 years ago
Martin Zimmermann 3281d645f8 run Tox with setuptools 6.1 or higher
8 years ago
Martin Zimmermann a3a1d8cb86 fix getAttribute return value
8 years ago
Martin Zimmermann 098f09e6df upgrade Travis' pip for PEP 426
8 years ago
Martin Zimmermann 032058b778 fix typo
8 years ago
Martin Zimmermann e24ac9aff8 Back to development: 0.10.2
8 years ago
Martin Zimmermann 7961943571 Preparing release 0.10.1
8 years ago
Martin Zimmermann 2e132f26db update changelog
8 years ago
Martin Zimmermann 3e309e0850 fix input field value access
8 years ago
Martin Zimmermann 6fdcbfb1b7 Back to development: 0.11
8 years ago
Martin Zimmermann b4da20a541 Preparing release 0.10
8 years ago
Martin Zimmermann 9496d7d4c2 use environment markers as defined by PEP 426
8 years ago
Martin Zimmermann 1401132c73 pin html5lib to 0.9999999
8 years ago
Martin Zimmermann 829ef4f502 make universal wheels
8 years ago
smileboy b48ac000b1 config.js error.
8 years ago
Martin Zimmermann 84f8acb21e Merge pull request #225 from gdyer/patch-1
8 years ago
Graham Dyer 890f296d58 fixes 2 typos
8 years ago
Martin Zimmermann 57f902acd4 actually include isso/defaults.ini
8 years ago
Martin Zimmermann 622b59f8a4 move default config expansion to function body (`default` already exists)
8 years ago
Martin Zimmermann 93e783ed60 symlink share/isso.conf to isso/defaults.ini and include it properly
8 years ago
Martin Zimmermann 5eb101fcb3 bump copyright year in docs and manpages
8 years ago
Martin Zimmermann 8579cbd6f8 fix undefined variable usage and enumeration logic
8 years ago
Martin Zimmermann 00ed48a1d3 fix incorrect define header
8 years ago
Martin Zimmermann 4c36db1ad2 Merge branch 'legacy/0.9'
8 years ago
Martin Zimmermann 1f86fa897e add vi (vietnamese) translation, #222
8 years ago
Martin Zimmermann dd9ebdc46b Merge remote-tracking branch 'origin/pr/222'
8 years ago
Martin Zimmermann 815c7f54b5 add hr (croatian) translation
8 years ago
Martin Zimmermann dc1d83b74b add cs (czech) translation
8 years ago
Martin Zimmermann 1201c5145d fix link to gevent, #204
8 years ago
Martin Zimmermann 7d89b94d66 Merge remote-tracking branch 'origin/pr/198'
8 years ago
Martin Zimmermann e52c7f801a ignore pip-selfcheck.json
8 years ago
Martin Zimmermann 4517235f85 add py35 to tox, fix missing dependency for py26
8 years ago
Martin Zimmermann fc10a30091 fix init script, #221
8 years ago
Martin Zimmermann 2e41c4728a don't extend native objects, #191
8 years ago
Đinh Xuân Sâm 5ce7084f59 Fix typo: s/trướ/trước
9 years ago
Đinh Xuân Sâm f1a8aed320 Completed Vietnamese translation.
9 years ago
Đinh Xuân Sâm 17747368e1 Created new branch for translation: vietnamese.
9 years ago
Martin Zimmermann 2137441958 Merge remote-tracking branch 'origin/pr/214'
9 years ago
Martin Zimmermann 33c02b45b4 Merge remote-tracking branch 'origin/pr/202'
9 years ago
Martin Zimmermann 54952e67ad Merge remote-tracking branch 'origin/pr/199'
9 years ago
Martin Zimmermann bf9e803dce Merge remote-tracking branch 'origin/pr/195'
9 years ago
Steffen Prince 367ee48b76 Pin misaka to 1.x
9 years ago
Sergey Lisakov 45c4e43ba2 Update ru.js
9 years ago
Sergey Lisakov 11dff33450 Update ru.js
9 years ago
Sergey Lisakov ed0f680e97 Update Russian translation
9 years ago
Nick Hu b9ce411f85 write unit tests for require-email
9 years ago
Nick Hu cb21af4cc5 Add config for requiring emails
9 years ago
Nick Hu 9e9e7b6f66 Make Vagrant actually work
9 years ago
Mushiyo 2af17b6204 corrected punctuation
9 years ago
Mushiyo 19179b1764 modify to a better translation
9 years ago
Mushiyo b98133836d Added zh_TW translation
9 years ago
Martin Zimmermann 5d21e1b20a pin html5lib due to regression
9 years ago
Martin Zimmermann 88e77bf9a3 typo
9 years ago
Martin Zimmermann 8018a7e23d update russian translation
9 years ago
Martin Zimmermann f940d630c4 update changelog
9 years ago
Martin Zimmermann cd0b41f2a6 Merge pull request #189 from avinassh/patch-1
9 years ago
avinassh 23c19a061c Added instructions to deploy Isso on Openshift
9 years ago
Martin Zimmermann 8f23a73edd update changelog for 0.9.10
9 years ago
Martin Zimmermann 3a18013db6 Back to development: 0.9.11
9 years ago
Martin Zimmermann 42e0642263 Preparing release 0.9.10
9 years ago
Julien Enselme 7e58f6b97c Correct auth without password or username.
9 years ago
Martin Zimmermann 3f73d83c99 Merge pull request #184 from wendal/i18n_zh_CN
9 years ago
wendal 6e4d9ba446 add: zh_CN Translation
9 years ago
Martin Zimmermann 35897ef01f Merge pull request #175 from Jenselme/fedora
9 years ago
Martin Zimmermann a2bda63bf0 Merge pull request #174 from Jenselme/smptAuth
9 years ago
Julien Enselme 7e51915f54 Add fedora in the prebuilt-package section of docs/docs/install.rst.
9 years ago
Julien Enselme 6973128eac Correct auth without password or username.
9 years ago
Martin Zimmermann 630e76f66c Merge branch 'legacy/0.9'
9 years ago
Martin Zimmermann beca18a344 Back to development: 0.9.10
9 years ago
Martin Zimmermann c8655731d6 Preparing release 0.9.9
9 years ago
Martin Zimmermann ed38ce13d8 update changelog
9 years ago
Martin Zimmermann f5566c1325 encode username/password in SMTP auth only for Python 2, fix #146
9 years ago
Martin Zimmermann 596acb7f79 request with User-Agent 'Isso/...', #151
9 years ago
Sergey 56c81c2d06 Update ru.js
9 years ago
Martin Zimmermann 45053f9c0c catch errors in http response
9 years ago
Martin Zimmermann 8e4db5a7a2 typo
9 years ago
Martin Zimmermann f681002e7e add support for html5lib below 0.95, #168
9 years ago
Martin Zimmermann c3c519ad0e add compatibility middleware for werkzeug 0.8, #170
9 years ago
Martin Zimmermann 9451704d3d Revert "require html5lib 0.95 or higher, #168"
9 years ago
Martin Zimmermann e5219157a7 Merge pull request #172 from xuhdev/fix-159-2
9 years ago
Hong Xu 21e91efbf9 Save the session-key as a unicode string in the db
9 years ago
Martin Zimmermann 957fc72eb1 reject request if reject is actually defined, fix #165
9 years ago
Martin Zimmermann 0466977109 replace bullet with HTML entity, fix #169
9 years ago
Martin Zimmermann e97d2aba04 require html5lib 0.95 or higher, #168
9 years ago
Martin Zimmermann aa64b27684 Python 2.7.9 didn't get the context=ssl... backport unfortunately
9 years ago
Martin Zimmermann e3dedef7ed Merge pull request #167 from albohlabs/feature/ansible
9 years ago
Daniel Gräber 09ad29aa81 Remove .idea from gitignore
9 years ago
Martin Zimmermann e098a199f3 Merge pull request #164 from xuhdev/typo
9 years ago
Martin Zimmermann 4c9a2aba30 fetch polish translation
9 years ago
Daniel Gräber 7725cfeefc Remove old apache conf
9 years ago
Daniel Gräber b37487dcef Add comments for debugging
9 years ago
Daniel Gräber aea85f807f Edit uwsgi and nginx use tcp socket
9 years ago
Daniel Gräber 5a29d2742d Remove virtualenv
9 years ago
Daniel Gräber 6deacf9527 Update add myself to contributors list
9 years ago
Daniel Gräber 894086bda2 Fix catch socket timeout and error exceptions
9 years ago
Daniel Gräber 63c3e1252c Update gitignore
9 years ago
Daniel Gräber 8387a5390f Replace vagrant shell provisioning with ansible
9 years ago
Hong Xu 81d09bfbe4 Fix some typos in the intallation doc.
9 years ago
Martin Zimmermann 0d55dadf46 Merge pull request #163 from albohlabs/patch-1
9 years ago
Daniel Gräber 763586448a Fix npm uglifyjs missing package error
9 years ago
Martin Zimmermann 5f511023e9 Merge pull request #158 from rolisz/patch-1
9 years ago
Roland Szabo 2a3075d0fb Catch exception in anonymize function
9 years ago
Martin Zimmermann 26b889d381 Merge remote-tracking branch 'origin/pr/157'
9 years ago
Matias 1957f4f99f Update CONTRIBUTORS.txt
9 years ago
Matias dc172975ee Update CONTRIBUTORS.txt
9 years ago
Matias c5496b103d Added spanish translation
9 years ago
Matias 68a8c2c380 Update client.rst
9 years ago
Matias 4d7fc956ab Create es.js
9 years ago
Martin Zimmermann e271851b50 fetch greek translation
9 years ago
Martin Zimmermann f80460a685 Merge pull request #152 from jelmer/dutch
9 years ago
Jelmer Vernooij 00c4d4149e Import transifex improvements to Dutch translation.
9 years ago
Martin Zimmermann 81756dcefa Merge pull request #150 from jelmer/dutch
9 years ago
Jelmer Vernooij dcb7f6457c Add Dutch translations.
9 years ago
Martin Zimmermann 7c4565afc7 Merge pull request #148 from richard-fine/feature/vagrant
10 years ago
Richard Fine 6ac5e8c6d0 Reverted change to demo file; changed web server config to mount the uWSGI app at the root, as it turns out it's capable of serving the demo file itself
10 years ago
Richard Fine 18118ec080 tell uWSGI to auto-reload when .py files are changed during development
10 years ago
Richard Fine 3977a8d00d set up Vagrant support to make it easy to get a dev environment going quickly
10 years ago
Martin Zimmermann a6c859c5a5 add changelog for 0.10
10 years ago
Martin Zimmermann f47df75422 use system's CA certificates for Python 2.7.9 or higher to verify TLS connection
10 years ago
Martin Zimmermann d70eb160b9 Merge branch 'legacy/0.9'
10 years ago
Martin Zimmermann 83d3c7443c remove email field from JSON example
10 years ago
Martin Zimmermann d6602b7fe4 Merge branch 'pr/143'
10 years ago
Martin Zimmermann 7f5ff457c1 integrate swedish translation into Isso
10 years ago
Martin Zimmermann afe6ece865 Merge branch 'pr/144'
10 years ago
Martin Zimmermann b45f39e662 resolve when comment is in moderation queue, too
10 years ago
Théo Zimmermann bba91b3f93 don't lose comment if it failed to create
10 years ago
Gustav Näslund da47dbd374 Added swedish translation file
10 years ago
Martin Zimmermann 4b97684e22 fix editing when avatars are disabled
10 years ago
Martin Zimmermann c9be737f5e document broken stdout notifications, #138
10 years ago
Martin Zimmermann 89d6ea076b add --empty-id flag to import weird Disqus exports, fixes #135
10 years ago
Martin Zimmermann 8918c4a186 Merge pull request #137 from Zimmi48/master
10 years ago
Martin Zimmermann 928198f340 update translations
10 years ago
Martin Zimmermann a1be81f6c8 add UnicodeDecodeError to troubleshooting (via #93)
10 years ago
Théo Zimmermann 97015d4034 correct order by in sql request
10 years ago
Martin Zimmermann 4b64615f92 set encoding to UTF-8 for Disqus and WordPress import, also fixes #93
10 years ago
Martin Zimmermann 0d6d975f98 use /opt/isso as virtualenv and add a simple sysvinit script
10 years ago
Martin Zimmermann f0a0f40223 add fallback localStorage implementation if not functional, #134
10 years ago
Martin Zimmermann f06be982e7 add target to lint for Python 2 and 3
10 years ago
Martin Zimmermann d469324392 fix 'undefined name 'buffer'' on Python 3.x
10 years ago
Martin Zimmermann b800a8bbe7 Merge pull request #130 from Zimmi48/master
10 years ago
Théo Zimmermann d0a0ac39b0 bug fixed: was trying to remove an unexisting span.votes
10 years ago
Martin Zimmermann 74363d44ba Merge branch 'legacy/0.9'
10 years ago
Martin Zimmermann da174cd712 Back to development: 0.9.9
10 years ago
Martin Zimmermann 33a1edafac Preparing release 0.9.8
10 years ago
Martin Zimmermann a07296b9fd update changelog
10 years ago
Martin Zimmermann 88be07d5de import backports.configparser before configparser, #128
10 years ago
Martin Zimmermann 9aaac16d17 add #125 and #129 to troubleshooting
10 years ago
Julien Lamy 4bc70dd09b Update documentation for deployment with mod_wsgi
10 years ago
Martin Zimmermann 9c2a48b388 Merge branch 'legacy/0.9'
10 years ago
Martin Zimmermann 1bfd4fb916 Back to development: 0.9.8
10 years ago
Martin Zimmermann 278f5c74bc Preparing release 0.9.7
10 years ago
Martin Zimmermann 6a3a9ea114 SMTP authentication uses bytes, not unicode, fixes #126
10 years ago
Martin Zimmermann ad1fdfdb32 add note about broken WXR (use xmllint to fix)
10 years ago
Martin Zimmermann 721e87a843 Merge branch 'legacy/0.9'
10 years ago
Martin Zimmermann 6c345f5d81 Back to development: 0.9.7
10 years ago
Martin Zimmermann 9f90e67f0a Preparing release 0.9.6
10 years ago
Martin Zimmermann 4b4b4a6a66 add changes for 0.9.6
10 years ago
Martin Zimmermann c712d196d7 add option to hide voting feature, closes #115
10 years ago
Martin Zimmermann e2911da560 fix #106
10 years ago
Martin Zimmermann d21aed83f8 save name, email and website in localStorage, closes #119
10 years ago
Martin Zimmermann d9098b83f0 use different identifiers to avoid mixin events
10 years ago
Martin Zimmermann c8acd461d3 do not export email field
10 years ago
Martin Zimmermann f7e51fd03d Merge branch 'legacy/0.9'
10 years ago
Martin Zimmermann 1a4b252bfe Back to development: 0.9.6
10 years ago
Martin Zimmermann 3e8d8f0122 Preparing release 0.9.5
10 years ago
Martin Zimmermann 77508ffb3a add changes for 0.9.5
10 years ago
Martin Zimmermann 5e76d406dc add link to Docker image
10 years ago
Martin Zimmermann 881788a049 fix <time> semantics and add title attribute, closes #104
10 years ago
Martin Zimmermann 0f1b95a125 add log to file option, closes #103
10 years ago
Martin Zimmermann 8a58afc8e6 fix order of converting HTML back to text
10 years ago
Martin Zimmermann 4a8cbcd8f0 limit request size, closes #107
10 years ago
Martin Zimmermann 7008e88314 prevent &nbsp; insertion, closes #112
10 years ago
Martin Zimmermann 7701dafa13 remove old Markup.js module
10 years ago
Martin Zimmermann 4aaa5bbdd2 fix #106
10 years ago
Martin Zimmermann 57d4380106 fix french 'date-now'
10 years ago
Martin Zimmermann e02687a066 remove superscript extension from defaults (again)
10 years ago
Martin Zimmermann 392add88e6 disable intra emphasis
10 years ago
Martin Zimmermann f0d1958cc0 Merge branch 'legacy/0.9'
10 years ago
Martin Zimmermann a89f228477 fix virtualenv path, add yum/apt-get hints and AUR package
10 years ago
Martin Zimmermann 7f82745cd0 Back to development: 0.9.5
10 years ago
Martin Zimmermann 203f9c7c1a Preparing release 0.9.4
10 years ago
Martin Zimmermann 978d22e77e fix wrong status code type
10 years ago
Martin Zimmermann ce9781df51 Merge branch 'legacy/0.9'
10 years ago
Martin Zimmermann b59f650c99 Back to development: 0.9.4
10 years ago
Martin Zimmermann d2769d73b4 Preparing release 0.9.3
10 years ago
Martin Zimmermann 261d0e4985 update changelog
10 years ago
Martin Zimmermann 35acf1e17e from __future__ import unicode_literals
10 years ago
Martin Zimmermann ee8a84c0b2 add CSS for blockquote and pre
10 years ago
Martin Zimmermann ad9384e8d7 preserve HTML tags while editing comments
10 years ago
Martin Zimmermann 0c8ec38dda don't scrollIntoView on expanding comments
10 years ago
Martin Zimmermann 9674afbeed remove isso.css from pypi distribution
10 years ago
Martin Zimmermann 9fa7edb74b add version fallback, closes #102
10 years ago
Martin Zimmermann 3975227ada Revert "border-radius only for first and last input"
10 years ago
Martin Zimmermann b2b6af24d6 fix clode block generation
10 years ago
Martin Zimmermann d386590e57 Merge branch 'legacy/0.9'
10 years ago
Martin Zimmermann 400e523c4c Back to development: 0.9.3
10 years ago
Martin Zimmermann a201b24802 Preparing release 0.9.2
10 years ago
Martin Zimmermann fbb55bf38a add esperanto translation
10 years ago
Martin Zimmermann 221b782157 refactor configuration parsing
10 years ago
Martin Zimmermann f489ae63d6 Python3.4 now uses system's CA to connect to SMTP via TLS
10 years ago
Martin Zimmermann 4a7830a96d add [hash] to isso.conf and update some strings
10 years ago
Martin Zimmermann 396eccfa00 fix error message
10 years ago
Martin Zimmermann 33ce5959e9 Merge branch 'pr/101'
10 years ago
Martin Zimmermann 4c697c50fd reuse environment variable
10 years ago
Federico Ceratto fb28eb85c5 Enable isso settings directory
10 years ago
Martin Zimmermann 9260e143f1 decouple hash generation from comment view and allow customization
10 years ago
Martin Zimmermann 91e63c7e5f simplify import format detection
10 years ago
Martin Zimmermann 3f50db4174 add link to package on AUR
10 years ago
Martin Zimmermann dc40d80c81 Merge branch 'legacy/0.9'
10 years ago
Martin Zimmermann 41dd7d8173 Back to development: 0.9.2
10 years ago
Martin Zimmermann d5a30bc09f Preparing release 0.9.1
10 years ago
Schoewilliam ad32243708 Fix issue #97 : Alignment problem with the submission forms fields
10 years ago
Martin Zimmermann 3f8bbd6f3c remvoe pagination and css improvements from the contribution page
10 years ago
Martin Zimmermann 661f2a6881 Back to development: 0.10
10 years ago
Martin Zimmermann 82932eb57f Preparing release 0.9
10 years ago
Martin Zimmermann d2644c3ba3 increase Copyright year
10 years ago
Martin Zimmermann a201534c8d differenciate between deployment and init scripts
10 years ago
Martin Zimmermann 119ceb0035 improve site targets
10 years ago
Martin Zimmermann 460db1dd1e update landing page
10 years ago
Martin Zimmermann a741c62cd6 use python-passlib fallback on Debian
10 years ago
Martin Zimmermann 211f637569 remove Django's PBKDF2 in favour of werkzeug.security.pbkdf2_hex
10 years ago
Martin Zimmermann 932274921c extend FastCGI deployment example with virtualenv
10 years ago
Martin Zimmermann 64054ec029 remove unused code, fix pyflakes and jshint hints
10 years ago
Martin Zimmermann 8c6a7e209e pin versions for Squeeze and Wheezy, also remove py26 from default run
10 years ago
Martin Zimmermann 94ee6a6981 use el.on("click") to load more comments and prevent default
10 years ago
Martin Zimmermann d0a50c7905 fix french translation
10 years ago
Martin Zimmermann 2d37637019 add fr and de translation for postbox-website, fix french translation
10 years ago
Martin Zimmermann 20fc700e98 fix typos
10 years ago
Martin Zimmermann 96206b110c fix pagination translations and pluralization
10 years ago
Martin Zimmermann cff9cabe9a update changelog
10 years ago
Martin Zimmermann 9c16237a6a update authors
10 years ago
Martin Zimmermann 8b5462ed2e remove /check-ip
10 years ago
Martin Zimmermann 5d3f178fca remove debug statement
10 years ago
Martin Zimmermann e00ef92a67 remove now unused parent-hightlight rule
10 years ago
Martin Zimmermann 96620e8cd0 rename .postbox to .isso-postbox
10 years ago
Martin Zimmermann 165caa9620 show all top-level comments (for now)
10 years ago
Martin Zimmermann f2aedff1a3 Merge branch 'fix/reference-deleted-comment'
10 years ago
Martin Zimmermann 8fefe3a616 fix hidden reply to deleted comment (and change a few names)
10 years ago
Martin Zimmermann 6bfd1344ba Merge branch 'remove-avatar-preview'
10 years ago
Martin Zimmermann e1b4ddb123 remove sha1.js and pbkdf2.js, part of #51
10 years ago
Martin Zimmermann 14fac577df fix syntax
10 years ago
Martin Zimmermann 16663d44f8 hide avatar during editing
10 years ago
Martin Zimmermann 0211322915 remove avatar preview in postbox
10 years ago
Martin Zimmermann 7474be12f0 Merge branch 'add-website-field'
10 years ago
Martin Zimmermann 77d40a99eb border-radius only for first and last input
10 years ago
Martin Zimmermann 065460d78a add tests for website validation
10 years ago
Martin Zimmermann 5b0ce6471a add website input
10 years ago
Martin Zimmermann fd8465eb1c warn about incorrect notification backends, fix #95
10 years ago
Martin Zimmermann 8cf9ea348e .gitignore /lib64 and /man
10 years ago
Martin Zimmermann c334655d91 Merge branch 'jade'
10 years ago
Martin Zimmermann 29085979e5 document jade as new (build) dependency
10 years ago
Martin Zimmermann 1a970557b8 add new JS deps to Makefile
10 years ago
Martin Zimmermann b60dbd3e42 remove old template 'struct'
10 years ago
Martin Zimmermann 608119e8ce add r.js build optimization for jade plugin
10 years ago
Martin Zimmermann ccf59fba2a initial support for jade
10 years ago
Martin Zimmermann 7c3bd52821 stub requirejs-text to save ~5kb
10 years ago
Martin Zimmermann 47618d06f2 simplify GH readme to avoid repetition
10 years ago
Martin Zimmermann fcc4cd63b4 fix #93
10 years ago
Martin Zimmermann a5e1dcc225 Merge pull request #92 from Schoewilliam/39-84
10 years ago
Schoewilliam dd14bb91db #49 : Comments thread and submission form now support data-isso-avatar="false"
10 years ago
Martin Zimmermann 4f98bca202 hide avatars with data-isso-avatar="false", part of #49
10 years ago
Martin Zimmermann 29b4643c5e Merge pull request #91 from Schoewilliam/39-84
10 years ago
Schoewilliam 34a50910f2 Tweaking the submission form — making it responsive
10 years ago
Martin Zimmermann c7c7595991 Merge branch 'pr-89'
10 years ago
Martin Zimmermann 9e3d933d82 remove targets to generate CSS from SCSS
10 years ago
Schoewilliam c2dd9d3bb5 getting rid of SCSS
10 years ago
Martin Zimmermann fb182ae93f Merge branch 'pr-83', closes #83
10 years ago
Martin Zimmermann e6fdfb03eb do not limit From: field to email address-only, closes #87
10 years ago
Martin Zimmermann 5c91a84951 fix uWSGI spooling for Python3
10 years ago
Martin Zimmermann d5e5e9c7e2 use numerical values in default configuration to match user-provided values
10 years ago
Martin Zimmermann ed810cdf39 fetch all nested comments when set to 'inf'
10 years ago
Martin Zimmermann 324326c2ba translate Hidden to german and french
10 years ago
Martin Zimmermann f3a7f65687 remove keyworded function arguments and fix JS hints
10 years ago
Martin Zimmermann 59bfde7c03 idiomatic python
10 years ago
Martin Zimmermann 4ee509ed02 Merge branch 'feature/75', closes #75
10 years ago
Martin Zimmermann 123ea26ca9 handle WP's query-string "pages" and variable WXR namespaces
10 years ago
Srijan Choudhary 26ae30f76c Update docs
10 years ago
Srijan Choudhary 26d26ae71b Add i18n for "Hidden"
10 years ago
Srijan Choudhary 8879db59b8 Show all comments if limit/nested_limit set as inf
10 years ago
Srijan Choudhary baef73f1e8 Change default values of config params
10 years ago
Srijan Choudhary ab927e39d0 Add a reveal on click parameter
10 years ago
Srijan Choudhary 2e2fba89a6 Add some tests
10 years ago
Srijan Choudhary abc0eaaf1d Handle limit/nested_limit zero
10 years ago
Martin Zimmermann 333bba728b update docs
10 years ago
Martin Zimmermann 346b60a9b3 disqus import imports anonymized IP address now
10 years ago
Martin Zimmermann 39101c2ac7 Disqus import uses Progressbar class as well
10 years ago
Martin Zimmermann 12f8af8434 add initial support to import WordPress comments
10 years ago
Martin Zimmermann 263095cf5f allow Travis CI to disturb the IRC channel
10 years ago
Martin Zimmermann 9dabf88b93 Travis supports Python 3.4 now
10 years ago
Martin Zimmermann 0154113c80 replace assert with assertEqual
10 years ago
Martin Zimmermann 910da2a6c0 refactor disqus migration code into a class
10 years ago
Martin Zimmermann cb36107eda reword and clean documentation
10 years ago
Srijan Choudhary 54b156844b Add max-comments limit for nested replies
10 years ago
Srijan Choudhary f5da45e525 Correct total comments count
10 years ago
Srijan Choudhary 76d5dbc97f Take max comments to load from config.js
10 years ago
Srijan Choudhary 8dbf4d5337 Client side changes for new API
10 years ago
Srijan Choudhary a5d8a0cfe1 Change in API: hidden_replies field instead of passed_replies
10 years ago
Srijan Choudhary 3c3e83b05c Bug in API: Reply count should also filter by the after value passed
10 years ago
Srijan Choudhary 8fdceeaafb Handle edge cases occuring in tests
10 years ago
Srijan Choudhary 71024cea70 API update - new comments format
10 years ago
Martin Zimmermann d3aa8129c4 Merge branch 'pr/85'
10 years ago
Martin Zimmermann a753efe42d add doctype and charset
10 years ago
Srijan Choudhary cb0acc5ac0 Add a basic demo page
10 years ago
Martin Zimmermann 087b9e98ff fix tx-push script to work with GNU mktemp
10 years ago
Martin Zimmermann b9102b44e2 fix russian translation for "Anonymous"
10 years ago
Martin Zimmermann 9706d7df12 ... but Travis does not ship Python 3.4
10 years ago
Martin Zimmermann f48cbf65b0 add Python 3.4 to Tox and Travis CI
10 years ago
Martin Zimmermann 26cc7eb634 Merge branch 'feature/79', closes #79
10 years ago
Martin Zimmermann 344f94e5a0 rm forward (reference) arrow
10 years ago
Martin Zimmermann 1e5878bec3 auto-correct wrong/invalid parent to max nesting level of 1
10 years ago
Martin Zimmermann ce14726f2f set parent to null if parent is not top-level comment
10 years ago
Martin Zimmermann 24adafa25b increase db version after migration
10 years ago
Martin Zimmermann 9ee0a1a2eb reply to comment now nests to max. level of 1, part of #79
10 years ago
Martin Zimmermann 5d2daa1244 add db migration, part of #79
10 years ago
Martin Zimmermann 1253d40422 Merge branch 'fix/issue-77'
10 years ago
Martin Zimmermann f09b6b9bdb preserve line breaks when editing comments, finally closes #77
10 years ago
Martin Zimmermann 748da790da Merge branch 'fix/issue-77'
10 years ago
Martin Zimmermann 13d979e290 Back to development: 0.8.3
10 years ago
Martin Zimmermann 16d79891da Preparing release 0.8.2
10 years ago
Martin Zimmermann 4444abc3d6 Merge branch 'fix/issue-77' into legacy/0.8
10 years ago
Martin Zimmermann 5ab3a7bed4 remove white-space: pre, closes #77
10 years ago
Martin Zimmermann d6237de982 Back to development: 0.8.2
10 years ago
Martin Zimmermann d5f3a118bb Preparing release 0.8.1
10 years ago
Martin Zimmermann 3fc52b94b9 Merge branch 'hotfix/origin-fallback'
10 years ago
Martin Zimmermann 52c41eef44 Merge branch 'hotfix/origin-fallback' into legacy/0.8
10 years ago
Martin Zimmermann 0509e15f67 clarify [general] host usage a bit
10 years ago
Martin Zimmermann 765a91fefb return first item of [general] -> host if origin is hidden
10 years ago
Martin Zimmermann cef44ab0ad Back to development: 0.9
10 years ago
Martin Zimmermann 87179fe8fa Preparing release 0.8
10 years ago
Martin Zimmermann e60ebfbdca correct manpage title
10 years ago
Martin Zimmermann eeebb4c34c fix coverage generation
10 years ago
Martin Zimmermann c4430c857c add test for database migration
10 years ago
Martin Zimmermann 6bb8207236 update changelog
10 years ago
Martin Zimmermann b199651548 run testsuite via setuptools
10 years ago
Martin Zimmermann 0233619d35 mv specs/ to tests/
10 years ago
Martin Zimmermann fb68f9a820 adjust coverage generation a bit
10 years ago
Martin Zimmermann 5166e69265 remove doctest-ignore-unicode dependency
10 years ago
Martin Zimmermann 4fa0f0d8ea fix server time offset calculation for IE10
10 years ago
Martin Zimmermann e393711859 use HTTP_REFERER as fallback if HTTP_ORIGIN is not sent
10 years ago
Martin Zimmermann 09451ff707 replace textarea with a content-editable div
10 years ago
Martin Zimmermann 638ddc6359 pass event through for $.on
10 years ago
Martin Zimmermann dd0837c0f7 remove superscript extension from Markdown
10 years ago
Martin Zimmermann 103e68e27b update changelog
10 years ago
Martin Zimmermann 78b34ecdd2 return only publicely visible comments on /count
10 years ago
Martin Zimmermann 1e2efb24b3 remove duplicate test
10 years ago
Martin Zimmermann 5ce48de94a add POST request to get comment counts for multiple URLs
10 years ago
Martin Zimmermann 0d6d072281 add isso.conf example to source distribution
10 years ago
Martin Zimmermann ce35b9ff0e Merge branch 'doc-improvements'
10 years ago
Martin Zimmermann da782654b2 remove warning when SMTP is not configured as notifcation backend
10 years ago
Martin Zimmermann e4ad81cde0 exit if no website(s) are configured and remove default host
10 years ago
Martin Zimmermann d69bfc2511 fix visual update up/downvote
10 years ago
Martin Zimmermann 0b816a0677 store session-key in database (once generated on db creation), #74
10 years ago
Martin Zimmermann de50c683bc extend installation docs
10 years ago
Martin Zimmermann e75fa4b7e1 add target to generate Isso's CSS
10 years ago
Martin Zimmermann 2c2c911ba4 Isso requires SQLite 3.3.8 or later
10 years ago
Martin Zimmermann ac41731c6a update changelog to reflect latest changes
10 years ago
Martin Zimmermann 5df4b40a1f rewrite Makefile
10 years ago
Martin Zimmermann b19084b3e2 add manpage stuff
10 years ago
Martin Zimmermann ad31a67d8f get doc version via installed distribution
10 years ago
Martin Zimmermann 8f293ad435 configurable avatar colors
10 years ago
Martin Zimmermann c6e9c7eee4 Revert "run tests without depending on an already installed instance"
10 years ago
Martin Zimmermann a94472d062 add BSD license header to crypto.py
10 years ago
Martin Zimmermann f6e25d7acb Merge pull request #72 from eroen/master.public
10 years ago
eroen 4e5e8c44f7 run tests without depending on an already installed instance
10 years ago
Martin Zimmermann 33fa56d8e9 add suggested flattr button
10 years ago
Martin Zimmermann 83361fbdac improve "time from now" helper, based on moment.js
10 years ago
Martin Zimmermann ffd5882810 Merge branch 'fix-time-ago', closes #69
10 years ago
Martin Zimmermann 9a678e4691 an attempt to address #69
10 years ago
Martin Zimmermann 8540d45fae cumtime is only available in Python 2.7.4 or later
10 years ago
Martin Zimmermann 772730dbcd fix make_app logic
10 years ago
Martin Zimmermann c4b80ff702 make CORS middleware more generic to use
10 years ago
Martin Zimmermann 3b248b293f set SMTP timeout to 10 seconds and make it configurable, ref 9a735e8
10 years ago
Martin Zimmermann 72c38c2312 set day_diff to 0 if negative, related to #69
10 years ago
Martin Zimmermann 9a735e8eac initial SMTP connection now timeouts after 5 seconds, closes #70
10 years ago
Martin Zimmermann 154d591ae9 add CONTRIBUTORS.txt
10 years ago
Martin Zimmermann 9272e7390f Merge branch 'feature/configurable-markdown', closes #62
10 years ago
Martin Zimmermann 1b0a74e188 expand db path, closes #68
10 years ago
Martin Zimmermann c6214e31d7 document new [markup] section
10 years ago
Martin Zimmermann 8f70a3a7cb add tests for 81ecc8e
10 years ago
Martin Zimmermann d93d77c8c7 refactor markup and sanitization code
10 years ago
Martin Zimmermann 6071a85787 add `Config.getlist` method
10 years ago
Martin Zimmermann 8f86109cb6 use system's python interpreter
10 years ago
Martin Zimmermann d1a0b3f6f9 refactor docs a bit, add section for mod_fastcgi and uberspace.de
10 years ago
Martin Zimmermann 56316b8998 remove html5 writer (does not work with Sphinx)
10 years ago
Martin Zimmermann f4cfa6f63c Merge pull request #67 from srijan/master
10 years ago
Srijan Choudhary 5525184243 Docs update: forward url protocol in sample nginx configs
10 years ago
Martin Zimmermann 079e5d19da add note about insecure connections, #65
10 years ago
Martin Zimmermann 16d085c9d1 improve tests for comment field validation
10 years ago
Martin Zimmermann 5efa81b57e replace assert foo == bar with appropriate self.assert$Foo calls
10 years ago
Martin Zimmermann b100517e4b update developer's guide
10 years ago
Martin Zimmermann 6aa122bc58 fix typo
10 years ago
Martin Zimmermann 3d9665b523 remove now obsolete Makefile
10 years ago
Martin Zimmermann 1c3c826ada replace requirejs-domready with a (self-made) HTML5 idiom, #51
10 years ago
Martin Zimmermann cfbf595605 mention mailing list and fix CSS typo
10 years ago
Martin Zimmermann a92471ca9a allow failures for TOX_ENV=backport
10 years ago
Martin Zimmermann 4681a391ee pin versions to current Debian Wheezy/Unstable
10 years ago
Martin Zimmermann f3e5d8dc1c add support for html5lib==0.95, fixes #60
10 years ago
Martin Zimmermann 417bd4614c Back to development: 0.8
10 years ago
Martin Zimmermann 45e838fab1 Preparing release 0.7
10 years ago
Martin Zimmermann d65c984220 update changelog
10 years ago
Martin Zimmermann 518820a4af fix typo in reply-to-self conf, #59
10 years ago
Martin Zimmermann 14a2f82134 s/tls/starttls/
10 years ago
Martin Zimmermann 335caa4887 Merge pull request #58 from JocelynDelalande/default-to-587-starttls
10 years ago
Jocelyn Delande cbf63f5a4e default smtp to port=587 and security=starttls
10 years ago
Martin Zimmermann aae07a3c24 Merge branch 'pr/57'
10 years ago
Martin Zimmermann b94329fc66 also mention count.min.js
10 years ago
Jocelyn Delande 5cdab92a4b Documentation on comment counter.
10 years ago
Martin Zimmermann baff120800 fix french pluralform
10 years ago
Martin Zimmermann 442cca5030 Merge pull request #56 from JocelynDelalande/patch-1
10 years ago
JocelynDelalande 2e60fc7f68 Update api.rst
10 years ago
Martin Zimmermann cbd449dcd0 Merge branch 'transifex'
10 years ago
Martin Zimmermann 5f990e3697 link example cfg, fix markup errors and show content table, closes #52
10 years ago
Martin Zimmermann 3a1f92b8bd use html5lib's sanitizer, supersedes 3713d5e
10 years ago
Martin Zimmermann 3713d5e8ee allow raw HTML markup for a few (whitelisted) tags
10 years ago
Martin Zimmermann 36d702c7bc proper use of Misaka's HTML render flags (fix malicious HTML injection)
10 years ago
Martin Zimmermann 241b278863 whitelist external ipaddr package in tox configuration
11 years ago
Martin Zimmermann dcd473967b Merge branch 'remove-q-lib'
11 years ago
Martin Zimmermann 6006a12778 fix wrong logic when vote counter stays at zero (e.g. self-vote)
11 years ago
Martin Zimmermann 306d2d9f9e log 5xx errors
11 years ago
Martin Zimmermann a29393ee3f replace kriskowal/q with 50 LoC homebrew implementation, part of #51
11 years ago
Martin Zimmermann ebf6ca7a85 add Transifex translation to contributing guide
11 years ago
Martin Zimmermann bfae158bde update translations from Transifex (initial pull)
11 years ago
Martin Zimmermann 4d530fb2f1 add Transifex project configuration file
11 years ago
Martin Zimmermann 055a20606a add tx-pull and tx-push FILE helper scripts
11 years ago
Martin Zimmermann 9dd066c6a6 reflect security = ... in docs and print warning if used
11 years ago
Martin Zimmermann c50fe22eb1 fix port -> listen snippet
11 years ago
Thomas Sileo a322cf673a Bugfix
11 years ago
Thomas Sileo e50ecc7811 Removed debug info
11 years ago
Thomas Sileo 08313c191c Added reply notification for commenter
11 years ago
Martin Zimmermann ab27ce5450 Merge pull request #48 from chimo/starttls
11 years ago
Chimo 658e065f23 Adds STARTTLS support to SMTP notifications
11 years ago

@ -0,0 +1,47 @@
---
kind: pipeline
name: default
platform:
os: linux
arch: amd64
steps:
- name: publish
pull: default
image: plugins/docker:18.09
settings:
registry: https://registry.nixaid.com
repo: "registry.nixaid.com/${DRONE_REPO_NAMESPACE}/${DRONE_REPO_NAME}"
tags:
- latest
username:
from_secret: docker_username
password:
from_secret: docker_password
# storage_path: /drone/docker
# storage_driver: aufs
# ipv6: false
# debug: true
when:
branch:
- master
event:
- push
- tag
- name: notify
pull: default
image: drillster/drone-email:latest
settings:
from: "Drone CI <noreply@nixaid.com>"
host: mx.nixaid.com
port: 587
subject: "NIXAID Drone Pipeline {{#success build.status}}SUCCESS{{else}}FAILURE{{/success}} Notification"
when:
event:
- push
- tag
status:
- success
- failure

@ -0,0 +1,85 @@
# workspace:
# base: /workspace
# path: src/git.nixaid.com/arno/myapp/
#
# branches:
# - master
pipeline:
restore_cache:
image: drillster/drone-volume-cache:latest
restore: true
mount:
- /drone/docker
# Set the ``DRONE_VOLUME=/tmp/drone-cache:/cache`` drone-server variable,
# so you can benefit from the caching.
# Otherwise you will have to make this repository trusted in Drone and use
# the volumes as follows.
# volumes:
# - /tmp/drone-cache:/cache
# drone repo add arno/isso
# drone secret add/update --name docker_username --value arno --event push --event tag --event deployment arno/isso
# drone secret add/update --name docker_password --value "$(pass show vps/registry.nixaid.com | head -1)" --event push --event tag --event deployment arno/isso
publish:
image: plugins/docker:17.12
# repo: andrey01/${DRONE_REPO_NAME}
registry: registry.nixaid.com
repo: registry.nixaid.com/arno/${DRONE_REPO_NAME}
tags:
- latest
# - ${DRONE_COMMIT_SHA:0:7}
# group: docker
# dockerfile: Dockerfile
secrets: [docker_username, docker_password]
# Since we restore the docker image cache to /drone/docker
storage_path: /drone/docker
use_cache: true
when:
event: [push, tag]
branch: master
rebuild_cache:
image: drillster/drone-volume-cache:latest
rebuild: true
mount:
- /drone/docker
# Set the ``DRONE_VOLUME=/tmp/drone-cache:/cache`` drone-server variable,
# so you can benefit from the caching.
# Otherwise you will have to make this repository trusted in Drone and use
# the volumes as follows.
# volumes:
# - /tmp/drone-cache:/cache
# # ca_cert comes from /srv/data/registry/certs/ca.crt
# claircheck:
# # image: jmccann/drone-clair:1
# image: andrey01/drone-clair
# url: http://clair:6060
# secrets: [ docker_username, docker_password ]
# # ignore errors for now. This will work only in drone 0.9 https://github.com/drone/drone-runtime/commit/3e8bd99f60f4032226523320cd2b2321f9525159
# err_ignore: true
# scan_image: registry.nixaid.com/arno/${DRONE_REPO_NAME}:latest
# ca_cert: |
# -----BEGIN CERTIFICATE-----
# MIIBOjCB4KADAgECAgkAzhpbLWXa4H0wCgYIKoZIzj0EAwIwEDEOMAwGA1UEAwwF
# bXktQ0EwHhcNMTgwNzA5MjIzMTAzWhcNMjgwNzA2MjIzMTAzWjAQMQ4wDAYDVQQD
# DAVteS1DQTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFIE8bTfQ76U5qG/Xgjw
# BbQU0oRJLYlRxBIWF9MTNSJr2LoaoyrU8jrcWQGRrfKPoVuwUJWp2tp5SJy0AHH7
# 4fijIzAhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKkMAoGCCqGSM49
# BAMCA0kAMEYCIQCYbTbxRD2yX4LzGjh84fKPWPQM9ps8RE2nfwZjqdRUGgIhAOHb
# USigh6FzqEPk2jiaV3t1wNtChRWRfupTKG6CD345
# -----END CERTIFICATE-----
notify:
image: drillster/drone-email:latest
from: Drone CI <noreply@nixaid.com>
subject: NIXAID Drone Pipeline {{#success build.status}}SUCCESS{{else}}FAILURE{{/success}} Notification
host: mx.nixaid.com
port: 587
# username: arno
# secrets: [ email_username, email_password ]
# recipients: [ andrey.arapov@nixaid.com ]
when:
status: [success, failure] # changed
event: [push, tag]

99
.gitignore vendored

@ -3,15 +3,18 @@
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~
*~
*.pyc
.Python
.sass-cache
.vagrant
/bin
/include
/lib
/lib64
/man
/share
/isso.egg-info/
/isso/js/components
@ -22,3 +25,97 @@
/docs/_build
/docs/_static/css/site.css
/pip-selfcheck.json
# github/gitignore
Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# IPython Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# dotenv
.env
# virtualenv
.venv/
venv/
ENV/
# Spyder project settings
.spyderproject
# Rope project settings
.ropeproject

@ -1,12 +1,25 @@
language: python
python: 2.7
env:
- TOX_ENV=py26
- TOX_ENV=py27
- TOX_ENV=py33
- TOX_ENV=backport
matrix:
include:
- python: 3.5
env: TOX_ENV=py35
- python: 3.6
env: TOX_ENV=py36
- python: 3.7
dist: xenial
env: TOX_ENV=py37
- python: 3.8
dist: xenial
env: TOX_ENV=py38
install:
- pip install tox
- sudo rm -rf /dev/shm && sudo ln -s /run/shm /dev/shm
- pip install -U pip
- pip install flake8 tox
script:
- tox -e $TOX_ENV
- make flakes
notifications:
irc:
channels:
- "chat.freenode.net#isso"
on_success: change
on_failure: always

@ -0,0 +1,6 @@
[main]
host = https://www.transifex.com
[isso.js]
file_filter = .tx/js/<lang>
source_lang = en
type = KEYVALUEJSON

@ -1,10 +1,445 @@
Changelog for Isso
==================
0.7 (unreleased)
0.12.3 (UNRELEASED)
-------------------
- New "flags" option in the [markdown] section to customize Misaka's Markdown
HTML rendering. By default, no flags are set.
[markup]
flags = skip-html, escape, hard-wrap
Check docs/configuration/server.rst for more details.
0.12.2 (2019-01-21)
-------------------
- Revert use of labels instead of placeholders, since it breaks
mail notifications. #524
0.12.1 (2019-01-19)
-------------------
- Revert fix for duplicate slashes, as it prevents isso from
starting in some cases. #523
0.12.0 (2019-01-18)
-------------------
- Fix compatibility with new XML API.
- Don't enable admin interface with default password by default. #491
- Add support and documentation for "generic" imports.
- Remove potential duplicate slashes in URLs from
email links. #420
- Add data-isso-reply-notifications to attributes in configuration.
- Use default IP in imports if none is found. Fixes imports of some comments.
- embed: fix feed link creation on older browsers.
- Properly handle to field in mail notifications when using uWSGI spooler
- css: fix vertical alignment of notification checkbox
0.11.1 (2018-11-03)
-------------------
- Include pre-built minified JavaScript and CSS.
0.11.0 (2018-11-03)
-------------------
Bugs & features:
- Fix link in moderation mails if isso is setup on a sub-url (e.g. domain.tld/comments/)
- Add reply notifications
- Add admin interface
- Add links highlighting in comments
- Add apidoc
- Add rc.d script for FreeBSD
- Add the possibility to set CORS Origin through ISSO_CORS_ORIGIN environ variable
- Add preview button
- Add Atom feed at /feed?uri={thread-id}
- Add optionnal gravatar support
- Add nofollow noopener on links inside comments
- Add Dockerfile
- Upgraded to Misaka 2
- Some tests/travis/documentation improvements and fixes + pep8
Translations:
- Fix Chinese translation & typo in CJK
- Add Danish translation
- Add Hungarian translation
- Add Persian translation
- Improvement on german translation
0.10.6 (2016-09-22)
-------------------
- fix missing configuration field
0.10.5 (2016-09-20)
-------------------
- add support for different vote levels, #260
List of vote levels used to customize comment appearance based on score.
Provide a comma-separated values (eg. `"0,5,10,25,100"`) or a JSON array (eg.
`"[-5,5,15]"`).
For example, the value `"-5,5"` will cause each `isso-comment` to be given
one of these 3 classes:
- `isso-vote-level-0` for scores lower than `-5`
- `isso-vote-level-1` for scores between `-5` and `4`
- `isso-vote-level-2` for scores of `5` and greater
These classes can then be used to customize the appearance of comments (eg.
put a star on popular comments).
- add new post preview API endpoint, #254
- add an option for mandatory author, #257
- clients can now use `data-title` to get the HTML title for a new page, #252
- add finish translation and other minor bugfixes
0.10.4 (2016-04-12)
-------------------
- fix wrapper attribute when using data-isso-require-mail="true", #238
- fix reponse for OPTIONS response on Python 3, #242
0.10.3 (2016-02-24)
-------------------
- follow redirects, #193
0.10.2 (2016-02-21)
-------------------
- fix getAttribute return value
0.10.1 (2016-02-06)
-------------------
- fix empty author, email and website values when writing a comment
0.10 (2016-02-06)
-----------------
- add new configuration section for hash handling.
[hash]
salt = Eech7co8Ohloopo9Ol6baimi
algorithm = pbkdf2
You can customize the salt, choose different hash functions and tweak the
parameters for PBKDF2.
- Python 3.4+ validate TLS connections against the system's CA. Previously no
validation was in place, see PEP-446__ for details.
- add `fenced_code` and `no_intra_emphasis` to default configuration.
Fenced code allows to write code without indentation using `~~~` delimiters
(optionally with language identifier).
Intra emphasis would compile `foo_bar_baz` to foo<em>bar</em>baz. This
behavior is very confusing for users not knowing the Markdown spec in detail.
- new configuration to require an email when submitting comments, #199. Set
[guard]
require-email = true
and use `data-isso-require-email="true"` to enable this feature. Disabled by
default.
- new Bulgarian translation by sahwar, new Swedish translation by Gustav
Näslund #143, new Vietnamese translation by Đinh Xuân Sâm, new Croatian
translation by streger, new Czech translation by Jan Chren
- fix SMTP setup without credentials, #174
- version pin Misaka to 1.x, html5lib to 0.9999999
.. __: https://www.python.org/dev/peps/pep-0466/
0.9.10 (2015-04-11)
-------------------
- fix regression in SMTP authentication, #174
0.9.9 (2015-03-04)
------------------
- several Python 3.x related bugfixes
- don't lose comment form if the server rejected the POST request, #144
- add localStorage fallback if QUOTA_EXCEEDED_ERR is thrown (e.g. Safari
private browsing)
- add '--empty-id' flag to Disqus import, because Disqus' export sucks
- (re)gain compatibility with Werkzeug 0.8 and really old html5lib versions
available in Debian Squeeze, #170 & #168
- add User-Agent when Isso requests the URL, an alternate way to #151 (add
'X-Isso' when requesting).
0.9.8 (2014-10-08)
------------------
- add compatibility with configparser==3.5.0b1, #128
0.9.7 (2014-09-25)
------------------
- fix SMTP authentication using CRAM-MD5 (incorrect usage of
`smtplib`), #126
0.9.6 (2014-08-18)
------------------
- remember name, email and website in localStorage, #119
- add option to hide voting feature, #115
data-isso-vote="true|false"
- remove email field from JSON responses
This is a quite serious issue. For the identicon, an expensive hash is used
to avoid the leakage of personal information like a real email address. A
`git blame` reveals, the email has been unintenionally exposed since the very
first release of Isso :-/
The testsuite now contains a dedicated test to prevent this error in the
future.
0.9.5 (2014-08-10)
------------------
- prevent no-break space (&nbsp;) insertion to enable manual line breaks using
two trailing spaces (as per Markdown convention), #112
- limit request size to 256 kb, #107
Previously unlimited or limited by proxy server). 256 kb is a rough
approximation of the next database schema with comments limited to 65535
characters and additional fields.
- add support for logging to file, #103
[general]
log-file =
- show timestamp when hovering <time>, #104
- fix a regression when editing comments with multiple paragraphs introduced
in 0.9.3 which would HTML escape manually inserted linebreaks.
0.9.4 (2014-07-09)
------------------
- fixed a regression when using Isso and Gevent
0.9.3 (2014-07-09)
------------------
- remove scrollIntoView while expanding further comments if a fragment is used
(e.g. #isso-thread brought you back to the top, unexpectedly)
- implement a custom Markdown renderer to support multi-line code listings. The
extension "fenced_code" is now enabled by default and generates HTML
compatible with Highlight.js__.
- escape HTML entities when editing a comment with raw HTML
- fix CSS for input
- remove isso.css from binary distribution to avoid confusion (it's still there
from the very first release, but modifications do not work)
.. __: http://highlightjs.org/
0.9 (2014-05-29)
----------------
- Nothing changed yet.
- comment pagination by Srijan Choudhary, #15
Isso can now limit the amount of comments shown by default and add link to
show more. By default, all top-level comments are shown but only 5 nested
comments (per reply). You can override the settings:
isso-data-max-comments-top="N"
isso-data-max-comments-nested="N"
Where N is a number from 0 to infinity ("inf"). If you limit the amount of
shown top level comments, the overall comment count may be incorrect and a
known issue.
You can also configure the amount of comments shown per click (5 by default):
isso-data-reveal-on-click="N"
This feature also required a change in the comment structure. Previously, all
comments are stored tree-like but shown linearly. To ease the implementation
of pagination, the comment tree is now limited to a maximum depth of one.
Jeff Atwood explains, why `discussions are flat by design`__.
.. __: http://blog.codinghorror.com/web-discussions-flat-by-design/
When you upgrade, Isso will automatically normalize the tree and some
information gets lost. All new replies to a comment are now automatically a
direct child of the top-level comment.
- style improvements by William Dorffer, #39, #84 #90 and #91
Isso now longer uses a fat SCSS library, but plain CSS instead. The design is
now responsive and no longer sets global CSS rules.
- experimental WordPress import, #75
Isso should be able to import WXR 1.0-1.2 exports. The import code is based
on two WXR dumps I found (and created) and may not work for you. Please
report any failure.
- avatar changes, #49
You can now configure the client to not show avatars:
data-isso-avatar="false"
Also there is no longer an avatar shown next to the comment box. This is due
to the new CSS and removes two runtime dependencies.
- you may now set a full From header, #87
[smtp]
from = Foo Bar <spam@local>
- SMTP (all caps) is now recognized for notifications, #95
- Isso now ships a small demo site at /demo, #44
- a few bugfixes: Disqus import now anonymizes IP addresses, uWSGI spooling for
Python 3, HTTP-Referer fallback for HTTP-Origin
- remove Django's PBKDF2 implementation in favour of the PBKDF2 function
available in werkzeug 0.9 or higher. If you're still using werkzeug 0.8, Isso
imports passlib__ as fallback (if available).
This release also features a new templating engine Jade__ which replaces
Markup.js__. Jade can compile directly to JavaScript with a tiny runtime module
on the client. Along with the removal of sha1.js and pbkdf2.js and a few build
optimizations, the JS client now weighs only 40kb (12kb gzipped) 52kb resp.
17kb before.
.. __: https://pypi.python.org/pypi/passlib
.. __: http://jade-lang.com/
.. __: https://github.com/adammark/Markup.js
0.8 (2014-03-28)
----------------
- replace ``<textarea>`` with ``<div contentedtiable="true">`` to remove the
sluggish auto-resize on input feature. If you use a custom CSS, replace
``textarea`` with ``.textarea`` and also set ``white-space: pre``.
- remove superscript extension from Markdown defaults as it may lead to
unexpected behavior for certain smileys such as "^^". To enable the extension,
add
[markup]
options = superscript
allowed-elements = sup
to your configuration.
- comment count requests are now bundled into a single POST request, but the old
API is still there (deprecated though).
- store *session-key* in database (once generated on database creation). That
means links to activate, edit or delete comments are now always valid even
when you restart Isso.
Currently statically set session keys in ``[general]`` are automatically
migrated into the database on startup and you will get a notice that you can
remove this option.
- fix undefined timestamp when client time differs for more than 1 second.
The human-readable "time ago" deltas have been refined to match `Moment.js`_
behavior.
- avatar colors and background can now be customized:
* ``data-isso-avatar-bg="#f0f0f0"`` sets the background color
* ``data-isso-avatar-fg="#9abf88 #5698c4 #e279a3 #9163b6 ..."`` sets possible
avatar colors (up to 8 colors are possible).
- new [markup] section to customize Misaka's Markdown generation (strikethrough,
superscript and autolink enabled by default). Furthermore, you can now allow
certain HTML elemenets and attributes in the generated output, e.g. to enable
images, set
[markup]
allowed-elements = img
allowed-attributes = src
Check docs/configuration/server.rst for more details.
- replace requirejs-domready with a (self-made) HTML5 idiom, #51
.. _Moment.js: http://momentjs.com/docs/#/displaying/fromnow/
0.7 (2014-01-29)
----------------
- fix malicious HTML injection (due to wrong API usage). All unknown/unsafe
HTML tags are now removed from the output (`html5lib` 0.99(9) or later) or
properly escaped (older `html5lib` versions).
See 36d702c and 3a1f92b for more details.
- remove kriskowal/q JS library (promises implementation) in favour of a
self-made 50 LoC implementation to ease packaging (for Debian), #51
- add documentation to display a comment counter, #56 and #57
- SMTP notifications now support STARTTLS and use this transport security
by default, #48 and #58. This also changes the configuration option from
`ssl = [yes|no]` to `security = [none|starttls|ssl]`.
- translation can now be made (and updated) with Transifex_. If you want to
take ownership for a language, contact me on IRC.
- fix french pluralform
- the (by default random) session-key is now shown on application startup
to make different keys per startup more visible
- use `threading.lock` by default for systems without semaphore support
.. _Transifex: https://www.transifex.com/projects/p/isso/
0.6 (2013-12-16)

@ -0,0 +1,121 @@
# Contributions to Isso
## Creator & Maintainer
* Martin Zimmermann <info@posativ.org>
## Co-Maintainers
* Benoît Latinier @blatinier <benoit@latinier.fr>
* Jelmer Vernooij <jelmer@jelmer.uk>
## Contributors
In chronological order:
* Florian Baumann <flo@noqqe.de>
* Documentation fixes in the early days
* Federico Ceratto <federico.ceratto@gmail.com>
* Support for ipaddr
* Added a sample configuration file
* Sploinga <xavier@sploing.be>
* French translation
* Laurent Arnoud <laurent@spkdev.net>
* Make Isso not accept blank comments
* Chimo <chimo@chromic.org>
* STARTTLS for SMTP notifications
* Jocelyn Delande <jocelyn at delalande dot fr>
* Documentation for comment counter and API
* Default SMTP security to STARTTLS
* Srijan Choudhary <srijan4@gmail.com>
* Correct nginx examples in documentation
* Added comment pagination feature
* Provide a demo site
* William Dorffer <schoewilliam@gmail.com>
* Convert SCSS to plain CSS
* Refresh style, make it responsive
* Baptiste Darthenay
* Esperanto translation
* Matías Ducasa <https://github.com/matiasducasa>
* Spanish translation
* Daniel Gräber <https://github.com/albohlabs>
* Added ansible for provisioning
* Nick Hu <https://github.com/NickHu>
* Added configuration to require email addresses (no validation)
* Fix Vagrantfile
* Benoît Latinier @blatinier <benoit@latinier.fr>
* Fix thread discovery
* Added mandatory author
* Added admin interface
* Ivan Pantic <ivanpantic82@gmail.com>
* Added vote levels
* Martin Schenck @schemar
* Improvement in the german translation
* @cclauss
* Pep8 and drop of legacy supports (old python & debian version tested in travis)
* Make travis use pyflakes
* Lucas Cimon @Lucas-C
* Added the possibility to define CORS origins through ISSO_CORS_ORIGIN environment variable
* Fix a bug with <a> in <svg>
* Fixing likes counter of replies not being displayed
* Adding contrib/dump_comments.py
* Adding a [server] proxy-fix-enable-x-prefix configuration option
* Using .access_route instead of .remote_addr to take into account HTTP_X_FORWARDED_FOR header
* Yuchen Pei @ycpei
* Fix link in moderation emails when isso is installed in a sub URL
* @Rocket1184
* Fix typo in CJK translations
* @vincentbernat
* Added documentation about data-isso-id attribute (overriding the standard isso-thread-id)
* Added multi-staged Dockerfile
* Added atom feed
* Added a nofollow/noopener on links inside comments to protect against bots
* Added a preview using the existing preview endpoint
* @p-vitt & @M4a1x
* Documentation on troubleshooting for uberspace users
* Facundo Batista <facundo@taniquetil.com.ar>
* Added a generic way to migrate from a json file
* @benjhess
* Optionnal gravatar support
* Steffen Prince @sprin
* Upgrade to Misaka 2
* Rocka <i@rocka.me>
* Implementation and documentation about async comment loading
* Pelle Nilsson @pellenilsson
* Reply notifications
* Craig P Hicks @craigphicks
* Fix sub urls configurations on admin interface
* Chris Warrick @Kwpolska
* Update Polish translation
* Redirect to comment after moderation
* [Your name or handle] <[email or website]>
* [Brief summary of your changes]

@ -0,0 +1,34 @@
# First, compile JS stuff
FROM node:dubnium-buster
WORKDIR /src/
COPY . .
RUN npm install -g requirejs uglify-js jade bower \
&& make init js
# Second, create virtualenv
FROM python:3.8-buster
WORKDIR /src/
COPY --from=0 /src .
RUN python3 -m venv /isso \
&& . /isso/bin/activate \
&& pip3 install --no-cache-dir --upgrade pip \
&& pip3 install --no-cache-dir gunicorn cffi flask \
&& python setup.py install \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
# Third, create final repository
FROM python:3.8-slim-buster
WORKDIR /isso/
COPY --from=1 /isso .
# Configuration
VOLUME /db /config
EXPOSE 8080
ENV ISSO_SETTINGS /config/isso.cfg
CMD ["/isso/bin/gunicorn", "-b", "0.0.0.0:8080", "-w", "4", "--preload", "isso.run", "--worker-tmp-dir", "/dev/shm"]
# Example of use:
#
# docker build -t isso .
# docker run -it --rm -v /opt/isso:/config -v /opt/isso:/db -v $PWD:$PWD isso /isso/bin/isso -c \$ISSO_SETTINGS import disqus.xml
# docker run -d --rm --name isso -p 8080:8080 -v /opt/isso:/config -v /opt/isso:/db isso

@ -1,6 +1,19 @@
include man/man1/isso.1
include man/man5/isso.conf.5
include share/isso.conf
include isso/js/embed.min.js
include isso/js/embed.dev.js
include isso/js/count.min.js
include isso/js/count.dev.js
include isso/js/admin.js
include isso/defaults.ini
include isso/templates/admin.html
include isso/templates/disabled.html
include isso/templates/login.html
include isso/css/admin.css
include isso/css/isso.css
include isso/img/isso.svg

@ -1,18 +1,75 @@
all: css js
css:
scss isso/css/isso.scss isso/css/isso.css
js:
r.js -o isso/js/build.embed.js
r.js -o isso/js/build.embed.js optimize="none" out="isso/js/embed.dev.js"
r.js -o isso/js/build.count.js
r.js -o isso/js/build.count.js optimize="none" out="isso/js/count.dev.js"
site:
cd docs/ && sphinx-build -E -b dirhtml -a . _build
scss docs/_static/css/site.scss docs/_build/_static/css/site.css
coverage:
nosetests --with-doctest --with-doctest-ignore-unicode --with-coverage \
--cover-package=isso --cover-html isso/ specs/
# INSTALLATION: pip install sphinx && npm install --global node-sass
ISSO_JS_SRC := $(shell find isso/js/app -type f) \
$(shell ls isso/js/*.js | grep -vE "(min|dev)") \
isso/js/lib/requirejs-jade/jade.js
ISSO_JS_DST := isso/js/embed.min.js isso/js/embed.dev.js \
isso/js/count.min.js isso/js/count.dev.js
ISSO_CSS := isso/css/isso.css
ISSO_PY_SRC := $(shell git ls-files | grep -E "^isso/.+.py$$")
DOCS_RST_SRC := $(shell find docs/ -type f -name '*.rst') \
$(wildcard docs/_isso/*) \
docs/index.html docs/conf.py docs/docutils.conf \
share/isso.conf
DOCS_CSS_SRC := docs/_static/css/site.scss
DOCS_CSS_DEP := $(shell find docs/_static/css/neat -type f) \
$(shell find docs/_static/css/bourbon -type f)
DOCS_CSS_DST := docs/_static/css/site.css
DOCS_MAN_DST := man/man1/isso.1 man/man5/isso.conf.5
DOCS_HTML_DST := docs/_build/html
RJS = r.js
SASS = node-sass
all: man js site
init:
(cd isso/js; bower --allow-root install almond requirejs requirejs-text jade)
flakes:
flake8 . --count --max-line-length=127 --show-source --statistics
isso/js/%.min.js: $(ISSO_JS_SRC) $(ISSO_CSS)
$(RJS) -o isso/js/build.$*.js out=$@
isso/js/%.dev.js: $(ISSO_JS_SRC) $(ISSO_CSS)
$(RJS) -o isso/js/build.$*.js optimize="none" out=$@
js: $(ISSO_JS_DST)
man: $(DOCS_RST_SRC)
sphinx-build -b man docs/ man/
mkdir -p man/man1/ man/man5
mv man/isso.1 man/man1/isso.1
mv man/isso.conf.5 man/man5/isso.conf.5
${DOCS_CSS_DST}: $(DOCS_CSS_SRC) $(DOCS_CSS_DEP)
$(SASS) --no-cache $(DOCS_CSS_SRC) $@
${DOCS_HTML_DST}: $(DOCS_RST_SRC) $(DOCS_CSS_DST)
sphinx-build -b dirhtml docs/ $@
site: $(DOCS_HTML_DST)
coverage: $(ISSO_PY_SRC)
nosetests --with-doctest --with-coverage --cover-package=isso --cover-html isso/
test: $($ISSO_PY_SRC)
python3 setup.py nosetests
clean:
rm -f $(DOCS_MAN_DST) $(DOCS_CSS_DST) $(ISSO_JS_DST)
rm -rf $(DOCS_HTML_DST)
.PHONY: clean site man init js coverage test

@ -1,39 +1,12 @@
Isso Ich schrei sonst
=======================
[![Build Status](https://drone.nixaid.com/api/badges/arno/isso/status.svg)](https://drone.nixaid.com/arno/isso)
[![Build Status](https://travis-ci.org/posativ/isso.png?branch=master)](https://travis-ci.org/posativ/isso)
Isso a commenting server similar to Disqus
============================================
You love static blog generators (especially [Acrylamid][1] *cough*) and the
only option to interact with your community is [Disqus][2]. There's nothing
wrong with it, but if you care about the privacy of your audience you are
better off with a comment system that is under your control. This is, where
Isso comes into play.
Isso *Ich schrei sonst* is a lightweight commenting server written in
Python and JavaScript. It aims to be a drop-in replacement for
[Disqus](http://disqus.com).
[1]: https://github.com/posativ/acrylamid
[2]: https://disqus.com/
![Isso in Action](http://posativ.org/~tmp/isso-sample.png)
**[Try Yourself!](http://posativ.org/isso/)**
Features
--------
* [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) comments written in Markdown
* SQLite backend, Disqus import
* client-side JS (currently 54kb minified, 18kb gzipped)
* I18N, available in english, french, russian and german
Setup
-----
Please refer to the official documentation: <http://posativ.org/isso/docs>.
Alternatives
------------
- [talkatv](https://github.com/talkatv/talkatv) Python
- [Juvia](https://github.com/phusion/juvia) Ruby on Rails
- [Tildehash.com](http://www.tildehash.com/?article=why-im-reinventing-disqus) PHP
- [SO: Unobtrusive, self-hosted comments](http://stackoverflow.com/q/2053217)
See [posativ.org/isso](http://posativ.org/isso/) for more details.

65
Vagrantfile vendored

@ -0,0 +1,65 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# This is the Vagrant config file for setting up an environment for Isso development.
# It requires:
#
# * Vagrant (https://vagrantup.com)
# * A VM engine, like VirtualBox (https://virtualbox.org)
# * The Vagrant-Hostmanager plugin (https://github.com/smdahlen/vagrant-hostmanager)
# * Ansible (https://www.ansible.com)
#
# With them installed, cd into this directory and do 'vagrant up'. It's possible Vagrant will
# ask for your root password so it can update your /etc/hosts file. Once it's happily churning out
# console output, go get a coffee :)
#
# The resulting VM should be accessible at http://isso-dev.local/ so you can try the demo page out.
# Edit files in your checkout as usual. If you need to look at log files and stuff, 'vagrant ssh'
# to get into the VM. Useful info about it:
#
# * Running Ubuntu 14.04
# * Isso is running on uWSGI
# * Actual webserver is Nginx to talk to uWSGI over a unix socket
# * uWSGI log file is /var/log/uwsgi/apps/isso.log
# * Isso DB file is /var/isso/comments.db
# * Isso log file is /var/log/isso.log
#
# When the VM is getting rebooted vagrant mounts the shared folder after uWSGI is getting startet. To fix this issue for
# the moment you need to 'vagrant ssh' into the VM and execute 'sudo service uwsgi restart'.
#
# For debugging with _pudb_ stop uWSGI service and start it manually
# 'sudo uwsgi --ini /etc/uwsgi/apps-available/isso.ini'.
#
# Enjoy!
Vagrant.configure(2) do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
config.vm.box = "ubuntu/trusty32"
config.vm.hostname = 'isso-dev.local'
config.vm.network "private_network", type: "dhcp"
config.hostmanager.enabled = true
config.hostmanager.manage_host = true
config.hostmanager.ignore_private_ip = false
config.hostmanager.include_offline = true
config.hostmanager.ip_resolver = proc do |machine|
result = ""
machine.communicate.execute("ifconfig eth1") do |type, data|
result << data if type == :stdout
end
(ip = /inet addr:(\d+\.\d+\.\d+\.\d)/.match(result)) && ip[1]
end
config.vm.provision "ansible" do |ansible|
ansible.playbook = "ansible/site.yml"
ansible.limit = "all"
ansible.verbose = "v"
end
config.vm.post_up_message = "Browse to http://isso-dev.local/demo/index.html to start."
end

@ -0,0 +1,39 @@
user root;
worker_processes 4;
worker_rlimit_nofile 8192;
error_log /var/log/nginx/error.log warn;
pid /run/nginx.pid;
events {
worker_connections 2014;
multi_accept on;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
log_format timed '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$request_time $upstream_response_time $upstream_addr '
' $upstream_status $upstream_cache_status $pipe';
access_log /var/log/nginx/access.log timed;
sendfile on;
tcp_nopush on;
keepalive_timeout 30;
gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}

@ -0,0 +1,13 @@
server {
client_max_body_size 20M;
listen 80 default_server;
server_name isso-dev.local;
root /vagrant/isso/demo;
location / {
# uwsgi_pass unix:///run/uwsgi/app/isso/socket;
uwsgi_pass 127.0.0.1:8080;
include uwsgi_params;
}
}

@ -0,0 +1,24 @@
[uwsgi]
plugins = python
chdir = /vagrant
uid = root
gid = root
socket = :8080
master = true
processes = 4
cache2 = name=hash,items=10240,blocksize=32
spooler = /var/isso/spool
module = isso.run
env = ISSO_SETTINGS=/vagrant/share/isso-dev.conf
env = PYTHON_EGG_CACHE=/tmp
# uncomment for debugging
# daemonize = /var/log/uwsgi/uwsgi.log
py-autoreload = 1
# prevent uWSGI from remapping stdin to /dev/null
honour-stdin = true

@ -0,0 +1,85 @@
---
- name: Provision development server
hosts: all
sudo: true
tasks:
- name: Apt | Add nodesource keys
apt_key: url=https://deb.nodesource.com/gpgkey/nodesource.gpg.key state=present
- name: Apt | Add nodesource sources list deb
apt_repository: repo='deb https://deb.nodesource.com/node {{ ansible_distribution_release }} main' state=present
- name: Apt | Add nodesource sources list deb src
apt_repository: repo='deb-src https://deb.nodesource.com/node {{ ansible_distribution_release }} main' state=present
- name: Apt | Install packages
apt: pkg={{ item }} state=latest update_cache=true
with_items:
- build-essential
- curl
- htop
- vim
- git
- python-dev
- python-software-properties
- python-setuptools
- python-pip
- nginx
- uwsgi
- uwsgi-plugin-python
- supervisor
- sqlite3
- nodejs
- libffi-dev
- name: NPM | Install packages
npm: name={{ item }} global=yes
with_items:
- bower
- requirejs
- uglify-js
- jade
- name: Python | Install egg
shell: cd /vagrant; python setup.py develop
- name: Make
shell: cd /vagrant; {{ item }}
with_items:
- make init
- make js
- name: Spool | Create directory
file: path=/var/isso/spool state=directory mode=0777
- name: uwsgi | Deploy configuration
copy: src=files/uwsgi.ini dest=/etc/uwsgi/apps-available/isso.ini
- name: uwsgi | Enable app
file: src=/etc/uwsgi/apps-available/isso.ini dest=/etc/uwsgi/apps-enabled/isso.ini state=link
- name: uwsgi | Restart service daemon
service: name=uwsgi state=restarted enabled=yes
- name: uwsgi | Chmod logfile
file: path=/var/log/uwsgi/uwsgi.log state=touch mode="a+r"
- name: nginx | Deploy nginx.conf
copy: src=files/nginx.conf dest=/etc/nginx/nginx.conf
- name: nginx | Delete default vhost
action: file path=/etc/nginx/sites-enabled/default state=absent
- name: nginx | Deploy vhost config
copy: src=files/nginx.vhost.conf dest=/etc/nginx/sites-available/isso.conf
- name: nginx | Enable vhost
file: src=/etc/nginx/sites-available/isso.conf dest=/etc/nginx/sites-enabled/000-isso state=link
- name: nginx | Chmod logfile
file: path=/var/log/nginx mode="a+rx" state=directory recurse=true
- name: nginx | Restart service daemon
service: name=nginx state=restarted enabled=yes

@ -0,0 +1,11 @@
{
"name": "isso",
"description": "a Disqus alternative",
"title": "isso API",
"order": ["Thread", "Comment"],
"template": {
"withCompare": false
}
}

@ -0,0 +1,13 @@
#!/usr/bin/env fish
set -g TRANSIFEX ".tx/js/"
set -g JS "isso/js/app/i18n/%s.js"
# fetch latest translations to .tx/<ressource>/<lang>
tx pull -a
for lang in (ls $TRANSIFEX)
printf "define(" > (printf $JS $lang)
cat .tx/js/$lang >> (printf $JS $lang)
printf ");\n" >> (printf $JS $lang)
end

@ -0,0 +1,34 @@
#!/usr/bin/env fish
set TRANSIFEX "https://www.transifex.com/api/2"
if [ (count $argv) -ne 1 ]
echo "tx-push FILE"
exit 2
end
if [ ! -f ~/.transifexrc ]
echo "no ~/.transifexrc found"
exit 1
end
set user (cat ~/.transifexrc | grep -E "^username" | awk -F " ?= ?" '{ print $2 }')
set pass (cat ~/.transifexrc | grep -E "^password" | awk -F " ?= ?" '{ print $2 }')
set lang (echo $argv | cut -d / -f 5 | cut -d . -f 1)
set trans (mktemp -t tx.XXX)
if [ $lang = "en" ]
set url "$TRANSIFEX/project/isso/resource/js/content/"
else
set url "$TRANSIFEX/project/isso/resource/js/translation/$lang/"
end
printf '{"content":' > $trans
cat $argv \
| sed "s,^define(,,g;\$ s,);,,g" \
| python -c 'import json,sys; print json.dumps(sys.stdin.read())' \
>> $trans
printf '}' >> $trans
curl -L -u $user:$pass -XPUT $url -H "Content-Type: application/json" -d @$trans

@ -0,0 +1,128 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
#
# The MIT License (MIT)
#
# Copyright (c) 2020 Lucas Cimon.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""Dump isso comments as text
The script can be run like this:
contrib/dump_comments.py .../path/to/isso.db --sort-by-last-reply
To get a list of all available options:
contrib/dump_comments.py --help
By installing the optional colorama dependency, you'll get a colored output.
An example of output can be found at https://github.com/posativ/isso/issues/634
"""
import argparse
import sqlite3
from collections import defaultdict, namedtuple
from datetime import date
from textwrap import indent
class ColorFallback():
__getattr__ = lambda self, name: '' # noqa: E731
try:
from colorama import Fore, Style, init
init() # needed for Windows
except ImportError: # fallback so that the imported classes always exist
Fore = Style = ColorFallback()
Comment = namedtuple('Comment', ('uri', 'id', 'parent', 'created', 'text', 'author', 'email', 'website', 'likes', 'dislikes', 'replies'))
INDENT = ' '
QUERY = 'SELECT uri, comments.id, parent, created, text, author, email, website, likes, dislikes FROM comments INNER JOIN threads on comments.tid = threads.id'
def main():
args = parse_args()
if not args.colors:
global Fore, Style
Fore = Style = ColorFallback()
db = sqlite3.connect(args.db_path)
comments_per_uri = defaultdict(list)
for result in db.execute(QUERY).fetchall():
comment = Comment(*result, replies=[])
comments_per_uri[comment.uri].append(comment)
root_comments_per_sort_date = {}
for comments in comments_per_uri.values():
comments_per_id = {comment.id: comment for comment in comments}
root_comments, sort_date = [], None
for comment in comments:
if comment.parent: # == this is a "reply" comment
comments_per_id[comment.parent].replies.append(comment)
if args.sort_by_last_reply and (sort_date is None or comment.created > sort_date):
sort_date = comment.created
else:
root_comments.append(comment)
if sort_date is None or comment.created > sort_date:
sort_date = comment.created
root_comments_per_sort_date[sort_date] = root_comments
for _, root_comments in sorted(root_comments_per_sort_date.items(), key=lambda pair: pair[0]):
print(Fore.MAGENTA + args.url_prefix + root_comments[0].uri + Fore.RESET)
for comment in root_comments:
print_comment(INDENT, comment)
for comment in comment.replies:
print_comment(INDENT * 2, comment)
print()
def print_comment(prefix, comment):
author = comment.author or 'Anonymous'
email = comment.email or ''
website = comment.website or ''
when = date.fromtimestamp(comment.created)
popularity = ''
if comment.likes:
popularity = '+{.likes}'.format(comment)
if comment.dislikes:
if popularity:
popularity += '/'
popularity = '-{.dislikes}'.format(comment)
print(prefix + '{Style.BRIGHT}{author}{Style.RESET_ALL} {Style.DIM}- {email} {website}{Style.RESET_ALL} {when} {Style.DIM}{popularity}{Style.RESET_ALL}'.format(Style=Style, **locals()))
print(indent(comment.text, prefix))
def parse_args():
parser = argparse.ArgumentParser(description='Dump all Isso comments in chronological order, grouped by replies',
formatter_class=ArgparseHelpFormatter)
parser.add_argument('db_path', help='File path to Isso Sqlite DB')
parser.add_argument('--sort-by-last-reply', action='store_true', help='By default comments are sorted by "parent" comment date, this sort comments based on the last replies')
parser.add_argument('--url-prefix', default='', help='Optional domain name to prefix to pages URLs')
parser.add_argument('--no-colors', action='store_false', dest='colors', default=True, help='Disabled colored output')
return parser.parse_args()
class ArgparseHelpFormatter(argparse.RawTextHelpFormatter, argparse.ArgumentDefaultsHelpFormatter):
pass
if __name__ == '__main__':
main()

@ -0,0 +1,123 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""Comment importer from Blogger
This python script can convert comments posted to a Blogger-powered blog to a
JSON file with can then be imported into Isso (by following the procedure
explained in docs/docs/extras/advanced-migration.rst.
The script can be run like this:
python import_blogger.py -p 'http://myblog.com/' blogger.xml out.json
where `blogger.xml` is a dump of the blog produced by the Blogger platform, and
the URL following the `-p` option is a prefix that will be applied to all post
URLs: the original host will be stripped and the path will be appended to the
string you specify here (this can be useful in the case that your blog moved to
a different domain, subdomain, or just into a new directory).
The `out.json` file is the file which will be generated by this tool, and which
can then be fed into isso:
isso -c /path/to/isso.cfg import -t generic out.json
"""
from __future__ import unicode_literals
import json
import feedparser
import time
from urllib.parse import urlparse
class Post:
def __init__(self, url):
self.url = url
self.title = None
self.comments = []
def add_comment(self, comment):
comment['id'] = len(self.comments) + 1
self.comments.append(comment)
def encode_post(post):
ret = {}
ret['id'] = post.url
ret['title'] = post.title
ret['comments'] = post.comments
return ret
class ImportBlogger:
TYPE_COMMENT = 'http://schemas.google.com/blogger/2008/kind#comment'
TYPE_POST = 'http://schemas.google.com/blogger/2008/kind#post'
def __init__(self, filename_in, filename_out, prefix):
self.channel = feedparser.parse(filename_in)
self.filename_out = filename_out
self.prefix = prefix
def run(self):
self.posts = {}
for item in self.channel.entries:
terms = [tag.term for tag in item.tags]
if not terms:
continue
if terms[0] == self.TYPE_COMMENT:
post = self.ensure_post(item)
post.add_comment(self.process_comment(item))
elif terms[0] == self.TYPE_POST:
self.process_post(item)
data = [encode_post(p) for p in self.posts.values() if p.comments]
with open(self.filename_out, 'w') as fp:
json.dump(data, fp, indent=2)
def process_post(self, item):
pid = self.post_id(item)
if pid in self.posts:
post = self.posts[pid]
else:
post = Post(pid)
self.posts[pid] = post
post.title = item.title
def ensure_post(self, item):
pid = self.post_id(item)
post = self.posts.get(pid, None)
if not post:
post = Post(pid)
self.posts[pid] = post
return post
def process_comment(self, item):
comment = {}
comment['author'] = item.author_detail.name
comment['email'] = item.author_detail.email
comment['website'] = item.author_detail.get('href', '')
t = time.strftime('%Y-%m-%d %H:%M:%S', item.published_parsed)
comment['created'] = t
comment['text'] = item.content[0].value
comment['remote_addr'] = '127.0.0.1'
return comment
def post_id(self, item):
u = urlparse(item.link)
return self.prefix + u.path
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(
description='Convert comments from blogger.com')
parser.add_argument('input', help='input file')
parser.add_argument('output', help='output file')
parser.add_argument('-p', dest='prefix',
help='prefix to be added to paths (ID)',
type=str, default='')
args = parser.parse_args()
importer = ImportBlogger(args.input, args.output, args.prefix)
importer.run()

@ -1,60 +0,0 @@
Development
===========
If you want to hack on Isso or track down issues, there's an alternate
way to set up Isso. It requires a lot more dependencies and effort.
Requirements:
- Python 2.6, 2.7 or 3.3
- Ruby 1.8 or higher
- Node.js, [NPM](https://npmjs.org/) and [Bower](http://bower.io/)
On Debian/Ubuntu install the following packages
~> sudo aptitude install python-setuptools python-dev npm ruby
~> ln -s /usr/bin/nodejs /usr/bin/node
Get the repository:
~> git clone https://github.com/posativ/isso.git
~> cd isso/
Install `virtualenv` and create a new environment for Isso (recommended):
~> pip install virtualenv
~> virtualenv .
~> source ./bin/activate
Install Isso dependencies:
~> python setup.py develop
~> isso run
Compile SCSS to CSS:
~> gem install sass
~> scss --watch isso/css/isso.scss
Install JS components:
~> cd isso/js
~> bower install almond q requirejs requirejs-domready requirejs-text
Integration
-----------
```html
<script src="/isso/js/config.js"></script>
<script data-main="/isso/js/embed" src="/isso/js/components/requirejs/require.js"></script>
```
Optimization
------------
~> npm install -g requirejs uglifyjs
~> cd isso/js
~> r.js -o build.embed.js
~> r.js -o build.count.js

File diff suppressed because it is too large Load Diff

@ -10,7 +10,8 @@
VERSION: '{{ release|e }}',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
HAS_SOURCE: {{ has_source|lower }}
HAS_SOURCE: {{ has_source|lower }},
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
};
</script>
{%- for scriptfile in script_files %}

@ -0,0 +1,11 @@
from docutils import nodes
from sphinx.writers.html import HTMLTranslator
class IssoTranslator(HTMLTranslator):
def visit_title(self, node):
if self.section_level == 1:
raise nodes.SkipNode
HTMLTranslator.visit_title(self, node)

@ -13,14 +13,20 @@
{{ doc("docs/quickstart", "Quickstart") }}
{{ doc("docs/troubleshooting", "Troubleshooting") }}
</ul>
<strong>Advanced Setup</strong>
<ul>
{{ doc("docs/setup/sub-uri", "Sub URI") }}
{{ doc("docs/setup/multiple-sites", "Multiple Sites") }}
</ul>
<strong>Configuration</strong>
<ul>
{{ doc("docs/configuration/setup", "Setup") }}
{{ doc("docs/configuration/server", "Server") }}
{{ doc("docs/configuration/client", "Client") }}
</ul>
<strong>Advanced</strong>
<strong>Extras</strong>
<ul>
{{ doc("docs/extras/uwsgi", "uWSGI") }}
{{ doc("docs/extras/deployment", "Deployment") }}
{{ doc("docs/extras/advanced-integration", "Advanced Integration") }}
{{ doc("docs/extras/api", "API") }}
{{ doc("docs/extras/contribs", "Community tools") }}
</ul>

@ -180,6 +180,14 @@ main {
margin-top: 0;
}
p + p {
margin-top: 1em;
}
p + p:last-child {
margin-top: 0;
}
li {
list-style-type: none;
}
@ -201,6 +209,21 @@ main {
h4 {
margin-bottom: 0.5em;
}
blockquote {
margin-top: 10px;
margin-bottom: 10px;
padding-left: 15px;
border-left: 3px solid #ccc;
}
pre {
background: #eee;
border: 1px solid #ddd;
padding: 10px 15px;
color: #4d4d4c;
overflow: auto;
}
}
.sidebar {
@ -275,7 +298,7 @@ main {
pre, code {
color: rgb(77, 77, 76);
font-size: 12px;
font-family: Monaco, Menlo, Consolas, monospaced;
font-family: Monaco, Menlo, Consolas, monospace;
}
.highlight {
@ -290,6 +313,10 @@ main {
overflow: auto;
}
.headerlink {
visibility: hidden;
}
p + p {
margin-top: 1em;
}
@ -337,4 +364,20 @@ main {
dd {
margin-left: 1.2em;
}
dl {
margin-bottom: 0.4em;
}
.admonition {
p + p {
margin-top: 0.25em;
}
p:not(:first-child) {
margin-left: 2em;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

@ -13,11 +13,26 @@
# serve to show the default.
import sys
import os
import io
import re
import pkg_resources
from os.path import join, dirname
sys.path.insert(0, join(dirname(__file__), "_isso/"))
try:
dist = pkg_resources.get_distribution("isso")
except pkg_resources.DistributionNotFound:
dist = type("I'm a Version", (object, ), {})
with io.open(join(dirname(__file__), "../setup.py")) as fp:
for line in fp:
m = re.match("\\s*version='([^']+)'\\s*", line)
if m:
dist.version = m.group(1)
break
else:
dist.version = ""
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
@ -49,16 +64,19 @@ master_doc = 'docs/index'
# General information about the project.
project = u'Isso'
copyright = u'2013, Martin Zimmermann'
copyright = u'2016, Martin Zimmermann'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
from distutils.version import LooseVersion
#
# The short X.Y version.
version = '0.5'
# The full version, including alpha/beta/rc tags.
release = '0.5.1'
release = dist.version
# The short X.Y version.
version = "{0}.{1}".format(*LooseVersion(dist.version).version)
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
@ -104,7 +122,7 @@ pygments_style = 'trac'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = '_isso'
html_translator_class = "html5.Isso"
html_translator_class = "remove_heading.IssoTranslator"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@ -182,22 +200,22 @@ htmlhelp_basename = 'Issodoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'Isso.tex', u'Isso Documentation',
u'Martin Zimmermann', 'manual'),
('index', 'Isso.tex', u'Isso Documentation',
u'Martin Zimmermann', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@ -226,8 +244,10 @@ latex_documents = [
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'isso', u'Isso Documentation',
[u'Martin Zimmermann'], 1)
('docs/man/index', 'isso', u'a Disqus alternative',
[u'Martin Zimmermann'], 1),
('docs/configuration/server', 'isso.conf', u'server configuration',
[u'Martin Zimmermann'], 5)
]
# If true, show URL addresses after external links.
@ -240,9 +260,9 @@ man_pages = [
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'Isso', u'Isso Documentation',
u'Martin Zimmermann', 'Isso', 'a commenting server similar to Disqus',
'Miscellaneous'),
('index', 'Isso', u'Isso Documentation',
u'Martin Zimmermann', 'Isso', 'a commenting server similar to Disqus',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.

@ -30,6 +30,20 @@ Report issues
- **Isso-related issues** Copy and paste traceback into a ticket and provide
some details of your usage.
Translations
------------
Isso supports multiple languages and it is fairly easy to add new translations.
You can either use the `english translation file`__ or use Transifex_. Contact
me on IRC (@posativ) if you want to be the main contributor for a language.
You may notice some "weird" newlines in translations -- that's the separator
for pluralforms_ in the templating engine.
.. __: https://github.com/posativ/isso/blob/master/isso/js/app/i18n/en.js
.. _Transifex: https://www.transifex.com/projects/p/isso/
.. _pluralforms: http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html?id=l10n/pluralforms
Where I need help.
------------------
@ -45,14 +59,3 @@ definitely need help:
- delete or activate comments matching a filter (e.g. name, email, ip address)
- close threads and remove threads completely
- edit comments
* `Pagination <https://github.com/posativ/isso/issues/14>`_ while Isso is
generally a lot faster than Disqus, after approx. 50 comments you will
notice roughly 1 second rendering time. It would be nice if the client
fetches only N comments and continues when the user scrolls down (or click
on a button to fetch more).
* CSS improvements. For some websites, the Isso integration just looks ugly.
If you can improve it, please do it :)

@ -7,17 +7,39 @@ preferably in the script tag which embeds the JS:
.. code-block:: html
<script data-isso="/prefix/"
data-isso-id="thread-id"
data-isso-css="true"
data-isso-lang="ru"
data-isso-reply-toself="false"
data-isso-reply-to-self="false"
data-isso-require-author="false"
data-isso-require-email="false"
data-isso-reply-notifications="false"
data-isso-max-comments-top="10"
data-isso-max-comments-nested="5"
data-isso-reveal-on-click="5"
data-isso-avatar="true"
data-isso-avatar-bg="#f0f0f0"
data-isso-avatar-fg="#9abf88 #5698c4 #e279a3 #9163b6 ..."
data-isso-vote="true"
data-isso-vote-levels=""
data-isso-feed="false"
src="/prefix/js/embed.js"></script>
Furthermore you can override the automatic title detection inside
the embed tag, e.g.:
the embed tag, as well as the thread ID, e.g.:
.. code-block:: html
<section id="isso-thread" data-title="Foo!"></section>
<section id="isso-thread" data-title="Foo!" data-isso-id="/path/to/resource"></section>
Additionally, you can override any translation string for any language by adding
a ``data-isso-`` attribute that is equal to the translation key (found `here`__) with
``-text-[lang]`` appended to it. So, for example, if you want to override the
english translation of the ``postbox-notification`` message, you could add:
``data-isso-postbox-notification-text-en="Select to be notified of replies to your comment"``
.. __: https://github.com/posativ/isso/blob/master/isso/js/app/i18n/en.js
data-isso
---------
@ -43,20 +65,94 @@ Defaults to `true`.
data-isso-lang
--------------
Override useragent's preferred language. Currently available: german (de),
english (en) and french (fr).
Override useragent's preferred language. Isso has been translated in over 12
languages. The language is configured by its `ISO 639-1
<https://en.wikipedia.org/wiki/ISO_639-1>`_ (two letter) code.
You find a list of all supported languages on `GitHub
<https://github.com/posativ/isso/tree/master/isso/js/app/i18n>`_.
data-isso-reply-to-self
-----------------------
Set to `true` when spam guard is configured with `reply-to-self = true`.
data-isso-id
------------
data-isso-require-author
------------------------
Set a custom thread id, defaults to current URI. If you a comment counter, add
this attribute to the link tag, too.
Set to `true` when spam guard is configured with `require-author = true`.
.. code-block:: html
data-isso-require-email
-----------------------
Set to `true` when spam guard is configured with `require-email = true`.
data-isso-reply-notifications
-----------------------------
Set to `true` when reply notifications is configured with `reply-notifications = true`.
data-isso-max-comments-top and data-isso-max-comments-nested
------------------------------------------------------------
Number of top level (or nested) comments to show by default. If some
comments are not shown, an "X Hidden" link is shown.
Set to `"inf"` to show all, or `"0"` to hide all.
data-isso-reveal-on-click
-------------------------
Number of comments to reveal on clicking the "X Hidden" link.
data-isso-avatar
----------------
Enable or disable avatar generation.
data-isso-avatar-bg
-------------------
Set avatar background color. Any valid CSS color will do.
data-isso-avatar-fg
-------------------
Set avatar foreground color. Up to 8 colors are possible. The default color
scheme is based in `this color palette <http://colrd.com/palette/19308/>`_.
Multiple colors must be separated by space. If you use less than eight colors
and not a multiple of 2, the color distribution is not even.
data-isso-gravatar
------------------
Uses gravatar images instead of generating svg images. You have to set
"data-isso-avatar" to **false** when you want to use this. Otherwise
both the gravatar and avatar svg image will show up. Please also set
option "gravatar" to **true** in the server configuration...
data-isso-vote
--------------
Enable or disable voting feature on the client side.
data-isso-vote-levels
---------------------
List of vote levels used to customize comment appearance based on score.
Provide a comma-separated values (eg. `"0,5,10,25,100"`) or a JSON array (eg. `"[-5,5,15]"`).
For example, the value `"-5,5"` will cause each `isso-comment` to be given one of these 3 classes:
- `isso-vote-level-0` for scores lower than `-5`
- `isso-vote-level-1` for scores between `-5` and `4`
- `isso-vote-level-2` for scores of `5` and greater
These classes can then be used to customize the appearance of comments (eg. put a star on popular comments)
data-isso-feed
--------------
<section data-isso-id="test.abc" id="isso-thread"></section>
Enable or disable the addition of a link to the feed for the comment
thread. The link will only be valid if the appropriate setting, in
``[rss]`` section, is also enabled server-side.

@ -2,7 +2,9 @@ Server Configuration
====================
The Isso configuration file is an `INI-style`__ textfile. It reads integers,
booleans and strings. Below is a basic example:
booleans, strings and lists. Here's the default isso configuration:
`isso.conf <https://github.com/posativ/isso/blob/master/share/isso.conf>`. A
basic configuration from scratch looks like this:
.. code-block:: ini
@ -10,7 +12,7 @@ booleans and strings. Below is a basic example:
dbpath = /var/lib/isso/comments.db
host = https://example.tld/
[server]
port = 1234
listen = http://localhost:1234/
To use your configuration file with Isso, append ``-c /path/to/cfg`` to the
executable or run Isso with an environment variable:
@ -39,10 +41,10 @@ session key and hostname. Here are the default values for this section:
[general]
dbpath = /tmp/isso.db
name =
host = http://localhost:8080/
host =
max-age = 15m
session-key = ... ; python: binascii.b2a_hex(os.urandom(24))
notify =
notify = stdout
log-file =
dbpath
file location to the SQLite3 database, highly recommended to change this
@ -53,34 +55,68 @@ name
not used otherwise.
host
URL to your website. When you start Isso, it will probe your website with
a simple ``GET /`` request to see if it can reach the webserver. If this
fails, Isso may not be able check if a web page exists, thus fails to
accept new comments.
Your website(s). If Isso is unable to connect to at least one site, you'll
get a warning during startup and comments are most likely non-functional.
You can supply more than one host:
You'll need at least one host/website to run Isso. This is due to security
reasons: Isso uses CORS_ to embed comments and to restrict comments only to
your website, you have to "whitelist" your website(s).
I recommend the first value to be a non-SSL website that is used as fallback
if Firefox users (and only those) supress their HTTP referer completely.
.. code-block:: ini
[general]
host =
http://localhost/
https://localhost/
This is useful, when your website is available on HTTP and HTTPS.
session-key
private session key to validate client cookies. If you restart the
application several times per hour for whatever reason, use a fixed
key.
http://example.tld/
https://example.tld/
max-age
time range that allows users to edit/remove their own comments. See
:ref:`Appendum: Timedelta <appendum-timedelta>` for valid values.
notify
Select notification backend for new comments. Currently, only SMTP
is available.
Select notification backend(s) for new comments, separated by comma.
Available backends:
stdout
Log to standard output. Default, if none selected. Note, this
functionality is broken since a few releases.
smtp
Send notifications via SMTP on new comments with activation (if
moderated) and deletion links.
reply-notifications
Allow users to request E-mail notifications for replies to their post.
It is highly recommended to also turn on moderation when enabling this
setting, as Isso can otherwise be easily exploited for sending spam.
Do not forget to configure the client accordingly.
log-file
Log console messages to file instead of standard out.
gravatar
When set to ``true`` this will add the property "gravatar_image"
containing the link to a gravatar image to every comment. If a comment
does not contain an email address, gravatar will render a random icon.
This is only true when using the default value for "gravatar-url"
which contains the query string param ``d=identicon`` ...
gravatar-url
Url for gravatar images. The "{}" is where the email hash will be placed.
Defaults to "https://www.gravatar.com/avatar/{}?d=identicon"
latest-enabled
If True it will enable the ``/latest`` endpoint. Optional, defaults
to False.
.. _CORS: https://developer.mozilla.org/en/docs/HTTP/Access_control_CORS
Moderation
@ -92,13 +128,21 @@ Enable moderation queue and handling of comments still in moderation queue
[moderation]
enabled = false
approve-if-email-previously-approved = false
purge-after = 30d
enabled
enable comment moderation queue. This option only affects new comments.
Comments in modertion queue are not visible to other users until you
Comments in moderation queue are not visible to other users until you
activate them.
approve-if-email-previously-approved
automatically approve comments by an email address if that address has
had a comment approved within the last 6 months. No ownership verification
is done on the entered email address. This means that if someone is able
to guess correctly the email address used by a previously approved author,
they will be able to have their new comment auto-approved.
purge-after
remove unprocessed comments in moderation queue after given time.
@ -123,7 +167,7 @@ listen
; UNIX domain socket
listen = unix:///tmp/isso.sock
; TCP/IP
listen = http:///localhost:1234/
listen = http://localhost:1234/
When ``gevent`` is available, it is automatically used for `http://`
Currently, gevent can not handle http requests on unix domain socket
@ -132,15 +176,27 @@ listen
Does not apply for `uWSGI`.
public-endpoint
public URL that Isso is accessed from by end users. Should always be
a http:// or https:// absolute address. If left blank, automatic
detection is attempted. Normally only needs to be specified if
different than the `listen` setting.
reload
reload application, when the source code has changed. Useful for
development (don't forget to use a fixed `session-key`). Only works
when ``gevent`` and ``uwsgi`` are *not* available.
development. Only works with the internal webserver.
profile
show 10 most time consuming function in Isso after each request. Do
not use in production.
trusted-proxies
an optional list of reverse proxies IPs behind which you have deployed
your Isso web service (e.g. `127.0.0.1`).
This allow for proper remote address resolution based on a
`X-Forwarded-For` HTTP header, which is important for the mechanism
forbiding several comment votes coming from the same subnet.
.. _configure-smtp:
SMTP
@ -156,10 +212,11 @@ also can moderate (=activate or delete) comments. Don't forget to configure
username =
password =
host = localhost
port = 465
ssl = on
port = 587
security = starttls
to =
from =
timeout = 10
username
self-explanatory, optional
@ -174,16 +231,22 @@ host
port
SMTP port
ssl
use SSL to connect to the server. Python probably does not validate the
certificate. Needs research, though. But you should use a dedicated
email account anyways.
security
use a secure connection to the server, possible values: *none*, *starttls*
or *ssl*. Note, that there is no easy way for Python 2.7 and 3.3 to
implement certification validation and thus the connection is vulnerable to
Man-in-the-Middle attacks. You should definitely use a dedicated SMTP
account for Isso in that case.
to
recipient address, e.g. your email address
from
sender address, e.g. isso@example.tld
sender address, e.g. `"Foo Bar" <isso@example.tld>`
timeout
specify a timeout in seconds for blocking operations like the
connection attempt.
Guard
@ -199,6 +262,8 @@ for IPv4, ``/48`` for IPv6).
ratelimit = 2
direct-reply = 3
reply-to-self = false
require-author = false
require-email = false
enabled
enable guard, recommended in production. Not useful for debugging
@ -216,8 +281,124 @@ reply-to-self
the comment. After the editing timeframe is gone, commenters can reply to
their own comments anyways.
Do not forget to configure the client.
Do not forget to configure the `client <client>`_ accordingly
require-author
force commenters to enter a value into the author field. No validation is
performed on the provided value.
Do not forget to configure the `client <client>`_ accordingly.
require-email
force commenters to enter a value into the email field. No validation is
performed on the provided value.
Do not forget to configure the `client <client>`_ accordingly.
Markup
------
Customize markup and sanitized HTML. Currently, only Markdown (via Misaka) is
supported, but new languages are relatively easy to add.
.. code-block:: ini
[markup]
options = strikethrough, superscript, autolink
flags = skip-html, escape, hard-wrap
allowed-elements =
allowed-attributes =
options
`Misaka-specific Markdown extensions <https://misaka.61924.nl/#api>`_, all
extension flags can be used there, separated by comma, either by their name
or as `EXT_`_.
flags
`Misaka-specific HTML rendering flags
<https://misaka.61924.nl/#html-render-flags>`_, all html rendering flags
can be used here, separated by comma, either by their name or as `HTML_`_.
Per Misaka's defaults, no flags are set.
allowed-elements
Additional HTML tags to allow in the generated output, comma-separated. By
default, only *a*, *blockquote*, *br*, *code*, *del*, *em*, *h1*, *h2*,
*h3*, *h4*, *h5*, *h6*, *hr*, *ins*, *li*, *ol*, *p*, *pre*, *strong*,
*table*, *tbody*, *td*, *th*, *thead* and *ul* are allowed.
allowed-attributes
Additional HTML attributes (independent from elements) to allow in the
generated output, comma-separated. By default, only *align* and *href* are
allowed.
To allow images in comments, you just need to add ``allowed-elements = img`` and
``allowed-attributes = src``.
Hash
----
Customize used hash functions to hide the actual email addresses from
commenters but still be able to generate an identicon.
.. code-block:: ini
[hash]
salt = Eech7co8Ohloopo9Ol6baimi
algorithm = pbkdf2
salt
A salt is used to protect against rainbow tables. Isso does not make use of
pepper (yet). The default value has been in use since the release of Isso
and generates the same identicons for same addresses across installations.
algorithm
Hash algorithm to use -- either from Python's `hashlib` or PBKDF2 (a
computational expensive hash function).
The actual identifier for PBKDF2 is `pbkdf2:1000:6:sha1`, which means 1000
iterations, 6 bytes to generate and SHA1 as pseudo-random family used for
key strengthening.
Arguments have to be in that order, but can be reduced to `pbkdf2:4096`
for example to override the iterations only.
.. _configure-rss:
RSS
---
Isso can provide an Atom feed for each comment thread. Users can use
them to subscribe to comments and be notified of changes. Atom feeds
are enabled as soon as there is a base URL defined in this section.
.. code-block:: ini
[rss]
base =
limit = 100
base
base URL to use to build complete URI to pages (by appending the URI from Isso)
limit
number of most recent comments to return for a thread
Admin
-----
Isso has an optional web administration interface that can be used to moderate
comments. The interface is available under ``/admin`` on your isso URL.
.. code-block:: ini
[admin]
enabled = true
password = secret
enabled
whether to enable the admin interface
password
the plain text password to use for logging into the administration interface
Appendum
--------
@ -231,3 +412,18 @@ Timedelta
You can add different types: `1m30s` equals to 90 seconds, `3h45m12s`
equals to 3 hours, 45 minutes and 12 seconds (12512 seconds).
Environment variables
---------------------
.. _environment-variables:
Isso also support configuration through some environment variables:
ISSO_CORS_ORIGIN
By default, `isso` will use the `Host` or else the `Referrer` HTTP header
of the request to defines a CORS `Access-Control-Allow-Origin` HTTP header
in the response.
This environent variable allows you to define a broader fixed value,
in order for example to share a single Isso instance among serveral of your
subdomains : `ISSO_CORS_ORIGIN=*.example.test`

@ -0,0 +1,56 @@
Advanced integration
====================
Comment counter
---------------
If you want to display a comment counter for a given thread, simply
put a link to that comments thread anchor:
.. code-block:: html
<a href="/my-uri.html#isso-thread">Comments</a>
The *isso js client* willl replace the content of this tag with a human readable
counter like *"5 comments"*.
Alternatively, if guessing from `href` is not relevant, you could use a
`data-isso-id` attribute on the `<a>` to indicate which thread to count for.
Now, either include `count.min.js` if you want to show only the comment count
(e.g. on an index page) or `embed.min.js` for the full comment client (see
:doc:`../quickstart`); do not mix both.
You can have as many comments counters as you want in a page, and they will be
merged into a single `GET` request.
Asynchronous comments loading
-----------------------------
Isso will automatically fetch comments after `DOMContentLoaded` event. However
in the case where your website is creating content dynamically (eg. via ajax),
you need to re-fetch comment thread manually. Here is how you can re-fetch the
comment thread:
.. code-block:: js
window.Isso.fetchComments()
It will delete all comments under the thread but not the PostBox, fetch
comments with `data-isso-id` attribute of the element `section#isso-thread` (if
that attribute does not exist, fallback to `window.location.pathname`), then
fill comments into the thread. In other words, you should change `data-isso-id`
attribute of the element `section#isso-thread` (or modify the pathname with
`location.pushState`) before you can get new comments. And the thread element
itself should *NOT* be touched or removed.
If you removed the `section#isso-thread` element, just create another element
with same TagName and ID in which you wish comments to be placed, then call the
`init` method of `Isso`:
.. code-block:: js
window.Isso.init()
Then Isso will initialize the comment section and fetch comments, as if the page
was loaded.

@ -0,0 +1,70 @@
Advanced Migration
==================
In quickstart we saw you can import comments from Disqus or WordPress. But there
are a many other comments system and you could be using one of them.
Isso provides a way to import such comments, however it's up to you to to:
- dump comments
- fit the data to the following JSON format::
A list of threads, each item being a dict with the following data:
- id: a text representing the unique thread id (note: by default isso
associates this ID to the article URL, but it can be changed on
client side with "data-isso-id" - see :doc:`client configuration <../configuration/client>` )
- title: the title of the thread
- comments: the list of comments
Each item in that list of comments is a dict with the following data:
- id: an integer with the unique id of the comment inside the thread
(it can be repeated among different threads); this will be used to
order the comment inside the thread
- author: the author's name
- email: the author's email
- website: the author's website
- remote_addr: the author's IP
- created: a timestamp, in the format "%Y-%m-%d %H:%M:%S"
Example:
.. code-block:: json
[
{
"id": "/blog/article1",
"title": "First article!",
"comments": [
{
"author": "James",
"created": "2018-11-28 17:24:23",
"email": "email@mail.com",
"id": "1",
"remote_addr": "127.0.0.1",
"text": "Great article!",
"website": "http://fefzfzef.frzr"
},
{
"author": "Harold",
"created": "2018-11-28 17:58:03",
"email": "email2@mail.com",
"id": "2",
"remote_addr": "",
"text": "I hated it...",
"website": ""
}
]
}
]
Keep in mind that isso expects to have an array, so keep the opening and ending square bracket even if you have only one article thread!
Next you can import you json dump:
.. code-block:: sh
~> isso -c /path/to/isso.cfg import -t generic comment-dump.json
[100%] 53 threads, 192 comments

@ -23,12 +23,11 @@ Isso:
"mode": 1,
"hash": "4505c1eeda98",
"author": null,
"email": null,
"website": null
"website": null,
"created": 1387321261.572392,
"modified": null,
"likes": 3,
"dislikes": 0,
"dislikes": 0
}
id :
@ -71,7 +70,7 @@ modified :
List comments
-------------
List all publicely visible comments for thread `uri`:
List all publicly visible comments for thread `uri`:
.. code-block:: text
@ -84,6 +83,19 @@ plain :
pass plain=1 to get the raw comment text, defaults to 0.
Get the latest N comments for all threads:
.. code-block:: text
GET /latest?limit=N
The N parameter limits how many of the latest comments to retrieve; it's
mandatory, and must be an integer greater than 0.
This endpoint needs to be enabled in the configuration (see the
``latest-enabled`` option in the ``general`` section).
Create comment
--------------
@ -174,4 +186,28 @@ Up- and downvote comments
Get comment count
-----------------
...
Counts all publicly visible comments for thread `uri`:
.. code-block:: text
GET /count?uri=%2Fhello-world%2F
2
uri :
URI to count comments for, required.
returns an integer
Get Atom feed
-------------
Get an Atom feed of comments for thread `uri`:
.. code-block:: text
GET /feed?uri=%2Fhello-world%2F
uri :
URI to get comments for, required.
Returns an XML document as the Atom feed.

@ -0,0 +1,20 @@
Community tools
===============
Utility scripts
---------------
Some utility scripts have been developed by isso users.
They are stored in the `GitHub contrib/ directory
<https://github.com/posativ/isso/tree/master/contrib>`_ :
* `dump_comments.py` : dump isso comments as text, optionally with color
* `import_blogger.py` : comment importer from Blogger
Related projects
----------------
* `wonderfall/isso Docker image <https://github.com/Wonderfall/docker-isso>`
* `a grav plugin to integrate isso comments <https://github.com/Sommerregen/grav-plugin-jscomments>`
* `a Pelican theme supporting isso comments <https://github.com/Lucas-C/pelican-mg>`

@ -0,0 +1,273 @@
Deployment
----------
Isso ships with a built-in web server, which is useful for the initial setup
and may be used in production for low-traffic sites (up to 20 requests per
second). Running a "real" WSGI server supports nice things such as UNIX domain
sockets, daemonization and solid HTTP handler. WSGI servers are more stable, secure
and web-scale than the built-in web server.
* gevent_, coroutine-based network library
* uWSGI_, full-featured uWSGI server
* gunicorn_, Python WSGI HTTP Server for UNIX
* mod_wsgi_, Apache interface to WSGI
* mod_fastcgi_, Apache interface to FastCGI
* uberspace.de, `try this guide (in german) <http://blog.posativ.org/2014/isso-und-uberspace-de/>`_
* Openshift, Isso has a one click installer
`gevent <http://www.gevent.org/>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Probably the easiest deployment method. Install with PIP (requires libevent):
.. code-block:: sh
$ pip install gevent
Then, just use the ``isso`` executable as usual. Gevent monkey-patches Python's
standard library to work with greenlets.
To execute Isso, just use the commandline interface:
.. code-block:: sh
$ isso -c my.cfg run
Unfortunately, gevent 0.13.2 does not support UNIX domain sockets (see `#295
<https://github.com/surfly/gevent/issues/295>`_ and `#299
<https://github.com/surfly/gevent/issues/299>`_ for details).
`uWSGI <http://uwsgi-docs.readthedocs.org/en/latest/>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Isso has special support for uWSGI, namely fast IPC caching, job spooling and
delayed jobs. It is the author's choice, but not the only one. You need
uWSGI 1.9 or higher, fortunately you can install it from PyPi:
.. code-block:: sh
~> apt-get install build-essential python-dev
~> pip install uwsgi
For convenience, I recommend a INI-style configuration (you can also
supply everything as command-line arguments):
.. code-block:: ini
[uwsgi]
http = :8080
master = true
; set to `nproc`
processes = 4
cache2 = name=hash,items=1024,blocksize=32
; you may change this
spooler = /tmp/isso/mail
module = isso.run
; uncomment if you use a virtual environment
; virtualenv = /path/to/isso
env = ISSO_SETTINGS=/path/to/isso.cfg
Then, create the spooling directory and start Isso via uWSGI:
.. code-block:: sh
~> mkdir /tmp/isso/mail
~> uwsgi /path/to/uwsgi.ini
`gunicorn <http://gunicorn.org>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Gunicorn 'Green Unicorn' is a Python WSGI HTTP Server for UNIX with a pre-fork
worker ported from Ruby's Unicorn project. Install gunicorn_ via PIP:
.. code-block:: sh
$ pip install gunicorn
To execute Isso, use a command similar to:
.. code-block:: sh
$ export ISSO_SETTINGS="/path/to/isso.cfg"
$ gunicorn -b localhost:8080 -w 4 --preload isso.run
`mod_wsgi <https://code.google.com/p/modwsgi/>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
First, create a startup script, called `isso.wsgi`. If Isso is in your system module
search path, then the script is quite simple. This script is included in the
isso distribution as `run.py`:
.. code-block:: python
from __future__ import unicode_literals
import os
from isso import make_app
from isso import dist, config
application = make_app(
config.load(
os.path.join(dist.location, dist.project_name, "defaults.ini"),
"/path/to/isso.cfg"),
multiprocessing=True)
If you have installed Isso in a virtual environment, then you will have to add the path
of the virtualenv to the site-specific paths of Python:
.. code-block:: python
from __future__ import unicode_literals
import site
site.addsitedir("/path/to/isso_virtualenv")
import os
from isso import make_app
from isso import dist, config
application = make_app(
config.load(
os.path.join(dist.location, dist.project_name, "defaults.ini"),
"/path/to/isso.cfg",
multiprocessing=True)
Using the aforementioned script will load system modules when available and modules
from the virtualenv otherwise. Should you want the opposite behavior, where modules from
the virtualenv have priority over system modules, the following script does the trick:
.. code-block:: python
from __future__ import unicode_literals
import os
import site
import sys
# Remember original sys.path.
prev_sys_path = list(sys.path)
# Add the new site-packages directory.
site.addsitedir("/path/to/isso_virtualenv")
# Reorder sys.path so new directories at the front.
new_sys_path = []
for item in list(sys.path):
if item not in prev_sys_path:
new_sys_path.append(item)
sys.path.remove(item)
sys.path[:0] = new_sys_path
from isso import make_app
from isso import dist, config
application = make_app(
config.load(
os.path.join(dist.location, dist.project_name, "defaults.ini"),
"/path/to/isso.cfg",
multiprocessing=True)
The last two scripts are based on those given by
`mod_wsgi documentation <https://code.google.com/p/modwsgi/wiki/VirtualEnvironments>`_.
The Apache configuration will then be similar to the following:
.. code-block:: apache
<VirtualHost *>
ServerName example.org
WSGIDaemonProcess isso user=www-data group=www-data threads=5
WSGIScriptAlias /mounted_isso_path /path/to/isso.wsgi
</VirtualHost>
You will need to adjust the user and group according to your Apache installation and
security policy. Be aware that the directory containing the comments database must
be writable by the user or group running the WSGI daemon process: having a writable
database only is not enough, since SQLite will need to create a lock file in the same
directory.
`mod_fastcgi <http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can use this method if your hosting provider doesn't allow you to have long
running processes. If FastCGI has not yet been configured in your server,
please follow these steps:
.. note:: This information may be incorrect, if you have more knowledge on how
to deploy Python via `mod_fastcgi`, consider extending/correcting this section.
For more information, see `Flask: Configuring Apache
<http://flask.pocoo.org/docs/deploying/fastcgi/#configuring-apache>`_.
.. code-block:: apache
LoadModule fastcgi_module /usr/lib64/httpd/modules/mod_fastcgi.so
FastCgiServer /var/www/html/yourapplication/app.fcgi -idle-timeout 300 -processes 5
<VirtualHost *>
ServerName example.org
AddHandler fastcgi-script fcgi
ScriptAlias / /var/www/isso.fcgi
<Location />
SetHandler fastcgi-script
</Location>
</VirtualHost>
Next, to run isso as a FastCGI script you'll need to install ``flup`` with
PIP:
.. code-block:: sh
$ pip install flup
Finally, copy'n'paste to `/var/www/isso.fcgi` (or whatever location you prefer):
.. code-block:: python
#!/usr/bin/env python
#: uncomment if you're using a virtualenv
# import sys
# sys.path.insert(0, '<your_local_path>/lib/python2.7/site-packages')
from isso import make_app, dist, config
import os
from flup.server.fcgi import WSGIServer
application = make_app(config.load(
os.path.join(dist.location, dist.project_name, "defaults.ini"),
"/path/to/isso.cfg"))
WSGIServer(application).run()
`Openshift <http://openshift.com>`__
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
With `Isso Openshift Deployment Kit`_, Isso can be installed on Open
Shift with just one click. Make sure you already have installed ``rhc``
(`instructions`_) and completed the setup.
1. Run the following, you will get an Open Shift instance installed with
Isso:
::
rhc create-app appname python-2.7 --from-code https://github.com/avinassh/isso-openshift.git
2. Above step also clones Git repository of your Open Shift instance, in
current directory. Make changes to the configuration file and push
back to Openshift, it will be redeployed with new settings.
3. Visit ``http://<yourappname>-<openshift-namespace>.com/info`` to
verify Isso is deployed properly and is working.
.. _Isso Openshift Deployment Kit: https://github.com/avinassh/isso-openshift
.. _instructions: https://developers.openshift.com/en/managing-client-tools.html

@ -1,57 +0,0 @@
uWSGI
=====
In short: `uWSGI <http://uwsgi-docs.readthedocs.org/>`_ is awesome. Isso
has builtin support for it (and simple fallback if uWSGI is not
available). Use uWSGI if you think that the builtin WSGI server is a bad
choice or slow (hint: it's both).
With uWSGI, you have roughly 100% performance improvements for just
using it. Instead of one thread per request, you can use multiple
processes, hence it is more "web scale". Other side effects: spooling,
fast inter-process caching.
Installation
------------
You need uWSGI 1.9 or higher, fortunately you can install it with
Python:
.. code-block:: sh
~> apt-get install build-essential python-dev
~> pip install uwsgi
Configuration
-------------
For convenience, I recommend a INI-style configuration (you can also
supply everything as command-line arguments):
.. code-block:: ini
[uwsgi]
http = :8080
master = true
processes = 4
cache2 = name=hash,items=1024,blocksize=32
spooler = %d/mail
module = isso.run
virtualenv = %d
env = ISSO_SETTINGS=%d/sample.cfg
You shoud adjust ``processes`` to your CPU count. Then, save this file
to a directory if choice. Next to this file, create an empty directory
called ``mail``:
.. code-block:: sh
~> mkdir mail/
~> ls
uwsgi.ini mail/
Now start Isso:
.. code-block:: sh
~> uwsgi /path/to/uwsgi.ini

@ -1,16 +1,25 @@
Overview
========
Welcome to the Isso's documentation. This documentation will help you get
started fast. If you get any problems when using Isso, you can find the answer
in troubleshooting or you can ask me on IRC or GitHub.
Welcome to Isso's documentation. This documentation will help you get started
fast. If you run into any problems when using Isso, you can find the answer in
troubleshooting guide or you can ask me on IRC or GitHub.
Documentation overview:
.. toctree::
:maxdepth: 1
install
quickstart
troubleshooting
What's Isso?
------------
Isso is a lightweight commenting server similar to Disqus. It allows anonymous
comments, maintains identity and is simple to administrate. It uses JavaScript
and cross-origin ressource sharing for easy integration into static websites.
and cross-origin ressource sharing for easy integration into (static) websites.
No, I meant "Isso"
------------------

@ -1,22 +1,274 @@
Installation
------------
============
Isso is a web application written in Python. If pip and virtualenv mean anything
to you, continue with :ref:`install-from-pypi`. If you are running
Debian/Ubuntu, Gentoo, Archlinux or Fedora, you can use
:ref:`prebuilt-package`. If not, read the next section carefully.
.. contents::
:local:
:depth: 1
.. _install-interludium:
Interludium: Python is not PHP
------------------------------
If you think hosting a web application written in Python is as easy as one
written in PHP, you are wrong. Unlike for PHP, many Linux distribution use
Python for internal tools. Your package manager already ships several python
libraries, but most likely not all required by Isso (or in an up-to-date
version looking at you, Debian!).
That's why most Python developers use the `Python Package Index`_ to get their
dependencies. The most important rule to follow is to never install *anything* from PyPi
as root. Not because of malicious software, but because you *will* break your
system.
``easy_install`` is one tool to mess up your system. Another package manager is
``pip``. If you ever searched for an issue with Python/pip and Stackoverflow is
suggesting you ``easy_install pip`` or ``pip install --upgrade pip`` (as root
of course!), you are doing it wrong. `Why you should not use Python's
easy_install carelessly on Debian`_ is worth the read.
Fortunately, Python has a way to install packages (both as root and as user)
without interfering with your globally installed packages: `virtualenv`. Use
this *always* if you are installing software unavailable in your favourite
package manager.
.. code-block:: sh
# for Debian/Ubuntu
~> sudo apt-get install python-setuptools python-virtualenv python-dev
# Fedora/Red Hat
~> sudo yum install python-setuptools python-virtualenv python-devel
Requirements:
The next steps should be done as regular user, not as root (although possible
but not recommended):
- Python 2.6, 2.7 or 3.3
- a working C compiler
.. code-block:: sh
~> virtualenv /opt/isso
~> source /opt/isso/bin/activate
After calling `source`, you can now install packages from PyPi locally into this
virtual environment. If you don't like Isso anymore, you just `rm -rf` the
folder. Inside this virtual environment, you may also execute the example
commands from above to upgrade your Python Package Manager (although it barely
makes sense), it is completely independent from your global system.
To use Isso installed in a virtual environment outside of the virtual
environment, you just need to add */opt/isso/bin* to your :envvar:`PATH` or
execute */opt/isso/bin/isso* directly. It will launch Isso from within the
virtual environment.
With a virtualenv active, you may now continue to :ref:`install-from-pypi`!
Of course you may not need a virtualenv when you are running dedicated virtual
machines or a shared host (e.g. Uberspace.de).
.. _Python Package Index: https://pypi.python.org/pypi
.. _Why you should not use Python's easy_install carelessly on Debian:
https://workaround.org/easy-install-debian
Install Isso with PIP_:
.. _install-from-pypi:
Install from PyPi
-----------------
Requirements
^^^^^^^^^^^^
- Python 2.7 or 3.4+ (+ devel headers)
- SQLite 3.3.8 or later
- a working C compiler
For Debian/Ubuntu just `copy and paste
<http://thejh.net/misc/website-terminal-copy-paste>`_ to your terminal:
.. code-block:: sh
~> sudo apt-get install python-dev sqlite3 build-essential
Similar for Fedora (and derivates):
.. code-block:: sh
~> sudo yum install python-devel sqlite
~> sudo yum groupinstall “Development Tools”
Installation
^^^^^^^^^^^^
Install Isso with `pip <http://www.pip-installer.org/en/latest/>`_:
.. code-block:: sh
~> pip install isso
.. _PIP: http://www.pip-installer.org/en/latest/
`Don't have pip? <https://twitter.com/gardaud/status/357638468572151808>`_
.. code-block:: sh
~> easy_install isso # cross your fingers
For easier execution, you can symlink the executable to a location in your
:envvar:`PATH`.
.. code-block:: sh
~> ln -s /opt/isso/bin/isso /usr/local/bin/isso
Upgrade
^^^^^^^
To upgrade Isso, activate your virtual environment again, and run
.. code-block:: sh
~> source /opt/isso/bin/activate # optional
~> pip install --upgrade isso
.. _prebuilt-package:
Prebuilt Packages
-----------------
* Debian (since Buster): https://packages.debian.org/search?keywords=isso
Init scripts:
* Gentoo: http://eroen.eu/cgit/cgit.cgi/eroen-overlay/tree/www-apps/isso?h=isso
not yet available in Portage, but you can use the ebuild to build Isso.
- SystemD: https://github.com/jgraichen/debian-isso/blob/master/debian/isso.service
- SysVinit: https://github.com/jgraichen/debian-isso/blob/master/debian/isso.init
* Arch Linux: https://aur.archlinux.org/packages/isso/
install with `yaourt isso`.
* Fedora: https://copr.fedoraproject.org/coprs/jujens/isso/ — copr
repository. Built from Pypi, includes a systemctl unit script.
Build a Docker image
--------------------
You can get a Docker image by running ``docker build . -t
isso``. Assuming you have your configuration in ``/opt/isso``, you can
use the following command to spawn the Docker container:
.. code-block:: sh
~> docker run -d --rm --name isso -p 127.0.0.1:8080:8080 -v /opt/isso:/config -v /opt/isso:/db isso
Then, you can use a reverse proxy to expose port 8080.
Install from Source
-------------------
If you want to hack on Isso or track down issues, there's an alternate
way to set up Isso. It requires a lot more dependencies and effort:
- Python 2.7 or 3.4+ (+ devel headers)
- Virtualenv
- SQLite 3.3.8 or later
- a working C compiler
- Node.js, `NPM <https://npmjs.org/>`__ and `Bower <http://bower.io/>`__
Get a fresh copy of Isso:
.. code-block:: sh
~> git clone https://github.com/posativ/isso.git
~> cd isso/
To create a virtual environment (recommended), run:
.. code-block:: sh
~> virtualenv .
~> source ./bin/activate
Install Isso and its dependencies:
.. code-block:: sh
~> python setup.py develop # or `install`
~> isso run
Install JavaScript modules:
.. code-block:: sh
~> make init
Integration without optimization:
.. code-block:: html
<script src="/js/config.js"></script>
<script data-main="/js/embed" src="/js/components/requirejs/require.js"></script>
Optimization:
.. code-block:: sh
~> npm install -g requirejs uglify-js jade
~> make js
.. _init-scripts:
Init scripts
------------
Init scripts to run Isso as a service (check your distribution's documentation
for your init-system; e.g. Debian uses SysVinit, Fedora uses systemd) if you
don't use FastCGi or uWSGI:
- systemd (Isso + Gunicorn): https://github.com/jgraichen/debian-isso/blob/master/debian/isso.service
- SysVinit (Isso + Gunicorn): https://github.com/jgraichen/debian-isso/blob/master/debian/isso.init
- OpenBSD: https://gist.github.com/noqqe/7397719
- FreeBSD: https://gist.github.com/ckoepp/52f6f0262de04cee1b88ef4a441e276d
- Supervisor: https://github.com/posativ/isso/issues/47
If you're writing your own init script, you can utilize ``start-stop-daemon``
to run Isso in the background (Isso runs in the foreground usually). Below you
will find a very basic SysVinit script which you can use for inspiration:
.. code-block:: sh
#!/bin/sh
### BEGIN INIT INFO
# Provides: isso
# Required-Start: $local_fs $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Description: lightweight Disqus alternative
### END INIT INFO
EXEC=/opt/isso/bin/isso
EXEC_OPTS="-c /etc/isso.cfg run"
RUNAS=isso
PIDFILE=/var/run/isso.pid
start() {
echo 'Starting service…' >&2
start-stop-daemon --start --user "$RUNAS" --background --make-pidfile --pidfile $PIDFILE \
--exec $EXEC -- $EXEC_OPTS
}
stop() {
echo 'Stopping service…' >&2
start-stop-daemon --stop --user "$RUNAS" --pidfile $PIDFILE --exec $EXEC
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart}"
esac

@ -0,0 +1,38 @@
Isso
====
What's Isso?
------------
Isso is a lightweight commenting server similar to Disqus. It allows anonymous
comments, maintains identity and is simple to administrate. It uses JavaScript
and cross-origin resource sharing for easy integration into static websites.
No, I meant "Isso"
------------------
Isso is an informal, german abbreviation for "Ich schrei sonst!", which can
roughly be translated to "I'm yelling otherwise". It usually ends the
discussion without any further arguments.
In germany, Isso `is also pokémon N° 360`__.
.. __: http://bulbapedia.bulbagarden.net/wiki/Wynaut_(Pok%C3%A9mon)
What's wrong with Disqus?
-------------------------
No anonymous comments (IP address, email and name recorded), hosted in the USA,
third-party. Just like IntenseDebate, livefrye etc. When you embed Disqus, they
can do anything with your readers (and probably mine Bitcoins, see the loading
times).
Setup
-----
.. toctree::
:maxdepth: 1
../quickstart
../troubleshooting

@ -2,20 +2,24 @@ Quickstart
==========
Assuming you have successfully :doc:`installed <install>` Isso, here's
a quickstart quide that covers common setups.
a quickstart guide that covers the most common setup. Sections covered:
.. contents::
:local:
:depth: 1
Configuration
-------------
You must provide a custom configuration. Most default parameters are useful for
development, not persistence. Two most important options are `dbpath` to set
the location of your database and `host` which is your website:
You must provide a custom configuration to set `dbpath` (your database
location) and `host` (a list of websites for CORS_). All other options have
sane defaults.
.. code-block:: ini
[general]
; database location, check permissions
; database location, check permissions, automatically created if it
does not exist
dbpath = /var/lib/isso/comments.db
; your website or blog (not the location of Isso!)
host = http://example.tld/
@ -28,12 +32,12 @@ the location of your database and `host` which is your website:
https://example.tld/
Note, that multiple, *different* websites are **not** supported in a single
configuration. To serve comments for diffent websites, refer to
configuration. To serve comments for different websites, refer to
:ref:`Multiple Sites <configure-multiple-sites>`.
You moderate Isso through signed URLs sent by email or logged. By default,
comments are accepted and immediately shown to other users. To enable
moderation queue, add:
The moderation is done with signed URLs sent by email or logged to stdout.
By default, comments are accepted and immediately shown to other users. To
enable moderation queue, add:
.. code-block:: ini
@ -41,7 +45,7 @@ moderation queue, add:
enabled = true
To moderate comments, either use the activation or deletion URL in the logs or
:ref:`use SMTP <configure-smtp>` to get notified on new comments including the
:ref:`use SMTP <configure-smtp>` to get notified of new comments, including the
URLs for activation and deletion:
.. code-block:: ini
@ -51,24 +55,33 @@ URLs for activation and deletion:
[smtp]
; SMTP settings
For more options, see :doc:`server <configuration/server>` and :doc:`client
<configuration/client>` configuration.
Migration
---------
You can migrate your existing comments from Disqus_. Log into Disqus, go to
your website, click on *Discussions* and select the *Export* tab. You'll
receive an email with your comments. Unfortunately, Disqus does not export
up- and downvotes.
Isso provides a tool for importing comments from Disqus_ or WordPress_.
You can also import comments from any other comment system, but this topic is more
complex and is covered in :doc:`advanced migration <extras/advanced-migration>`.
To import existing comments, run Isso with your new configuration file:
To export your comments from Disqus, log into Disqus, go to your website, click
on *Discussions* and select the *Export* tab. You'll receive an email with your
comments. Unfortunately, Disqus does not export up- and downvotes.
To export comments from your previous WordPress installation, go to *Tools*,
export your data. It has been reported that WordPress may generate broken XML.
Try to repair the file using ``xmllint`` before you continue with the import.
Now import the XML dump:
.. code-block:: sh
~> isso -c /path/to/isso.cfg import user-2013-09-02T11_39_22.971478-all.xml
~> isso -c /path/to/isso.cfg import -t [disqus|wordpress] disqus-or-wordpress.xml
[100%] 53 threads, 192 comments
.. _Disqus: <https://disqus.com/>
.. _Disqus: https://disqus.com/
.. _WordPress: https://wordpress.org/
Running Isso
------------
@ -82,8 +95,7 @@ To run Isso, simply execute:
Next, we configure Nginx_ to proxy Isso. Do not run Isso on a public interface!
A popular but often error-prone (because of CORS_) setup to host Isso uses a
dedicated domain such as ``comments.example.tld``; see
:doc:`configuration/setup` for alternate ways.
dedicated domain such as ``comments.example.tld``.
Assuming both, your website and Isso are on the same server, the nginx
configuration looks like this:
@ -104,15 +116,19 @@ configuration looks like this:
proxy_pass http://localhost:8080;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Integration
-----------
Now, you embed Isso to your website:
.. code-block:: html
<script data-isso="http://comments.example.tld/"
src="http://comments.example.tld/js/embed.min.js"></script>
<script data-isso="//comments.example.tld/"
src="//comments.example.tld/js/embed.min.js"></script>
<section id="isso-thread"></section>
@ -122,102 +138,17 @@ Note, that `data-isso` is optional, but when a website includes a script using
That's it. When you open your website, you should see a commenting form. Leave
a comment to see if the setup works. If not, see :doc:`troubleshooting`.
.. _Nginx: http://nginx.org/
.. _CORS: https://developer.mozilla.org/en/docs/HTTP/Access_control_CORS
Deployment
----------
Isso ships with a built-in web server, which is useful for the initial setup.
But it is not recommended to use the built-in web server for production. A few
WSGI servers are supported out-of-the-box:
* gevent_, coroutine-based network library
* uWSGI_, full-featured uWSGI server
* gunicorn_, Python WSGI HTTP Server for UNIX
.. _gevent: http://www.gevent.org/
.. _uWSGI: http://uwsgi-docs.readthedocs.org/en/latest/
.. _gunicorn: http://gunicorn.org/
gevent
^^^^^^
Probably the easiest deployment method. Install with PIP (requires libevent):
.. code-block:: sh
$ pip install gevent
Then, just use the ``isso`` executable as usual. Gevent monkey-patches Python's
standard library to work with greenlets.
To execute Isso, just use the commandline interface:
.. code-block:: sh
$ isso -c my.cfg run
Unfortunately, gevent 0.13.2 does not support UNIX domain sockets (see `#295
<https://github.com/surfly/gevent/issues/295>`_ and `#299
<https://github.com/surfly/gevent/issues/299>`_ for details).
uWSGI
^^^^^
The author's favourite WSGI server. Due the complexity of uWSGI, there is a
:doc:`separate document <extras/uwsgi>` on how to setup uWSGI for use
with Isso.
gunicorn
^^^^^^^^
Install gunicorn_ via PIP:
.. code-block:: sh
$ pip install gunicorn
To execute Isso, use a command similar to:
.. code-block:: sh
$ export ISSO_SETTINGS="/path/to/isso.cfg"
$ gunicorn -b localhost:8080 -w 4 --preload isso.run
mod_wsgi
^^^^^^^^
I have no experience at all with `mod_wsgi`, most things are taken from
`Flask: Configuring Apache <http://flask.pocoo.org/docs/deploying/mod_wsgi/#configuring-apache>`_:
.. code-block:: apache
<VirtualHost *>
ServerName example.org
WSGIDaemonProcess isso user=... group=... threads=5
WSGIScriptAlias / /var/www/isso.wsgi
</VirtualHost>
Now, you need to create a new `isso.wsgi` file:
.. code-block:: python
import os
from isso import make_app
from isso.core import Config
application = make_app(Config.load("/path/to/isso.cfg"))
Unless you know how to preload the application, add a static session key to
your `isso.cfg`:
Going Further
-------------
.. code-block:: ini
There are several server and client configuration options not covered in this
quickstart, check out :doc:`configuration/server` and
:doc:`configuration/client` for more information. For further website
integration, see :doc:`extras/advanced-integration`.
[general]
; cat /dev/urandom | strings | grep -o '[[:alnum:]]' | head -n 30 | tr -d '\n'
session-key = superrandomkey1
To launch Isso automatically, check the :ref:`init-scripts` section from the
installation guide. A different approach to deploy a web application is
written here: :doc:`Deployment of Isso <extras/deployment>`.
.. _Nginx: http://nginx.org/
.. _CORS: https://developer.mozilla.org/en/docs/HTTP/Access_control_CORS

@ -1,34 +1,3 @@
Setup
=====
Sub-URI
-------
You can run Isso on the same domain as your website, which circumvents issues
originating from CORS_. Also, privacy-protecting browser addons such as
`Request Policy`_ wont block comments.
.. code-block:: nginx
server {
listen [::]:80;
listen [::]:443 ssl;
server_name example.tld;
root /var/www/example.tld;
location /isso {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Script-Name /isso;
proxy_pass http://localhost:8080;
}
}
Now, the website integration is just as described in :doc:`../quickstart` but
with a different location.
.. _CORS: https://developer.mozilla.org/en/docs/HTTP/Access_control_CORS
.. _Request Policy: https://www.requestpolicy.com/
.. _configure-multiple-sites:
@ -36,8 +5,8 @@ Multiple Sites
--------------
Isso is designed to serve comments for a single website and therefore stores
comments for a relative URL to support HTTP, HTTPS and even domain transfers
without manual intervention. But you can chain Isso to support multiple
comments for a relative URL. This is done to support HTTP, HTTPS and even domain transfers
without manual intervention. You can chain Isso to support multiple
websites on different domains.
The following example uses `gunicorn <http://gunicorn.org/>`_ as WSGI server (

@ -0,0 +1,29 @@
Sub-URI
=======
You can run Isso on the same domain as your website, which circumvents issues
originating from CORS_. Also, privacy-protecting browser addons such as
`Request Policy`_ wont block comments.
.. code-block:: nginx
server {
listen [::]:80;
listen [::]:443 ssl;
server_name example.tld;
root /var/www/example.tld;
location /isso {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Script-Name /isso;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://localhost:8080;
}
}
Now, the website integration is just as described in :doc:`../quickstart` but
with a different location.
.. _CORS: https://developer.mozilla.org/en/docs/HTTP/Access_control_CORS
.. _Request Policy: https://www.requestpolicy.com/

@ -1,4 +1,39 @@
Troubleshooting
===============
To be written.
For uberspace users
-------------------
Some uberspace users experienced problems with isso and they solved their
issues by adding `DirectoryIndex disabled` as the first line in the `.htaccess`
file for the domain the isso server is running on.
pkg_ressources.DistributionNotFound
-----------------------------------
This is usually caused by messing up the system's Python with newer packages
from PyPi (e.g. by executing `easy_install --upgrade pip` as root) and is not
related to Isso at all.
Install Isso in a virtual environment as described in
:ref:`install-interludium`. Alternatively, you can use `pip install --user`
to install Isso into the user's home.
UnicodeDecodeError: 'ascii' codec can't decode byte 0xff
--------------------------------------------------------
Likely an issue with your environment, check you set your preferred file
encoding either in :envvar:`LANG`, :envvar:`LANGUAGE`, :envvar:`LC_ALL` or
:envvar:`LC_CTYPE`:
.. code-block:: text
$ env LANG=C.UTF-8 isso [-h] [--version] ...
If none of the mentioned variables are set, the interaction with Isso will
likely fail (unable to print non-ascii characters to stdout/err, unable to
parse configuration file with non-ascii characters and so forth).
The web console shows 404 Not Found responses
---------------------------------------------
That's fine. Isso returns "404 Not Found" to indicate "No comments".

@ -1,2 +0,0 @@
Usage
=====

@ -0,0 +1,2 @@
[html4css1 writer]
initial_header_level: 2

@ -1,112 +0,0 @@
# Isso configuration file
# vim: set filetype=ini
[general]
# file location to the SQLite3 database, highly recommended to change this
# location to a non-temporary location
dbpath = /tmp/comments.db
# required to dispatch multiple websites, not used otherwise.
name =
# URL to your website. When you start Isso, it will probe your website with a
# simple GET / request to see if it can reach the webserver. If this fails, Isso
# may not be able check if a web page exists, thus fails to accept new comments.
# You can supply more than one host:
# host =
# http://localhost/
# https://localhost/
host = http://localhost/
# time range that allows users to edit/remove their own comments.
# It supports years, weeks, days, hours, minutes, seconds.
# 3h45m12s equals to 3 hours, 45 minutes and 12 seconds.
max-age = 15m
# private session key to validate client cookies. If you restart the application
# several times per hour for whatever reason, use a fixed key.
session-key = ... ; python: binascii.b2a_hex(os.urandom(24))
# Select notification backend for new comments. Currently, only SMTP is
# available.
notify =
[moderation]
# enable comment moderation queue. This option only affects new comments.
# Comments in modertion queue are not visible to other users until you activate
# them.
enabled = false
# remove unprocessed comments in moderation queue after given time.
purge-after = 30d
[server]
# interface to listen on. Isso supports TCP/IP and unix domain sockets: UNIX
# domain socket listen = unix:///tmp/isso.sock TCP/IP listen =
# http:///localhost:1234/
#
# When gevent is available, it is automatically used for http:// Currently,
# gevent can not handle http requests on unix domain socket (see #295 and #299
# for details). Does not apply for uWSGI.
listen = http://localhost:8080
# reload application, when the source code has changed. Useful for development
# (don't forget to use a fixed session-key). Only works when gevent and uwsgi
# are not available.
reload = off
# show 10 most time consuming function in Isso after each request. Do not use in
# production.
profile = off
[smtp]
# Isso can notify you on new comments via SMTP. In the email notification, you
# also can moderate (=activate or delete) comments.
# self-explanatory, optional
username =
# self-explanatory (yes, plain text, create a dedicated account for
# notifications), optional.
password =
# SMTP server
host = localhost
# SMTP port
port = 465
# use SSL to connect to the server. Python probably does not validate the
# certificate. Needs research, though. But you should use a dedicated email
# account anyways.
ssl = on
# recipient address, e.g. your email address
to =
# sender address, e.g. isso@example.tld
from =
[guard]
# Enable basic spam protection features, e.g. rate-limit per IP address (/24 for
# IPv4, /48 for IPv6).
# enable guard, recommended in production. Not useful for debugging purposes.
enabled = true
# limit to N new comments per minute.
ratelimit = 2
# how many comments directly to the thread (prevent a simple while true; do curl
# ...; done.
direct-reply = 3
# allow commenters to reply to their own comments when they could still edit the
# comment. After the editing timeframe is gone, commenters can reply to their
# own comments anyways. Do not forget to configure the client.
reply-to-self = false

@ -1,32 +1,17 @@
Frequently asked question
=========================
Why not use Gravatar/Libravatar/... ?
-------------------------------------
Various people asked or complained about the generated icons next to their
comments. First, it is not an avatar, it is an identicon used to
*identify* an author of multiple comments without leaking personal
informations (unlike Gravatar).
If you are in need of Gravatar_, then use Disqus. If you run your own
Libravatar_ server, you can work on a patch for Isso which adds *optional*
support for avatars.
.. _Gravatar: https://secure.gravatar.com/
.. _Libravatar: http://libravatar.org/
Why SQLite3?
------------
Although partially answered on the index page, here a more complete answer: If
Although partially answered on the index page, here is a more complete answer: If
you manage massive amounts of comments, Isso is a really bad choice. Isso is
designed to be simple and easy to setup, not optimizied for high-traffic
designed to be simple and easy to setup, it is not optimized for high-traffic
websites (use a `dedicated Disqus`_ instance then).
comments are not big data
Comments are not big data.
For example, 209 threads and 778 comments in total only need 620K (kilobyte)
memory. Excellent use case for SQLite.
For example, if you have 209 threads and 778 comments in total this only needs 620 kilobytes
of memory. This is an excellent use case for SQLite.
.. _dedicated Disqus:

@ -14,10 +14,10 @@
</figure>
<ul>
<li>
<p><strong>Create, Edit and Remove Comments</strong></p>
<p>Commenters can edit or delete their own comments (within
15 minutes by default).</p>
<p>Comments in moderation queue are not publicly visible until
<p><strong>Comments written in Markdown</strong></p>
<p>Users can edit or delete own comments (within 15 minutes by
default).</p>
<p>Comments in moderation queue are not publicly visible before
activation.</p>
</li>
<li>
@ -25,13 +25,13 @@
<p>Because comments are not Big Data.</p>
</li>
<li>
<p><strong>Disqus Import</strong></p>
<p>You can migrate your Disqus comments without any hassle.</p>
<p><strong>Disqus &amp; WordPress Import</strong></p>
<p>You can migrate your Disqus/WordPress comments without any hassle.</p>
</li>
<li>
<p><strong>client-side JavaScript</strong></p>
<p>Embed a single JS file, 54kb (18kb gzipped) and you are
done.</p>
<p><strong>Configurable JS client</strong></p>
<p>Embed a single JS file, 40kb (12kb gzipped) and you are
done.</p>
<p>Supports Firefox, Safari, Chrome and IE10.</p>
</li>
</ul>
@ -50,6 +50,18 @@
<code>#isso</code></a> on <a href="http://freenode.net/">Freenode</a>
or open an issue on <a href="https://github.com/posativ/isso/issues">GitHub</a>.
</p>
<p>
Or join the <a href="http://librelist.com/browser/isso/">mailing list</a>,
just send an email to <a href="mailto:isso@librelist.com">isso@librelist.com</a>.
</p>
<h2>Contribute</h2>
<p>
<a href="{{ pathto('contribute') }}">Write Code</a>,
<a href="https://www.transifex.com/projects/p/isso/">Translate</a> or
<a href="https://flattr.com/thing/2059355/posativisso-on-GitHub">Flattr
<img src="{{ pathto('_static/flattr.png', 1) }}" alt="Flattr icon"/></a>.
</p>
{% include "searchbox.html" %}
</div>

@ -0,0 +1,10 @@
Releasing steps
===============
* Run ``python3 setup.py nosetests``, ``python2 setup.py nosetests``
* Update version number in ``setup.py`` and ``CHANGES.rst``
* ``git commit -m "Preparing ${VERSION}" setup.py CHANGES.rst``
* ``git tag -as ${VERSION}``
* ``make init all``
* ``python3 setup.py sdist``
* ``twine upload --sign dist/isso-${VERSION}.tar.gz``

@ -3,7 +3,7 @@
#
# The MIT License (MIT)
#
# Copyright (c) 2012-2013 Martin Zimmermann.
# Copyright (c) 2012-2014 Martin Zimmermann.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@ -25,7 +25,7 @@
#
# Isso a lightweight Disqus alternative
from __future__ import print_function
from __future__ import print_function, unicode_literals
import pkg_resources
dist = pkg_resources.get_distribution("isso")
@ -35,7 +35,8 @@ import sys
if sys.argv[0].startswith("isso"):
try:
import gevent.monkey; gevent.monkey.patch_all()
import gevent.monkey
gevent.monkey.patch_all()
except ImportError:
pass
@ -48,28 +49,32 @@ from os.path import dirname, join
from argparse import ArgumentParser
from functools import partial, reduce
import pkg_resources
werkzeug = pkg_resources.get_distribution("werkzeug")
from itsdangerous import URLSafeTimedSerializer
from werkzeug.routing import Map
from werkzeug.exceptions import HTTPException, InternalServerError
from werkzeug.wsgi import SharedDataMiddleware
from werkzeug.middleware.shared_data import SharedDataMiddleware
from werkzeug.local import Local, LocalManager
from werkzeug.serving import run_simple
from werkzeug.contrib.fixers import ProxyFix
from werkzeug.contrib.profiler import ProfilerMiddleware
from werkzeug.middleware.proxy_fix import ProxyFix
from werkzeug.middleware.profiler import ProfilerMiddleware
local = Local()
local_manager = LocalManager([local])
from isso import db, migrate, wsgi, ext, views
from isso.core import ThreadedMixin, ProcessMixin, uWSGIMixin, Config
from isso.utils import parse, http, JSONRequest, origin
from isso import config, db, migrate, wsgi, ext, views
from isso.core import ThreadedMixin, ProcessMixin, uWSGIMixin
from isso.wsgi import origin, urlsplit
from isso.utils import http, JSONRequest, html, hash
from isso.views import comments
from isso.ext.notifications import Stdout, SMTP
logging.getLogger('werkzeug').setLevel(logging.ERROR)
logging.getLogger('werkzeug').setLevel(logging.WARN)
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s: %(message)s")
@ -77,22 +82,37 @@ logging.basicConfig(
logger = logging.getLogger("isso")
class Isso(object):
class ProxyFixCustom(ProxyFix):
def __init__(self, app):
# This is needed for werkzeug.wsgi.get_current_url called in isso/views/comments.py
# to work properly when isso is hosted under a sub-path
# cf. https://werkzeug.palletsprojects.com/en/1.0.x/middleware/proxy_fix/
super().__init__(app, x_prefix=1)
salt = b"Eech7co8Ohloopo9Ol6baimi"
class Isso(object):
def __init__(self, conf):
self.conf = conf
self.db = db.SQLite3(conf.get('general', 'dbpath'), conf)
self.signer = URLSafeTimedSerializer(conf.get('general', 'session-key'))
self.signer = URLSafeTimedSerializer(
self.db.preferences.get("session-key"))
self.markup = html.Markup(conf.section('markup'))
self.hasher = hash.new(conf.section("hash"))
super(Isso, self).__init__(conf)
subscribers = []
subscribers.append(Stdout(None))
if conf.get("general", "notify") == "smtp":
smtp_backend = False
for backend in conf.getlist("general", "notify"):
if backend == "stdout":
subscribers.append(Stdout(None))
elif backend in ("smtp", "SMTP"):
smtp_backend = True
else:
logger.warn("unknown notification backend '%s'", backend)
if smtp_backend or conf.getboolean("general", "reply-notifications"):
subscribers.append(SMTP(self))
self.signal = ext.Signal(*subscribers)
@ -100,7 +120,10 @@ class Isso(object):
self.urls = Map()
views.Info(self)
comments.API(self)
comments.API(self, self.hasher)
def render(self, text):
return self.markup.render(text)
def sign(self, obj):
return self.signer.dumps(obj)
@ -112,7 +135,8 @@ class Isso(object):
local.request = request
local.host = wsgi.host(request.environ)
local.origin = origin(self.conf.getiter("general", "host"))(request.environ)
local.origin = origin(self.conf.getiter(
"general", "host"))(request.environ)
adapter = self.urls.bind_to_environ(request.environ)
@ -126,7 +150,8 @@ class Isso(object):
except HTTPException as e:
return e
except Exception:
logger.exception("%s %s", request.method, request.environ["PATH_INFO"])
logger.exception("%s %s", request.method,
request.environ["PATH_INFO"])
return InternalServerError()
else:
return response
@ -141,23 +166,21 @@ class Isso(object):
def make_app(conf=None, threading=True, multiprocessing=False, uwsgi=False):
if not any((threading, multiprocessing, uwsgi)):
raise RuntimeError("either set threading, multiprocessing or uwsgi")
if threading:
class App(Isso, ThreadedMixin):
pass
if multiprocessing:
elif multiprocessing:
class App(Isso, ProcessMixin):
pass
if uwsgi:
else:
class App(Isso, uWSGIMixin):
pass
isso = App(conf)
# show session-key (to see that it changes randomely if unset)
logger.info("session-key = %s", isso.conf.get("general", "session-key"))
# check HTTP server connection
for host in conf.getiter("general", "host"):
with http.curl('HEAD', host, '/', 5) as resp:
@ -165,22 +188,32 @@ def make_app(conf=None, threading=True, multiprocessing=False, uwsgi=False):
logger.info("connected to %s", host)
break
else:
logger.warn("unable to connect to %s", ", ".join(conf.getiter("general", "host")))
logger.warn("unable to connect to your website, Isso will probably not "
"work correctly. Please make sure, Isso can reach your "
"website via HTTP(S).")
wrapper = [local_manager.make_middleware]
if isso.conf.getboolean("server", "profile"):
wrapper.append(partial(ProfilerMiddleware,
sort_by=("cumtime", ), restrictions=("isso/(?!lib)", 10)))
sort_by=("cumulative", ), restrictions=("isso/(?!lib)", 10)))
wrapper.append(partial(SharedDataMiddleware, exports={
'/js': join(dirname(__file__), 'js/'),
'/css': join(dirname(__file__), 'css/')}))
'/css': join(dirname(__file__), 'css/'),
'/img': join(dirname(__file__), 'img/'),
'/demo': join(dirname(__file__), 'demo/')
}))
wrapper.append(partial(wsgi.CORSMiddleware,
origin=origin(isso.conf.getiter("general", "host"))))
origin=origin(isso.conf.getiter("general", "host")),
allowed=("Origin", "Referer", "Content-Type"),
exposed=("X-Set-Cookie", "Date")))
wrapper.extend([wsgi.SubURI, ProxyFixCustom])
wrapper.extend([wsgi.SubURI, ProxyFix])
if werkzeug.version.startswith("0.8"):
wrapper.append(wsgi.LegacyWerkzeugMiddleware)
return reduce(lambda x, f: f(x), wrapper, isso)
@ -190,30 +223,56 @@ def main():
parser = ArgumentParser(description="a blog comment hosting service")
subparser = parser.add_subparsers(help="commands", dest="command")
parser.add_argument('--version', action='version', version='%(prog)s ' + dist.version)
parser.add_argument('--version', action='version',
version='%(prog)s ' + dist.version)
parser.add_argument("-c", dest="conf", default="/etc/isso.conf",
metavar="/etc/isso.conf", help="set configuration file")
metavar="/etc/isso.conf", help="set configuration file")
imprt = subparser.add_parser('import', help="import Disqus XML export")
imprt.add_argument("dump", metavar="FILE")
imprt.add_argument("-n", "--dry-run", dest="dryrun", action="store_true",
help="perform a trial run with no changes made")
imprt.add_argument("-t", "--type", dest="type", default=None,
choices=["disqus", "wordpress", "generic"], help="export type")
imprt.add_argument("--empty-id", dest="empty_id", action="store_true",
help="workaround for weird Disqus XML exports, #135")
serve = subparser.add_parser("run", help="run server")
# run Isso as stand-alone server
subparser.add_parser("run", help="run server")
args = parser.parse_args()
conf = Config.load(args.conf)
conf = config.load(
join(dist.location, dist.project_name, "defaults.ini"), args.conf)
if args.command == "import":
xxx = tempfile.NamedTemporaryFile()
dbpath = conf.get("general", "dbpath") if not args.dryrun else xxx.name
conf.set("guard", "enabled", "off")
migrate.disqus(db.SQLite3(dbpath, conf), args.dump)
if args.dryrun:
xxx = tempfile.NamedTemporaryFile()
dbpath = xxx.name
else:
dbpath = conf.get("general", "dbpath")
mydb = db.SQLite3(dbpath, conf)
migrate.dispatch(args.type, mydb, args.dump, args.empty_id)
sys.exit(0)
if conf.get("general", "log-file"):
handler = logging.FileHandler(conf.get("general", "log-file"))
logger.addHandler(handler)
logging.getLogger("werkzeug").addHandler(handler)
logger.propagate = False
logging.getLogger("werkzeug").propagate = False
if not any(conf.getiter("general", "host")):
logger.error("No website(s) configured, Isso won't work.")
sys.exit(1)
if conf.get("server", "listen").startswith("http://"):
host, port, _ = parse.host(conf.get("server", "listen"))
host, port, _ = urlsplit(conf.get("server", "listen"))
try:
from gevent.pywsgi import WSGIServer
WSGIServer((host, port), make_app(conf)).serve_forever()

@ -1,22 +1,26 @@
# -*- encoding: utf-8 -*-
import sys
PY2K = sys.version_info[0] == 2
if not PY2K:
map, zip, filter = map, zip, filter
try:
text_type = unicode # Python 2
string_types = (str, unicode)
PY2K = True
except NameError: # Python 3
PY2K = False
text_type = str
string_types = (str, )
if not PY2K:
buffer = memoryview
else:
from itertools import imap, izip, ifilter
map, zip, filter = imap, izip, ifilter
text_type = unicode
string_types = (str, unicode)
filter, map, zip = filter, map, zip
def iteritems(dikt):
return iter(dikt.items()) # noqa: E731
from functools import reduce
else:
buffer = buffer
from itertools import ifilter, imap, izip
filter, map, zip = ifilter, imap, izip
def iteritems(dikt):
return dikt.iteritems() # noqa: E731
reduce = reduce

@ -0,0 +1,152 @@
# -*- encoding: utf-8 -*-
from __future__ import unicode_literals
import re
import logging
import datetime
from email.utils import parseaddr, formataddr
try:
from backports.configparser import ConfigParser
except ImportError:
from configparser import ConfigParser
from isso.compat import text_type as str
logger = logging.getLogger("isso")
def timedelta(string):
"""
Parse :param string: into :class:`datetime.timedelta`, you can use any
(logical) combination of Nw, Nd, Nh and Nm, e.g. `1h30m` for 1 hour, 30
minutes or `3w` for 3 weeks.
Raises a ValueError if the input is invalid/unparseable.
>>> print(timedelta("3w"))
21 days, 0:00:00
>>> print(timedelta("3w 12h 57m"))
21 days, 12:57:00
>>> print(timedelta("1h30m37s"))
1:30:37
>>> print(timedelta("1asdf3w"))
Traceback (most recent call last):
...
ValueError: invalid human-readable timedelta
"""
keys = ["weeks", "days", "hours", "minutes", "seconds"]
regex = "".join(["((?P<%s>\\d+)%s ?)?" % (k, k[0]) for k in keys])
kwargs = {}
for k, v in re.match(regex, string).groupdict(default="0").items():
kwargs[k] = int(v)
rv = datetime.timedelta(**kwargs)
if rv == datetime.timedelta():
raise ValueError("invalid human-readable timedelta")
return datetime.timedelta(**kwargs)
class Section(object):
"""A wrapper around :class:`IssoParser` that returns a partial configuration
section object.
>>> conf = new({"foo": {"bar": "spam"}})
>>> section = conf.section("foo")
>>> conf.get("foo", "bar") == section.get("bar")
True
"""
def __init__(self, conf, section):
self.conf = conf
self.section = section
def get(self, key):
return self.conf.get(self.section, key)
def getint(self, key):
return self.conf.getint(self.section, key)
def getlist(self, key):
return self.conf.getlist(self.section, key)
def getiter(self, key):
return self.conf.getiter(self.section, key)
def getboolean(self, key):
return self.conf.getboolean(self.section, key)
class IssoParser(ConfigParser):
"""Parse INI-style configuration with some modifications for Isso.
* parse human-readable timedelta such as "15m" as "15 minutes"
* handle indented lines as "lists"
"""
def getint(self, section, key):
try:
delta = timedelta(self.get(section, key))
except ValueError:
return super(IssoParser, self).getint(section, key)
else:
try:
return int(delta.total_seconds())
except AttributeError:
return int(delta.total_seconds())
def getlist(self, section, key):
return list(map(str.strip, self.get(section, key).split(',')))
def getiter(self, section, key):
for item in map(str.strip, self.get(section, key).split('\n')):
if item:
yield item
def section(self, section):
return Section(self, section)
def new(options=None):
cp = IssoParser(allow_no_value=True)
if options:
cp.read_dict(options)
return cp
def load(default, user=None):
# return set of (section, option)
def setify(cp):
return set((section, option) for section in cp.sections()
for option in cp.options(section))
parser = new()
parser.read(default)
a = setify(parser)
if user:
parser.read(user)
for item in setify(parser).difference(a):
logger.warn("no such option: [%s] %s", *item)
if item in (("server", "host"), ("server", "port")):
logger.warn("use `listen = http://$host:$port` instead")
if item == ("smtp", "ssl"):
logger.warn("use `security = none | starttls | ssl` instead")
if item == ("general", "session-key"):
logger.info("Your `session-key` has been stored in the "
"database itself, this option is now unused")
if not parseaddr(parser.get("smtp", "from"))[0]:
parser.set("smtp", "from",
formataddr(("Ich schrei sonst!", parser.get("smtp", "from"))))
return parser

@ -2,16 +2,11 @@
from __future__ import print_function
import io
import os
import time
import logging
import binascii
import threading
import multiprocessing
from configparser import ConfigParser
try:
import uwsgi
except ImportError:
@ -24,139 +19,12 @@ if PY2K:
else:
import _thread as thread
from isso.utils import parse
from isso.compat import text_type as str
from werkzeug.contrib.cache import NullCache, SimpleCache
from flask_caching.backends.null import NullCache
from flask_caching.backends.simple import SimpleCache
logger = logging.getLogger("isso")
class Section:
def __init__(self, conf, section):
self.conf = conf
self.section = section
def get(self, key):
return self.conf.get(self.section, key)
def getint(self, key):
return self.conf.getint(self.section, key)
def getiter(self, key):
return self.conf.getiter(self.section, key)
def getboolean(self, key):
return self.conf.getboolean(self.section, key)
class IssoParser(ConfigParser):
"""
Extended :class:`ConfigParser` to parse human-readable timedeltas
into seconds and handles multiple values per key.
>>> import io
>>> parser = IssoParser(allow_no_value=True)
>>> parser.read_file(io.StringIO(u'''
... [foo]
... bar = 1h
... baz = 12
... bla =
... spam
... ham
... asd = fgh
... '''))
>>> parser.getint("foo", "bar")
3600
>>> parser.getint("foo", "baz")
12
>>> list(parser.getiter("foo", "bla")) # doctest: +IGNORE_UNICODE
['spam', 'ham']
>>> list(parser.getiter("foo", "asd")) # doctest: +IGNORE_UNICODE
['fgh']
"""
@classmethod
def _total_seconds(cls, td):
return (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6
def getint(self, section, key):
try:
delta = parse.timedelta(self.get(section, key))
except ValueError:
return super(IssoParser, self).getint(section, key)
else:
try:
return int(delta.total_seconds())
except AttributeError:
return int(IssoParser._total_seconds(delta))
def getiter(self, section, key):
for item in map(str.strip, self.get(section, key).split('\n')):
if item:
yield item
def section(self, section):
return Section(self, section)
class Config:
default = [
"[general]",
"name = ",
"dbpath = /tmp/isso.db", "session-key = %s" % binascii.b2a_hex(os.urandom(16)),
"host = http://localhost:8080/", "max-age = 15m",
"notify = ",
"[moderation]",
"enabled = false",
"purge-after = 30d",
"[server]",
"listen = http://localhost:8080/",
"reload = off", "profile = off",
"[smtp]",
"username = ", "password = ",
"host = localhost", "port = 465", "ssl = on",
"to = ", "from = ",
"[guard]",
"enabled = true",
"ratelimit = 2",
"direct-reply = 3",
"reply-to-self = false"
]
@classmethod
def load(cls, configfile):
# return set of (section, option)
setify = lambda cp: set((section, option) for section in cp.sections()
for option in cp.options(section))
rv = IssoParser(allow_no_value=True)
rv.read_file(io.StringIO(u'\n'.join(Config.default)))
a = setify(rv)
if configfile:
rv.read(configfile)
diff = setify(rv).difference(a)
if diff:
for item in diff:
logger.warn("no such option: [%s] %s", *item)
if item in (("server", "host"), ("server", "port")):
logger.warn("use `listen = http://$host:$port` instead")
if rv.get("smtp", "username") and not rv.get("general", "notify"):
logger.warn(("SMTP is no longer enabled by default, add "
"`notify = smtp` to the general section to "
"enable SMTP nofications."))
return rv
class Cache:
"""Wrapper around werkzeug's cache class, to make it compatible to
uWSGI's cache framework.
@ -255,7 +123,9 @@ class uWSGIMixin(Mixin):
self.cache = uWSGICache
timedelta = conf.getint("moderation", "purge-after")
purge = lambda signum: self.db.comments.purge(timedelta)
def purge(signum):
return self.db.comments.purge(timedelta)
uwsgi.register_signal(1, "", purge)
uwsgi.add_timer(1, timedelta)

@ -0,0 +1,134 @@
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
h1, h2, h3, h4, h5, h6 {
font-style: normal;
font-weight: normal;
}
input {
text-align: center;
}
.header::before, .header::after {
content: " ";
display: table;
}
.header::after {
clear: both;
}
.header::before, .header::after {
content: " ";
display: table;
}
.header {
margin-left: auto;
margin-right: auto;
max-width: 68em;
padding-bottom: 1em;
padding-top: 1em;
}
.header header {
display: block;
float: left;
font-weight: normal;
margin-right: 16.0363%;
width: 41.9818%;
}
.header header .logo {
float: left;
max-height: 60px;
padding-right: 12px;
}
.header header h1 {
font-size: 1.55em;
margin-bottom: 0.3em;
}
.header header h2 {
font-size: 1.05em;
}
.header a, .header a:visited {
color: #4d4c4c;
text-decoration: none;
}
.outer {
background-color: #eeeeee;
box-shadow: 0 0 0.5em #c0c0c0 inset;
}
.outer .filters::before, .outer .filters::after {
content: " ";
display: table;
}
.outer .filters::after {
clear: both;
}
.outer .filters::before, .outer .filters::after {
content: " ";
display: table;
}
.outer .filters {
margin-left: auto;
margin-right: auto;
max-width: 68em;
padding: 1em;
}
a {
text-decoration: none;
color: #4d4c4c;
}
.label {
background-color: #ddd;
border: 1px solid #ccc;
border-radius: 2px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
cursor: pointer;
line-height: 1.4em;
outline: 0 none;
padding: calc(0.6em - 1px);
}
.active {
box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.6) inset;
}
.label-valid {
background-color: #cfc;
border-color: #cfc;
}
.label-pending {
background-color: #ffc;
border-color: #ffc;
}
.mode {
float: left;
}
.pagination {
float: right;
}
.note .label {
margin: 9px;
padding: 3px;
}
#login {
margin-top: 40px;
text-align: center;
width: 100%;
}
.isso-comment-footer a {
cursor: pointer;
}
.thread-title {
margin-left: 3em;
}
.group {
float: left;
margin-left: 2em;
}
.editable {
border: 1px solid #aaa;
border-radius: 5px;
margin: 10px;
padding: 5px;
}
.hidden {
display: none;
}

@ -1,13 +0,0 @@
//************************************************************************//
// These mixins/functions are deprecated
// They will be removed in the next MAJOR version release
//************************************************************************//
@mixin box-shadow ($shadows...) {
@include prefixer(box-shadow, $shadows, spec);
@warn "box-shadow is deprecated and will be removed in the next major version release";
}
@mixin background-size ($lengths...) {
@include prefixer(background-size, $lengths, spec);
@warn "background-size is deprecated and will be removed in the next major version release";
}

@ -1,59 +0,0 @@
// Custom Helpers
@import "helpers/deprecated-webkit-gradient";
@import "helpers/gradient-positions-parser";
@import "helpers/linear-positions-parser";
@import "helpers/radial-arg-parser";
@import "helpers/radial-positions-parser";
@import "helpers/render-gradients";
@import "helpers/shape-size-stripper";
// Custom Functions
@import "functions/compact";
@import "functions/flex-grid";
@import "functions/grid-width";
@import "functions/linear-gradient";
@import "functions/modular-scale";
@import "functions/px-to-em";
@import "functions/radial-gradient";
@import "functions/tint-shade";
@import "functions/transition-property-name";
// CSS3 Mixins
@import "css3/animation";
@import "css3/appearance";
@import "css3/backface-visibility";
@import "css3/background";
@import "css3/background-image";
@import "css3/border-image";
@import "css3/border-radius";
@import "css3/box-sizing";
@import "css3/columns";
@import "css3/flex-box";
@import "css3/font-face";
@import "css3/hidpi-media-query";
@import "css3/image-rendering";
@import "css3/inline-block";
@import "css3/keyframes";
@import "css3/linear-gradient";
@import "css3/perspective";
@import "css3/radial-gradient";
@import "css3/transform";
@import "css3/transition";
@import "css3/user-select";
@import "css3/placeholder";
// Addons & other mixins
@import "addons/button";
@import "addons/clearfix";
@import "addons/font-family";
@import "addons/hide-text";
@import "addons/html5-input-types";
@import "addons/position";
@import "addons/prefixer";
@import "addons/retina-image";
@import "addons/size";
@import "addons/timing-functions";
@import "addons/triangle";
// Soon to be deprecated Mixins
@import "bourbon-deprecated-upcoming";

@ -1,273 +0,0 @@
@mixin button ($style: simple, $base-color: #4294f0) {
@if type-of($style) == color {
$base-color: $style;
$style: simple;
}
// Grayscale button
@if $base-color == grayscale($base-color) {
@if $style == simple {
@include simple($base-color, $grayscale: true);
}
@else if $style == shiny {
@include shiny($base-color, $grayscale: true);
}
@else if $style == pill {
@include pill($base-color, $grayscale: true);
}
}
// Colored button
@else {
@if $style == simple {
@include simple($base-color);
}
@else if $style == shiny {
@include shiny($base-color);
}
@else if $style == pill {
@include pill($base-color);
}
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
// Simple Button
//************************************************************************//
@mixin simple($base-color, $grayscale: false) {
$color: hsl(0, 0, 100%);
$border: adjust-color($base-color, $saturation: 9%, $lightness: -14%);
$inset-shadow: adjust-color($base-color, $saturation: -8%, $lightness: 15%);
$stop-gradient: adjust-color($base-color, $saturation: 9%, $lightness: -11%);
$text-shadow: adjust-color($base-color, $saturation: 15%, $lightness: -18%);
@if lightness($base-color) > 70% {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@if $grayscale == true {
$border: grayscale($border);
$inset-shadow: grayscale($inset-shadow);
$stop-gradient: grayscale($stop-gradient);
$text-shadow: grayscale($text-shadow);
}
border: 1px solid $border;
border-radius: 3px;
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
font-size: 11px;
font-weight: bold;
@include linear-gradient ($base-color, $stop-gradient);
padding: 7px 18px;
text-decoration: none;
text-shadow: 0 1px 0 $text-shadow;
background-clip: padding-box;
&:hover:not(:disabled) {
$base-color-hover: adjust-color($base-color, $saturation: -4%, $lightness: -5%);
$inset-shadow-hover: adjust-color($base-color, $saturation: -7%, $lightness: 5%);
$stop-gradient-hover: adjust-color($base-color, $saturation: 8%, $lightness: -14%);
@if $grayscale == true {
$base-color-hover: grayscale($base-color-hover);
$inset-shadow-hover: grayscale($inset-shadow-hover);
$stop-gradient-hover: grayscale($stop-gradient-hover);
}
box-shadow: inset 0 1px 0 0 $inset-shadow-hover;
cursor: pointer;
@include linear-gradient ($base-color-hover, $stop-gradient-hover);
}
&:active:not(:disabled) {
$border-active: adjust-color($base-color, $saturation: 9%, $lightness: -14%);
$inset-shadow-active: adjust-color($base-color, $saturation: 7%, $lightness: -17%);
@if $grayscale == true {
$border-active: grayscale($border-active);
$inset-shadow-active: grayscale($inset-shadow-active);
}
border: 1px solid $border-active;
box-shadow: inset 0 0 8px 4px $inset-shadow-active, inset 0 0 8px 4px $inset-shadow-active, 0 1px 1px 0 #eee;
}
}
// Shiny Button
//************************************************************************//
@mixin shiny($base-color, $grayscale: false) {
$color: hsl(0, 0, 100%);
$border: adjust-color($base-color, $red: -117, $green: -111, $blue: -81);
$border-bottom: adjust-color($base-color, $red: -126, $green: -127, $blue: -122);
$fourth-stop: adjust-color($base-color, $red: -79, $green: -70, $blue: -46);
$inset-shadow: adjust-color($base-color, $red: 37, $green: 29, $blue: 12);
$second-stop: adjust-color($base-color, $red: -56, $green: -50, $blue: -33);
$text-shadow: adjust-color($base-color, $red: -140, $green: -141, $blue: -114);
$third-stop: adjust-color($base-color, $red: -86, $green: -75, $blue: -48);
@if lightness($base-color) > 70% {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@if $grayscale == true {
$border: grayscale($border);
$border-bottom: grayscale($border-bottom);
$fourth-stop: grayscale($fourth-stop);
$inset-shadow: grayscale($inset-shadow);
$second-stop: grayscale($second-stop);
$text-shadow: grayscale($text-shadow);
$third-stop: grayscale($third-stop);
}
border: 1px solid $border;
border-bottom: 1px solid $border-bottom;
border-radius: 5px;
box-shadow: inset 0 1px 0 0 $inset-shadow;
color: $color;
display: inline-block;
font-size: 14px;
font-weight: bold;
@include linear-gradient(top, $base-color 0%, $second-stop 50%, $third-stop 50%, $fourth-stop 100%);
padding: 8px 20px;
text-align: center;
text-decoration: none;
text-shadow: 0 -1px 1px $text-shadow;
&:hover:not(:disabled) {
$first-stop-hover: adjust-color($base-color, $red: -13, $green: -15, $blue: -18);
$second-stop-hover: adjust-color($base-color, $red: -66, $green: -62, $blue: -51);
$third-stop-hover: adjust-color($base-color, $red: -93, $green: -85, $blue: -66);
$fourth-stop-hover: adjust-color($base-color, $red: -86, $green: -80, $blue: -63);
@if $grayscale == true {
$first-stop-hover: grayscale($first-stop-hover);
$second-stop-hover: grayscale($second-stop-hover);
$third-stop-hover: grayscale($third-stop-hover);
$fourth-stop-hover: grayscale($fourth-stop-hover);
}
cursor: pointer;
@include linear-gradient(top, $first-stop-hover 0%,
$second-stop-hover 50%,
$third-stop-hover 50%,
$fourth-stop-hover 100%);
}
&:active:not(:disabled) {
$inset-shadow-active: adjust-color($base-color, $red: -111, $green: -116, $blue: -122);
@if $grayscale == true {
$inset-shadow-active: grayscale($inset-shadow-active);
}
box-shadow: inset 0 0 20px 0 $inset-shadow-active, 0 1px 0 #fff;
}
}
// Pill Button
//************************************************************************//
@mixin pill($base-color, $grayscale: false) {
$color: hsl(0, 0, 100%);
$border-bottom: adjust-color($base-color, $hue: 8, $saturation: -11%, $lightness: -26%);
$border-sides: adjust-color($base-color, $hue: 4, $saturation: -21%, $lightness: -21%);
$border-top: adjust-color($base-color, $hue: -1, $saturation: -30%, $lightness: -15%);
$inset-shadow: adjust-color($base-color, $hue: -1, $saturation: -1%, $lightness: 7%);
$stop-gradient: adjust-color($base-color, $hue: 8, $saturation: 14%, $lightness: -10%);
$text-shadow: adjust-color($base-color, $hue: 5, $saturation: -19%, $lightness: -15%);
@if lightness($base-color) > 70% {
$color: hsl(0, 0, 20%);
$text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%);
}
@if $grayscale == true {
$border-bottom: grayscale($border-bottom);
$border-sides: grayscale($border-sides);
$border-top: grayscale($border-top);
$inset-shadow: grayscale($inset-shadow);
$stop-gradient: grayscale($stop-gradient);
$text-shadow: grayscale($text-shadow);
}
border: 1px solid $border-top;
border-color: $border-top $border-sides $border-bottom;
border-radius: 16px;
box-shadow: inset 0 1px 0 0 $inset-shadow, 0 1px 2px 0 #b3b3b3;
color: $color;
display: inline-block;
font-size: 11px;
font-weight: normal;
line-height: 1;
@include linear-gradient ($base-color, $stop-gradient);
padding: 5px 16px;
text-align: center;
text-decoration: none;
text-shadow: 0 -1px 1px $text-shadow;
background-clip: padding-box;
&:hover:not(:disabled) {
$base-color-hover: adjust-color($base-color, $lightness: -4.5%);
$border-bottom: adjust-color($base-color, $hue: 8, $saturation: 13.5%, $lightness: -32%);
$border-sides: adjust-color($base-color, $hue: 4, $saturation: -2%, $lightness: -27%);
$border-top: adjust-color($base-color, $hue: -1, $saturation: -17%, $lightness: -21%);
$inset-shadow-hover: adjust-color($base-color, $saturation: -1%, $lightness: 3%);
$stop-gradient-hover: adjust-color($base-color, $hue: 8, $saturation: -4%, $lightness: -15.5%);
$text-shadow-hover: adjust-color($base-color, $hue: 5, $saturation: -5%, $lightness: -22%);
@if $grayscale == true {
$base-color-hover: grayscale($base-color-hover);
$border-bottom: grayscale($border-bottom);
$border-sides: grayscale($border-sides);
$border-top: grayscale($border-top);
$inset-shadow-hover: grayscale($inset-shadow-hover);
$stop-gradient-hover: grayscale($stop-gradient-hover);
$text-shadow-hover: grayscale($text-shadow-hover);
}
border: 1px solid $border-top;
border-color: $border-top $border-sides $border-bottom;
box-shadow: inset 0 1px 0 0 $inset-shadow-hover;
cursor: pointer;
@include linear-gradient ($base-color-hover, $stop-gradient-hover);
text-shadow: 0 -1px 1px $text-shadow-hover;
background-clip: padding-box;
}
&:active:not(:disabled) {
$active-color: adjust-color($base-color, $hue: 4, $saturation: -12%, $lightness: -10%);
$border-active: adjust-color($base-color, $hue: 6, $saturation: -2.5%, $lightness: -30%);
$border-bottom-active: adjust-color($base-color, $hue: 11, $saturation: 6%, $lightness: -31%);
$inset-shadow-active: adjust-color($base-color, $hue: 9, $saturation: 2%, $lightness: -21.5%);
$text-shadow-active: adjust-color($base-color, $hue: 5, $saturation: -12%, $lightness: -21.5%);
@if $grayscale == true {
$active-color: grayscale($active-color);
$border-active: grayscale($border-active);
$border-bottom-active: grayscale($border-bottom-active);
$inset-shadow-active: grayscale($inset-shadow-active);
$text-shadow-active: grayscale($text-shadow-active);
}
background: $active-color;
border: 1px solid $border-active;
border-bottom: 1px solid $border-bottom-active;
box-shadow: inset 0 0 6px 3px $inset-shadow-active, 0 1px 0 0 #fff;
text-shadow: 0 -1px 1px $text-shadow-active;
}
}

@ -1,29 +0,0 @@
// Micro clearfix provides an easy way to contain floats without adding additional markup
//
// Example usage:
//
// // Contain all floats within .wrapper
// .wrapper {
// @include clearfix;
// .content,
// .sidebar {
// float : left;
// }
// }
@mixin clearfix {
*zoom: 1;
&:before,
&:after {
content: " ";
display: table;
}
&:after {
clear: both;
}
}
// Acknowledgements
// Micro clearfix: [Nicolas Gallagher](http://nicolasgallagher.com/micro-clearfix-hack/)

@ -1,5 +0,0 @@
$georgia: Georgia, Cambria, "Times New Roman", Times, serif;
$helvetica: "Helvetica Neue", Helvetica, Arial, sans-serif;
$lucida-grande: "Lucida Grande", Tahoma, Verdana, Arial, sans-serif;
$monospace: "Bitstream Vera Sans Mono", Consolas, Courier, monospace;
$verdana: Verdana, Geneva, sans-serif;

@ -1,5 +0,0 @@
@mixin hide-text {
color: transparent;
font: 0/0 a;
text-shadow: none;
}

@ -1,56 +0,0 @@
//************************************************************************//
// Generate a variable ($all-text-inputs) with a list of all html5
// input types that have a text-based input, excluding textarea.
// http://diveintohtml5.org/forms.html
//************************************************************************//
$inputs-list: 'input[type="email"]',
'input[type="number"]',
'input[type="password"]',
'input[type="search"]',
'input[type="tel"]',
'input[type="text"]',
'input[type="url"]',
// Webkit & Gecko may change the display of these in the future
'input[type="color"]',
'input[type="date"]',
'input[type="datetime"]',
'input[type="datetime-local"]',
'input[type="month"]',
'input[type="time"]',
'input[type="week"]';
$unquoted-inputs-list: ();
@each $input-type in $inputs-list {
$unquoted-inputs-list: append($unquoted-inputs-list, unquote($input-type), comma);
}
$all-text-inputs: $unquoted-inputs-list;
// Hover Pseudo-class
//************************************************************************//
$all-text-inputs-hover: ();
@each $input-type in $unquoted-inputs-list {
$input-type-hover: $input-type + ":hover";
$all-text-inputs-hover: append($all-text-inputs-hover, $input-type-hover, comma);
}
// Focus Pseudo-class
//************************************************************************//
$all-text-inputs-focus: ();
@each $input-type in $unquoted-inputs-list {
$input-type-focus: $input-type + ":focus";
$all-text-inputs-focus: append($all-text-inputs-focus, $input-type-focus, comma);
}
// You must use interpolation on the variable:
// #{$all-text-inputs}
// #{$all-text-inputs-hover}
// #{$all-text-inputs-focus}
// Example
//************************************************************************//
// #{$all-text-inputs}, textarea {
// border: 1px solid red;
// }

@ -1,42 +0,0 @@
@mixin position ($position: relative, $coordinates: 0 0 0 0) {
@if type-of($position) == list {
$coordinates: $position;
$position: relative;
}
$top: nth($coordinates, 1);
$right: nth($coordinates, 2);
$bottom: nth($coordinates, 3);
$left: nth($coordinates, 4);
position: $position;
@if $top == auto {
top: $top;
}
@else if not(unitless($top)) {
top: $top;
}
@if $right == auto {
right: $right;
}
@else if not(unitless($right)) {
right: $right;
}
@if $bottom == auto {
bottom: $bottom;
}
@else if not(unitless($bottom)) {
bottom: $bottom;
}
@if $left == auto {
left: $left;
}
@else if not(unitless($left)) {
left: $left;
}
}

@ -1,49 +0,0 @@
//************************************************************************//
// Example: @include prefixer(border-radius, $radii, webkit ms spec);
//************************************************************************//
$prefix-for-webkit: true !default;
$prefix-for-mozilla: true !default;
$prefix-for-microsoft: true !default;
$prefix-for-opera: true !default;
$prefix-for-spec: true !default; // required for keyframe mixin
@mixin prefixer ($property, $value, $prefixes) {
@each $prefix in $prefixes {
@if $prefix == webkit {
@if $prefix-for-webkit {
-webkit-#{$property}: $value;
}
}
@else if $prefix == moz {
@if $prefix-for-mozilla {
-moz-#{$property}: $value;
}
}
@else if $prefix == ms {
@if $prefix-for-microsoft {
-ms-#{$property}: $value;
}
}
@else if $prefix == o {
@if $prefix-for-opera {
-o-#{$property}: $value;
}
}
@else if $prefix == spec {
@if $prefix-for-spec {
#{$property}: $value;
}
}
@else {
@warn "Unrecognized prefix: #{$prefix}";
}
}
}
@mixin disable-prefix-for-all() {
$prefix-for-webkit: false;
$prefix-for-mozilla: false;
$prefix-for-microsoft: false;
$prefix-for-opera: false;
$prefix-for-spec: false;
}

@ -1,32 +0,0 @@
@mixin retina-image($filename, $background-size, $extension: png, $retina-filename: null, $asset-pipeline: false) {
@if $asset-pipeline {
background-image: image-url("#{$filename}.#{$extension}");
}
@else {
background-image: url("#{$filename}.#{$extension}");
}
@include hidpi {
@if $asset-pipeline {
@if $retina-filename {
background-image: image-url("#{$retina-filename}.#{$extension}");
}
@else {
background-image: image-url("#{$filename}@2x.#{$extension}");
}
}
@else {
@if $retina-filename {
background-image: url("#{$retina-filename}.#{$extension}");
}
@else {
background-image: url("#{$filename}@2x.#{$extension}");
}
}
background-size: $background-size;
}
}

@ -1,44 +0,0 @@
@mixin size($size) {
@if length($size) == 1 {
@if $size == auto {
width: $size;
height: $size;
}
@else if unitless($size) {
width: $size + px;
height: $size + px;
}
@else if not(unitless($size)) {
width: $size;
height: $size;
}
}
// Width x Height
@if length($size) == 2 {
$width: nth($size, 1);
$height: nth($size, 2);
@if $width == auto {
width: $width;
}
@else if not(unitless($width)) {
width: $width;
}
@else if unitless($width) {
width: $width + px;
}
@if $height == auto {
height: $height;
}
@else if not(unitless($height)) {
height: $height;
}
@else if unitless($height) {
height: $height + px;
}
}
}

@ -1,32 +0,0 @@
// CSS cubic-bezier timing functions. Timing functions courtesy of jquery.easie (github.com/jaukia/easie)
// Timing functions are the same as demo'ed here: http://jqueryui.com/demos/effect/easing.html
// EASE IN
$ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530);
$ease-in-cubic: cubic-bezier(0.550, 0.055, 0.675, 0.190);
$ease-in-quart: cubic-bezier(0.895, 0.030, 0.685, 0.220);
$ease-in-quint: cubic-bezier(0.755, 0.050, 0.855, 0.060);
$ease-in-sine: cubic-bezier(0.470, 0.000, 0.745, 0.715);
$ease-in-expo: cubic-bezier(0.950, 0.050, 0.795, 0.035);
$ease-in-circ: cubic-bezier(0.600, 0.040, 0.980, 0.335);
$ease-in-back: cubic-bezier(0.600, -0.280, 0.735, 0.045);
// EASE OUT
$ease-out-quad: cubic-bezier(0.250, 0.460, 0.450, 0.940);
$ease-out-cubic: cubic-bezier(0.215, 0.610, 0.355, 1.000);
$ease-out-quart: cubic-bezier(0.165, 0.840, 0.440, 1.000);
$ease-out-quint: cubic-bezier(0.230, 1.000, 0.320, 1.000);
$ease-out-sine: cubic-bezier(0.390, 0.575, 0.565, 1.000);
$ease-out-expo: cubic-bezier(0.190, 1.000, 0.220, 1.000);
$ease-out-circ: cubic-bezier(0.075, 0.820, 0.165, 1.000);
$ease-out-back: cubic-bezier(0.175, 0.885, 0.320, 1.275);
// EASE IN OUT
$ease-in-out-quad: cubic-bezier(0.455, 0.030, 0.515, 0.955);
$ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1.000);
$ease-in-out-quart: cubic-bezier(0.770, 0.000, 0.175, 1.000);
$ease-in-out-quint: cubic-bezier(0.860, 0.000, 0.070, 1.000);
$ease-in-out-sine: cubic-bezier(0.445, 0.050, 0.550, 0.950);
$ease-in-out-expo: cubic-bezier(1.000, 0.000, 0.000, 1.000);
$ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.150, 0.860);
$ease-in-out-back: cubic-bezier(0.680, -0.550, 0.265, 1.550);

@ -1,45 +0,0 @@
@mixin triangle ($size, $color, $direction) {
height: 0;
width: 0;
@if ($direction == up) or ($direction == down) or ($direction == right) or ($direction == left) {
border-color: transparent;
border-style: solid;
border-width: $size / 2;
@if $direction == up {
border-bottom-color: $color;
} @else if $direction == right {
border-left-color: $color;
} @else if $direction == down {
border-top-color: $color;
} @else if $direction == left {
border-right-color: $color;
}
}
@else if ($direction == up-right) or ($direction == up-left) {
border-top: $size solid $color;
@if $direction == up-right {
border-left: $size solid transparent;
} @else if $direction == up-left {
border-right: $size solid transparent;
}
}
@else if ($direction == down-right) or ($direction == down-left) {
border-bottom: $size solid $color;
@if $direction == down-right {
border-left: $size solid transparent;
} @else if $direction == down-left {
border-right: $size solid transparent;
}
}
}

@ -1,52 +0,0 @@
// http://www.w3.org/TR/css3-animations/#the-animation-name-property-
// Each of these mixins support comma separated lists of values, which allows different transitions for individual properties to be described in a single style rule. Each value in the list corresponds to the value at that same position in the other properties.
// Official animation shorthand property.
@mixin animation ($animations...) {
@include prefixer(animation, $animations, webkit moz spec);
}
// Individual Animation Properties
@mixin animation-name ($names...) {
@include prefixer(animation-name, $names, webkit moz spec);
}
@mixin animation-duration ($times...) {
@include prefixer(animation-duration, $times, webkit moz spec);
}
@mixin animation-timing-function ($motions...) {
// ease | linear | ease-in | ease-out | ease-in-out
@include prefixer(animation-timing-function, $motions, webkit moz spec);
}
@mixin animation-iteration-count ($values...) {
// infinite | <number>
@include prefixer(animation-iteration-count, $values, webkit moz spec);
}
@mixin animation-direction ($directions...) {
// normal | alternate
@include prefixer(animation-direction, $directions, webkit moz spec);
}
@mixin animation-play-state ($states...) {
// running | paused
@include prefixer(animation-play-state, $states, webkit moz spec);
}
@mixin animation-delay ($times...) {
@include prefixer(animation-delay, $times, webkit moz spec);
}
@mixin animation-fill-mode ($modes...) {
// none | forwards | backwards | both
@include prefixer(animation-fill-mode, $modes, webkit moz spec);
}

@ -1,3 +0,0 @@
@mixin appearance ($value) {
@include prefixer(appearance, $value, webkit moz ms o spec);
}

@ -1,6 +0,0 @@
//************************************************************************//
// Backface-visibility mixin
//************************************************************************//
@mixin backface-visibility($visibility) {
@include prefixer(backface-visibility, $visibility, webkit spec);
}

@ -1,48 +0,0 @@
//************************************************************************//
// Background-image property for adding multiple background images with
// gradients, or for stringing multiple gradients together.
//************************************************************************//
@mixin background-image($images...) {
background-image: _add-prefix($images, webkit);
background-image: _add-prefix($images);
}
@function _add-prefix($images, $vendor: false) {
$images-prefixed: ();
$gradient-positions: false;
@for $i from 1 through length($images) {
$type: type-of(nth($images, $i)); // Get type of variable - List or String
// If variable is a list - Gradient
@if $type == list {
$gradient-type: nth(nth($images, $i), 1); // linear or radial
$gradient-pos: null;
$gradient-args: null;
@if ($gradient-type == linear) or ($gradient-type == radial) {
$gradient-pos: nth(nth($images, $i), 2); // Get gradient position
$gradient-args: nth(nth($images, $i), 3); // Get actual gradient (red, blue)
}
@else {
$gradient-args: nth(nth($images, $i), 2); // Get actual gradient (red, blue)
}
$gradient-positions: _gradient-positions-parser($gradient-type, $gradient-pos);
$gradient: _render-gradients($gradient-positions, $gradient-args, $gradient-type, $vendor);
$images-prefixed: append($images-prefixed, $gradient, comma);
}
// If variable is a string - Image
@else if $type == string {
$images-prefixed: join($images-prefixed, nth($images, $i), comma);
}
}
@return $images-prefixed;
}
//Examples:
//@include background-image(linear-gradient(top, orange, red));
//@include background-image(radial-gradient(50% 50%, cover circle, orange, red));
//@include background-image(url("/images/a.png"), linear-gradient(orange, red));
//@include background-image(url("image.png"), linear-gradient(orange, red), url("image.png"));
//@include background-image(linear-gradient(hsla(0, 100%, 100%, 0.25) 0%, hsla(0, 100%, 100%, 0.08) 50%, transparent 50%), linear-gradient(orange, red));

@ -1,103 +0,0 @@
//************************************************************************//
// Background property for adding multiple backgrounds using shorthand
// notation.
//************************************************************************//
@mixin background(
$background-1 , $background-2: false,
$background-3: false, $background-4: false,
$background-5: false, $background-6: false,
$background-7: false, $background-8: false,
$background-9: false, $background-10: false,
$fallback: false
) {
$backgrounds: compact($background-1, $background-2,
$background-3, $background-4,
$background-5, $background-6,
$background-7, $background-8,
$background-9, $background-10);
$fallback-color: false;
@if (type-of($fallback) == color) or ($fallback == "transparent") {
$fallback-color: $fallback;
}
@else {
$fallback-color: _extract-background-color($backgrounds);
}
@if $fallback-color {
background-color: $fallback-color;
}
background: _background-add-prefix($backgrounds, webkit);
background: _background-add-prefix($backgrounds);
}
@function _extract-background-color($backgrounds) {
$final-bg-layer: nth($backgrounds, length($backgrounds));
@if type-of($final-bg-layer) == list {
@for $i from 1 through length($final-bg-layer) {
$value: nth($final-bg-layer, $i);
@if type-of($value) == color {
@return $value;
}
}
}
@return false;
}
@function _background-add-prefix($backgrounds, $vendor: false) {
$backgrounds-prefixed: ();
@for $i from 1 through length($backgrounds) {
$shorthand: nth($backgrounds, $i); // Get member for current index
$type: type-of($shorthand); // Get type of variable - List (gradient) or String (image)
// If shorthand is a list (gradient)
@if $type == list {
$first-member: nth($shorthand, 1); // Get first member of shorthand
// Linear Gradient
@if index(linear radial, nth($first-member, 1)) {
$gradient-type: nth($first-member, 1); // linear || radial
$gradient-args: false;
$gradient-positions: false;
$shorthand-start: false;
@if type-of($first-member) == list { // Linear gradient plus additional shorthand values - lg(red,orange)repeat,...
$gradient-positions: nth($first-member, 2);
$gradient-args: nth($first-member, 3);
$shorthand-start: 2;
}
@else { // Linear gradient only - lg(red,orange),...
$gradient-positions: nth($shorthand, 2);
$gradient-args: nth($shorthand, 3); // Get gradient (red, blue)
}
$gradient-positions: _gradient-positions-parser($gradient-type, $gradient-positions);
$gradient: _render-gradients($gradient-positions, $gradient-args, $gradient-type, $vendor);
// Append any additional shorthand args to gradient
@if $shorthand-start {
@for $j from $shorthand-start through length($shorthand) {
$gradient: join($gradient, nth($shorthand, $j), space);
}
}
$backgrounds-prefixed: append($backgrounds-prefixed, $gradient, comma);
}
// Image with additional properties
@else {
$backgrounds-prefixed: append($backgrounds-prefixed, $shorthand, comma);
}
}
// If shorthand is a simple string (color or image)
@else if $type == string {
$backgrounds-prefixed: join($backgrounds-prefixed, $shorthand, comma);
}
}
@return $backgrounds-prefixed;
}
//Examples:
//@include background(linear-gradient(top, orange, red));
//@include background(radial-gradient(circle at 40% 40%, orange, red));
//@include background(url("/images/a.png") no-repeat, linear-gradient(orange, red));
//@include background(url("image.png") center center, linear-gradient(orange, red), url("image.png"));

@ -1,55 +0,0 @@
@mixin border-image($images) {
-webkit-border-image: _border-add-prefix($images, webkit);
-moz-border-image: _border-add-prefix($images, moz);
-o-border-image: _border-add-prefix($images, o);
border-image: _border-add-prefix($images);
}
@function _border-add-prefix($images, $vendor: false) {
$border-image: null;
$images-type: type-of(nth($images, 1));
$first-var: nth(nth($images, 1), 1); // Get type of Gradient (Linear || radial)
// If input is a gradient
@if $images-type == string {
@if ($first-var == "linear") or ($first-var == "radial") {
$gradient-type: nth($images, 1); // Get type of gradient (linear || radial)
$gradient-pos: nth($images, 2); // Get gradient position
$gradient-args: nth($images, 3); // Get actual gradient (red, blue)
$gradient-positions: _gradient-positions-parser($gradient-type, $gradient-pos);
$border-image: _render-gradients($gradient-positions, $gradient-args, $gradient-type, $vendor);
}
// If input is a URL
@else {
$border-image: $images;
}
}
// If input is gradient or url + additional args
@else if $images-type == list {
$type: type-of(nth($images, 1)); // Get type of variable - List or String
// If variable is a list - Gradient
@if $type == list {
$gradient: nth($images, 1);
$gradient-type: nth($gradient, 1); // Get type of gradient (linear || radial)
$gradient-pos: nth($gradient, 2); // Get gradient position
$gradient-args: nth($gradient, 3); // Get actual gradient (red, blue)
$gradient-positions: _gradient-positions-parser($gradient-type, $gradient-pos);
$border-image: _render-gradients($gradient-positions, $gradient-args, $gradient-type, $vendor);
@for $i from 2 through length($images) {
$border-image: append($border-image, nth($images, $i));
}
}
}
@return $border-image;
}
//Examples:
// @include border-image(url("image.png"));
// @include border-image(url("image.png") 20 stretch);
// @include border-image(linear-gradient(45deg, orange, yellow));
// @include border-image(linear-gradient(45deg, orange, yellow) stretch);
// @include border-image(linear-gradient(45deg, orange, yellow) 20 30 40 50 stretch round);
// @include border-image(radial-gradient(top, cover, orange, yellow, orange));

@ -1,22 +0,0 @@
//************************************************************************//
// Shorthand Border-radius mixins
//************************************************************************//
@mixin border-top-radius($radii) {
@include prefixer(border-top-left-radius, $radii, spec);
@include prefixer(border-top-right-radius, $radii, spec);
}
@mixin border-bottom-radius($radii) {
@include prefixer(border-bottom-left-radius, $radii, spec);
@include prefixer(border-bottom-right-radius, $radii, spec);
}
@mixin border-left-radius($radii) {
@include prefixer(border-top-left-radius, $radii, spec);
@include prefixer(border-bottom-left-radius, $radii, spec);
}
@mixin border-right-radius($radii) {
@include prefixer(border-top-right-radius, $radii, spec);
@include prefixer(border-bottom-right-radius, $radii, spec);
}

@ -1,4 +0,0 @@
@mixin box-sizing ($box) {
// content-box | border-box | inherit
@include prefixer(box-sizing, $box, webkit moz spec);
}

@ -1,47 +0,0 @@
@mixin columns($arg: auto) {
// <column-count> || <column-width>
@include prefixer(columns, $arg, webkit moz spec);
}
@mixin column-count($int: auto) {
// auto || integer
@include prefixer(column-count, $int, webkit moz spec);
}
@mixin column-gap($length: normal) {
// normal || length
@include prefixer(column-gap, $length, webkit moz spec);
}
@mixin column-fill($arg: auto) {
// auto || length
@include prefixer(columns-fill, $arg, webkit moz spec);
}
@mixin column-rule($arg) {
// <border-width> || <border-style> || <color>
@include prefixer(column-rule, $arg, webkit moz spec);
}
@mixin column-rule-color($color) {
@include prefixer(column-rule-color, $color, webkit moz spec);
}
@mixin column-rule-style($style: none) {
// none | hidden | dashed | dotted | double | groove | inset | inset | outset | ridge | solid
@include prefixer(column-rule-style, $style, webkit moz spec);
}
@mixin column-rule-width ($width: none) {
@include prefixer(column-rule-width, $width, webkit moz spec);
}
@mixin column-span($arg: none) {
// none || all
@include prefixer(column-span, $arg, webkit moz spec);
}
@mixin column-width($length: auto) {
// auto || length
@include prefixer(column-width, $length, webkit moz spec);
}

@ -1,52 +0,0 @@
// CSS3 Flexible Box Model and property defaults
// Custom shorthand notation for flexbox
@mixin box($orient: inline-axis, $pack: start, $align: stretch) {
@include display-box;
@include box-orient($orient);
@include box-pack($pack);
@include box-align($align);
}
@mixin display-box {
display: -webkit-box;
display: -moz-box;
display: box;
}
@mixin box-orient($orient: inline-axis) {
// horizontal|vertical|inline-axis|block-axis|inherit
@include prefixer(box-orient, $orient, webkit moz spec);
}
@mixin box-pack($pack: start) {
// start|end|center|justify
@include prefixer(box-pack, $pack, webkit moz spec);
}
@mixin box-align($align: stretch) {
// start|end|center|baseline|stretch
@include prefixer(box-align, $align, webkit moz spec);
}
@mixin box-direction($direction: normal) {
// normal|reverse|inherit
@include prefixer(box-direction, $direction, webkit moz spec);
}
@mixin box-lines($lines: single) {
// single|multiple
@include prefixer(box-lines, $lines, webkit moz spec);
}
@mixin box-ordinal-group($int: 1) {
@include prefixer(box-ordinal-group, $int, webkit moz spec);
}
@mixin box-flex($value: 0.0) {
@include prefixer(box-flex, $value, webkit moz spec);
}
@mixin box-flex-group($int: 1) {
@include prefixer(box-flex-group, $int, webkit moz spec);
}

@ -1,23 +0,0 @@
// Order of the includes matters, and it is: normal, bold, italic, bold+italic.
@mixin font-face($font-family, $file-path, $weight: normal, $style: normal, $asset-pipeline: false ) {
@font-face {
font-family: $font-family;
font-weight: $weight;
font-style: $style;
@if $asset-pipeline == true {
src: font-url('#{$file-path}.eot');
src: font-url('#{$file-path}.eot?#iefix') format('embedded-opentype'),
font-url('#{$file-path}.woff') format('woff'),
font-url('#{$file-path}.ttf') format('truetype'),
font-url('#{$file-path}.svg##{$font-family}') format('svg');
} @else {
src: url('#{$file-path}.eot');
src: url('#{$file-path}.eot?#iefix') format('embedded-opentype'),
url('#{$file-path}.woff') format('woff'),
url('#{$file-path}.ttf') format('truetype'),
url('#{$file-path}.svg##{$font-family}') format('svg');
}
}
}

@ -1,10 +0,0 @@
// HiDPI mixin. Default value set to 1.3 to target Google Nexus 7 (http://bjango.com/articles/min-device-pixel-ratio/)
@mixin hidpi($ratio: 1.3) {
@media only screen and (-webkit-min-device-pixel-ratio: $ratio),
only screen and (min--moz-device-pixel-ratio: $ratio),
only screen and (-o-min-device-pixel-ratio: #{$ratio}/1),
only screen and (min-resolution: #{round($ratio*96)}dpi),
only screen and (min-resolution: #{$ratio}dppx) {
@content;
}
}

@ -1,13 +0,0 @@
@mixin image-rendering ($mode:optimizeQuality) {
@if ($mode == optimize-contrast) {
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: optimize-contrast;
}
@else {
image-rendering: $mode;
}
}

@ -1,8 +0,0 @@
// Legacy support for inline-block in IE7 (maybe IE6)
@mixin inline-block {
display: inline-block;
vertical-align: baseline;
zoom: 1;
*display: inline;
*vertical-align: auto;
}

@ -1,43 +0,0 @@
// Adds keyframes blocks for supported prefixes, removing redundant prefixes in the block's content
@mixin keyframes($name) {
$original-prefix-for-webkit: $prefix-for-webkit;
$original-prefix-for-mozilla: $prefix-for-mozilla;
$original-prefix-for-microsoft: $prefix-for-microsoft;
$original-prefix-for-opera: $prefix-for-opera;
$original-prefix-for-spec: $prefix-for-spec;
@if $original-prefix-for-webkit {
@include disable-prefix-for-all();
$prefix-for-webkit: true;
@-webkit-keyframes #{$name} {
@content;
}
}
@if $original-prefix-for-mozilla {
@include disable-prefix-for-all();
$prefix-for-mozilla: true;
@-moz-keyframes #{$name} {
@content;
}
}
@if $original-prefix-for-opera {
@include disable-prefix-for-all();
$prefix-for-opera: true;
@-o-keyframes #{$name} {
@content;
}
}
@if $original-prefix-for-spec {
@include disable-prefix-for-all();
$prefix-for-spec: true;
@keyframes #{$name} {
@content;
}
}
$prefix-for-webkit: $original-prefix-for-webkit;
$prefix-for-mozilla: $original-prefix-for-mozilla;
$prefix-for-microsoft: $original-prefix-for-microsoft;
$prefix-for-opera: $original-prefix-for-opera;
$prefix-for-spec: $original-prefix-for-spec;
}

@ -1,41 +0,0 @@
@mixin linear-gradient($pos, $G1, $G2: false,
$G3: false, $G4: false,
$G5: false, $G6: false,
$G7: false, $G8: false,
$G9: false, $G10: false,
$deprecated-pos1: left top,
$deprecated-pos2: left bottom,
$fallback: false) {
// Detect what type of value exists in $pos
$pos-type: type-of(nth($pos, 1));
$pos-spec: null;
$pos-degree: null;
// If $pos is missing from mixin, reassign vars and add default position
@if ($pos-type == color) or (nth($pos, 1) == "transparent") {
$G10: $G9; $G9: $G8; $G8: $G7; $G7: $G6; $G6: $G5;
$G5: $G4; $G4: $G3; $G3: $G2; $G2: $G1; $G1: $pos;
$pos: null;
}
@if $pos {
$positions: _linear-positions-parser($pos);
$pos-degree: nth($positions, 1);
$pos-spec: nth($positions, 2);
}
$full: compact($G1, $G2, $G3, $G4, $G5, $G6, $G7, $G8, $G9, $G10);
// Set $G1 as the default fallback color
$fallback-color: nth($G1, 1);
// If $fallback is a color use that color as the fallback color
@if (type-of($fallback) == color) or ($fallback == "transparent") {
$fallback-color: $fallback;
}
background-color: $fallback-color;
background-image: _deprecated-webkit-gradient(linear, $deprecated-pos1, $deprecated-pos2, $full); // Safari <= 5.0
background-image: -webkit-linear-gradient($pos-degree $full); // Safari 5.1+, Chrome
background-image: unquote("linear-gradient(#{$pos-spec}#{$full})");
}

@ -1,8 +0,0 @@
@mixin perspective($depth: none) {
// none | <length>
@include prefixer(perspective, $depth, webkit moz spec);
}
@mixin perspective-origin($value: 50% 50%) {
@include prefixer(perspective-origin, $value, webkit moz spec);
}

@ -1,29 +0,0 @@
$placeholders: '-webkit-input-placeholder',
'-moz-placeholder',
'-ms-input-placeholder';
@mixin placeholder {
@each $placeholder in $placeholders {
@if $placeholder == "-webkit-input-placeholder" {
&::#{$placeholder} {
@content;
}
}
@else if $placeholder == "-moz-placeholder" {
// FF 18-
&:#{$placeholder} {
@content;
}
// FF 19+
&::#{$placeholder} {
@content;
}
}
@else {
&:#{$placeholder} {
@content;
}
}
}
}

@ -1,44 +0,0 @@
// Requires Sass 3.1+
@mixin radial-gradient($G1, $G2,
$G3: false, $G4: false,
$G5: false, $G6: false,
$G7: false, $G8: false,
$G9: false, $G10: false,
$pos: null,
$shape-size: null,
$deprecated-pos1: center center,
$deprecated-pos2: center center,
$deprecated-radius1: 0,
$deprecated-radius2: 460,
$fallback: false) {
$data: _radial-arg-parser($G1, $G2, $pos, $shape-size);
$G1: nth($data, 1);
$G2: nth($data, 2);
$pos: nth($data, 3);
$shape-size: nth($data, 4);
$full: compact($G1, $G2, $G3, $G4, $G5, $G6, $G7, $G8, $G9, $G10);
// Strip deprecated cover/contain for spec
$shape-size-spec: _shape-size-stripper($shape-size);
// Set $G1 as the default fallback color
$first-color: nth($full, 1);
$fallback-color: nth($first-color, 1);
@if (type-of($fallback) == color) or ($fallback == "transparent") {
$fallback-color: $fallback;
}
// Add Commas and spaces
$shape-size: if($shape-size, '#{$shape-size}, ', null);
$pos: if($pos, '#{$pos}, ', null);
$pos-spec: if($pos, 'at #{$pos}', null);
$shape-size-spec: if(($shape-size-spec != ' ') and ($pos == null), '#{$shape-size-spec}, ', '#{$shape-size-spec} ');
background-color: $fallback-color;
background-image: _deprecated-webkit-gradient(radial, $deprecated-pos1, $deprecated-pos2, $full, $deprecated-radius1, $deprecated-radius2); // Safari <= 5.0 && IOS 4
background-image: -webkit-radial-gradient(unquote(#{$pos}#{$shape-size}#{$full}));
background-image: unquote("radial-gradient(#{$shape-size-spec}#{$pos-spec}#{$full})");
}

@ -1,15 +0,0 @@
@mixin transform($property: none) {
// none | <transform-function>
@include prefixer(transform, $property, webkit moz ms o spec);
}
@mixin transform-origin($axes: 50%) {
// x-axis - left | center | right | length | %
// y-axis - top | center | bottom | length | %
// z-axis - length
@include prefixer(transform-origin, $axes, webkit moz ms o spec);
}
@mixin transform-style ($style: flat) {
@include prefixer(transform-style, $style, webkit moz ms o spec);
}

@ -1,34 +0,0 @@
// Shorthand mixin. Supports multiple parentheses-deliminated values for each variable.
// Example: @include transition (all, 2.0s, ease-in-out);
// @include transition ((opacity, width), (1.0s, 2.0s), ease-in, (0, 2s));
// @include transition ($property:(opacity, width), $delay: (1.5s, 2.5s));
@mixin transition ($properties...) {
@if length($properties) >= 1 {
@include prefixer(transition, $properties, webkit moz spec);
}
@else {
$properties: all 0.15s ease-out 0;
@include prefixer(transition, $properties, webkit moz spec);
}
}
@mixin transition-property ($properties...) {
-webkit-transition-property: transition-property-names($properties, 'webkit');
-moz-transition-property: transition-property-names($properties, 'moz');
transition-property: transition-property-names($properties, false);
}
@mixin transition-duration ($times...) {
@include prefixer(transition-duration, $times, webkit moz spec);
}
@mixin transition-timing-function ($motions...) {
// ease | linear | ease-in | ease-out | ease-in-out | cubic-bezier()
@include prefixer(transition-timing-function, $motions, webkit moz spec);
}
@mixin transition-delay ($times...) {
@include prefixer(transition-delay, $times, webkit moz spec);
}

@ -1,3 +0,0 @@
@mixin user-select($arg: none) {
@include prefixer(user-select, $arg, webkit moz ms spec);
}

@ -1,11 +0,0 @@
// Remove `false` values from a list
@function compact($vars...) {
$list: ();
@each $var in $vars {
@if $var {
$list: append($list, $var, comma);
}
}
@return $list;
}

@ -1,39 +0,0 @@
// Flexible grid
@function flex-grid($columns, $container-columns: $fg-max-columns) {
$width: $columns * $fg-column + ($columns - 1) * $fg-gutter;
$container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter;
@return percentage($width / $container-width);
}
// Flexible gutter
@function flex-gutter($container-columns: $fg-max-columns, $gutter: $fg-gutter) {
$container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter;
@return percentage($gutter / $container-width);
}
// The $fg-column, $fg-gutter and $fg-max-columns variables must be defined in your base stylesheet to properly use the flex-grid function.
// This function takes the fluid grid equation (target / context = result) and uses columns to help define each.
//
// The calculation presumes that your column structure will be missing the last gutter:
//
// -- column -- gutter -- column -- gutter -- column
//
// $fg-column: 60px; // Column Width
// $fg-gutter: 25px; // Gutter Width
// $fg-max-columns: 12; // Total Columns For Main Container
//
// div {
// width: flex-grid(4); // returns (315px / 995px) = 31.65829%;
// margin-left: flex-gutter(); // returns (25px / 995px) = 2.51256%;
//
// p {
// width: flex-grid(2, 4); // returns (145px / 315px) = 46.031746%;
// float: left;
// margin: flex-gutter(4); // returns (25px / 315px) = 7.936508%;
// }
//
// blockquote {
// float: left;
// width: flex-grid(2, 4); // returns (145px / 315px) = 46.031746%;
// }
// }

@ -1,13 +0,0 @@
@function grid-width($n) {
@return $n * $gw-column + ($n - 1) * $gw-gutter;
}
// The $gw-column and $gw-gutter variables must be defined in your base stylesheet to properly use the grid-width function.
//
// $gw-column: 100px; // Column Width
// $gw-gutter: 40px; // Gutter Width
//
// div {
// width: grid-width(4); // returns 520px;
// margin-left: $gw-gutter; // returns 40px;
// }

@ -1,13 +0,0 @@
@function linear-gradient($pos, $gradients...) {
$type: linear;
$pos-type: type-of(nth($pos, 1));
// if $pos doesn't exist, fix $gradient
@if ($pos-type == color) or (nth($pos, 1) == "transparent") {
$gradients: zip($pos $gradients);
$pos: false;
}
$type-gradient: $type, $pos, $gradients;
@return $type-gradient;
}

@ -1,40 +0,0 @@
@function modular-scale($value, $increment, $ratio) {
@if $increment > 0 {
@for $i from 1 through $increment {
$value: ($value * $ratio);
}
}
@if $increment < 0 {
$increment: abs($increment);
@for $i from 1 through $increment {
$value: ($value / $ratio);
}
}
@return $value;
}
// div {
// Increment Up GR with positive value
// font-size: modular-scale(14px, 1, 1.618); // returns: 22.652px
//
// Increment Down GR with negative value
// font-size: modular-scale(14px, -1, 1.618); // returns: 8.653px
//
// Can be used with ceil(round up) or floor(round down)
// font-size: floor( modular-scale(14px, 1, 1.618) ); // returns: 22px
// font-size: ceil( modular-scale(14px, 1, 1.618) ); // returns: 23px
// }
//
// modularscale.com
@function golden-ratio($value, $increment) {
@return modular-scale($value, $increment, 1.618)
}
// div {
// font-size: golden-ratio(14px, 1); // returns: 22.652px
// }
//
// goldenratiocalculator.com

@ -1,8 +0,0 @@
// Convert pixels to ems
// eg. for a relational value of 12px write em(12) when the parent is 16px
// if the parent is another value say 24px write em(12, 24)
@function em($pxval, $base: 16) {
@return ($pxval / $base) * 1em;
}

@ -1,23 +0,0 @@
// This function is required and used by the background-image mixin.
@function radial-gradient($G1, $G2,
$G3: false, $G4: false,
$G5: false, $G6: false,
$G7: false, $G8: false,
$G9: false, $G10: false,
$pos: null,
$shape-size: null) {
$data: _radial-arg-parser($G1, $G2, $pos, $shape-size);
$G1: nth($data, 1);
$G2: nth($data, 2);
$pos: nth($data, 3);
$shape-size: nth($data, 4);
$type: radial;
$gradient: compact($G1, $G2, $G3, $G4, $G5, $G6, $G7, $G8, $G9, $G10);
$type-gradient: $type, $shape-size $pos, $gradient;
@return $type-gradient;
}

@ -1,9 +0,0 @@
// Add percentage of white to a color
@function tint($color, $percent){
@return mix(white, $color, $percent);
}
// Add percentage of black to a color
@function shade($color, $percent){
@return mix(black, $color, $percent);
}

@ -1,22 +0,0 @@
// Return vendor-prefixed property names if appropriate
// Example: transition-property-names((transform, color, background), moz) -> -moz-transform, color, background
//************************************************************************//
@function transition-property-names($props, $vendor: false) {
$new-props: ();
@each $prop in $props {
$new-props: append($new-props, transition-property-name($prop, $vendor), comma);
}
@return $new-props;
}
@function transition-property-name($prop, $vendor: false) {
// put other properties that need to be prefixed here aswell
@if $vendor and $prop == transform {
@return unquote('-'+$vendor+'-'+$prop);
}
@else {
@return $prop;
}
}

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

Loading…
Cancel
Save