Compare commits

...

792 Commits

Author SHA1 Message Date
Tim Abbott
90634356cb Add changelog for Zulip 1.3.12 release. 2016-05-10 09:51:49 -07:00
Tim Abbott
9b65464b6b logout_all_users: Add option to logout deactivated users. 2016-05-10 09:50:57 -07:00
Tim Abbott
393159bbd8 queue: Disable RabbitMQ heartbeat in BlockingConnection.
Fixes #741.
2016-05-10 09:50:57 -07:00
Tim Abbott
6f282581f7 requirements: Upgrade pika to version 0.10.0.
This is needed to fix RabbitMQ heartbeat issues that cause connections
to drop (#741).  It's also relevant for Python 3 support.
2016-05-10 09:50:57 -07:00
Tim Abbott
d82e44ecd0 queue: Refactor Pika credentials code to be a bit cleaner. 2016-05-10 09:50:57 -07:00
Tim Abbott
620debc5fd Change PrincipalError to return status code 403 by default. 2016-05-10 09:50:57 -07:00
Tim Abbott
85c64c9f93 zulip_login_required: Add checks for active users and realms.
Like the recent change blocking JSON endpoints for deactivated users
and users in deactivated realms, this change is a hardening
improvement.  Those users should be unable to get an active session
anyway, but if somehow one is leaked, this means they won't be able to
access any user data.
2016-05-10 09:50:57 -07:00
Tim Abbott
be216506a9 Improve api_fetch_api_key error messages.
Previously, api_fetch_api_key would not give clear error messages if
password auth was disabled or the user's realm had been deactivated;
additionally, the account disabled error stopped triggering when we
moved the active account check into the auth decorators.
2016-05-10 09:50:57 -07:00
Tim Abbott
52ddd500f0 Add tests for authentication backends. 2016-05-10 09:50:57 -07:00
Tim Abbott
38c82083de Add test suite for deactivated users. 2016-05-10 09:50:57 -07:00
Tim Abbott
df7466e893 Add test suite for deactivate realms. 2016-05-10 09:50:57 -07:00
Tim Abbott
76814f37a3 decorators: Block access to JSON endpoints for deactivated users.
While in theory users should be unable to get a valid session in order
to access these endpoints in the first place, this provides an extra
layer of hardering to prevent a deactivated user with a session from
accessing data via the old-style JSON API.
2016-05-10 09:50:57 -07:00
Tim Abbott
b28b3cd65c CVE-2016-4427: Fix access by deactivated realms/users.
The security model for deactivated users (and users in deactivated
realms) being unable to access the service is intended to work via two
mechanisms:

* All active user sessions are deleted, and all login code paths
  (where a user could get a new session) check whether the user (or
  realm) is inactive before authorizing the request, preventing the
  user from accessing the website and AJAX endpoints.
* All API code paths (which don't require a session) check whether the
  user (and realm) are active.

However, this security model was not implemented correctly.  In
particular, the check for whether a user has an active account in the
login process was done inside the login form's validators, which meant
that authentication mechanisms that did not use the login form
(e.g. Google and REMOTE_USER auth) could succeed in granting a session
even with an inactive account.  The Zulip homepage would still fail to
load because the code for / includes an API call to Tornado authorized
by the user's token that would fail, but this mechanism could allow an
inactive user to access realm data or users to access data in a
deactivated realm.

This fixes the issue by adding explicit checks for inactive users and
inactive realms in all authentication backends (even those that were
already protected by the login form validator).

Mirror dummy users are already inactive, so we can remove the explicit
code around mirror dummy users.

The following commits add a complete set of tests for Zulip's inactive
user and realm security model.
2016-05-10 09:50:48 -07:00
Tim Abbott
b31ac1eca9 Fix users in deactivated realms sending webhook messages.
In a deactivated realm, webhooks would still successfully send
messages, since there was no check for whether the realm was active in
api_key_only_webhook_view.
2016-05-10 09:50:48 -07:00
Tim Abbott
9da73b22d3 assert_json_error_contains: Support passing a status code.
Previously this test helper function hardcoded 400.
2016-05-10 09:50:48 -07:00
Tim Abbott
3cde06ea33 Add support for setting HTTP status codes in JsonableError. 2016-05-10 09:50:48 -07:00
Tim Abbott
b38c50c6bb docs: Document possible auditing features in security model. 2016-05-10 09:50:47 -07:00
Tim Abbott
44fae09a48 docs: Clarify security model around bots and invite-only streams. 2016-05-10 09:50:47 -07:00
Tim Abbott
b4ccca300b Add tests for whether API keys appear in initial state data. 2016-05-10 09:50:47 -07:00
Tim Abbott
07fc47f953 CVE-2016-4426: Fix non-admin users having access to all bot API keys.
Long ago, there was work on an experimental integration model where
every user in a realm would have administrative control over all bots,
with the goal of simplifying the process of setting up communally
administered bots for smaller teams.  While that new model was never
fully implemented (and thus never setup as an option), an error in
that original implementation meant that the data on all bots in a
realm, including their API keys, was sent to the browsers of users via
the `realm_bots` variable in `page_params`.  The data wasn't displayed
in the UI for non-admin users, but was available via e.g. the
javascript console.

This commit updates this behavior to only send sensitive bot data like
API keys to the owner of the bot (and realm admins).

We may in the future implement a model simplifying communally
administered integrations, but if we do that, those bots should be
limited in their capabilities (e.g. only able to send webhook
messages).

This bug has been present since Zulip was released as open source.
2016-05-10 09:50:02 -07:00
Tim Abbott
0161d2fddd Cleanup guardian-based complexity in get_realm_user_dicts.
The old code for this lookup was unnecessarily complicated because we
were working around Guardian, where the `is_realm_admin` check was
extremely expensive.
2016-05-09 10:12:35 -07:00
Tim Abbott
2a2cbd60c3 cache: Fix fragile active_bot_dicts_in_realm caching model.
The issue here is similar to that in the previous commit.
2016-05-09 10:12:35 -07:00
Tim Abbott
fbc7e977ac cache: Fix fragile active_user_dicts_in_realm caching model.
Previously we relied on having two matching list of fields for the
get_active_user_dicts_in_realm, one in the actual code and the other
in the caching system.  By unifying these lists to have a single
source, we eliminate a class of caching bugs we might otherwise
regularly introduce.
2016-05-09 10:12:35 -07:00
Tim Abbott
f02571202a EventsRegisterTest: display full error diffs. 2016-05-09 10:12:35 -07:00
Tim Abbott
5ffe1439eb Add changelog for Zulip 1.3.11 release. 2016-05-02 20:39:51 -07:00
Tim Abbott
d9e4968d6f Increase maximum URL length for RealmEmoji to 1000.
The default of 200 was shorter than the Camo URLs use by Zulip.
2016-05-02 19:02:56 -07:00
Tim Abbott
5bd94c15c7 Use camo to avoid mixed content warnings when displaying emoji. 2016-05-02 17:21:31 -07:00
Tim Abbott
52c1e8ac7d Run a local camo server in voyager production environments.
Camo is a caching image proxy, used in Zulip to avoid mixed-content
warnings by proxying HTTP image content over HTTPS.  We've been using
it in zulip.com production for years; this change makes it available
in standalone Zulip deployments.
2016-05-02 17:21:31 -07:00
Tim Abbott
65207477c4 bugdown: Annotate emoji handleMatch function. 2016-05-02 17:01:09 -07:00
Tim Abbott
4241e01854 realm emoji: Fix realm-time updating of admin emoji table.
Previously the realm emoji table on the admin page didn't update
properly in the event that another user added or removed emoji.
2016-05-02 17:00:47 -07:00
Tim Abbott
48a578d003 travis: hold expensive to upgrade packages in Travis CI.
This should save a few minutes of time running the production test
suite.  This is part of solving #722.
2016-05-02 16:59:21 -07:00
Tim Abbott
79327a61ae travis: Do an apt-get update before the apt upgrade.
This should save several minutes off the Travis CI `production`
suite's runtime, since previously we were doing the full apt upgrade
process twice, resulting in things like multiple expensive rebuilds of
the initramfs.
2016-05-02 16:35:46 -07:00
Eklavya Sharma
27f12b2de3 Annotate tools/lister.py. 2016-05-01 23:04:09 +05:30
Eklavya Sharma
247cdf578b Add dependencies to setup-py3k.
Add 'six' to setup-py3k, because it is being used in tools/lister.py.
Add 'typing' to setup-py3k, so that tools/lister.py can be type
annotated in the future.
2016-05-01 10:47:04 +05:30
Eklavya Sharma
2d3f9c8fb9 tools/lister.py: Use default arguments in add_argument.
Use the `default` parameter of ArgumentParser.add_argument
instead of manually setting default using the `x = x or []` pattern.
2016-05-01 07:01:52 +05:30
Tim Abbott
aa3549097d Mark Docker development instructions as experimental. 2016-04-29 16:15:14 -07:00
Tim Abbott
f06c8c7cc2 Update *.readthedocs.org => *.readthedocs.io.
ReadTheDocs has moved their hosting of user project websites to the
new readthedocs.io domain.
2016-04-29 16:00:08 -07:00
Tim Abbott
4644967afc dropbox preview: Remove preview_fail.png error condition.
Since we don't have a stable way to get the Dropbox preview failure
image (and it was sorta a weird setup anyway), it seems best to just
remove the condition.
2016-04-29 15:40:52 -07:00
Tim Abbott
4be3c4afd6 Use mocks so we can re-enable Dropbox integration tests. 2016-04-29 15:27:43 -07:00
Tim Abbott
8df58432f6 Clear user filter after pressing enter to start compose.
Previously, the user list would remain filtered after a user hit enter
to start composing a message to a user, leaving them in a state with a
partial user list.

Fixes #360.
2016-04-29 15:01:41 -07:00
Ashish Kumar
31408d639e Type annotation of zerver/lib/cache.py. 2016-04-29 14:43:48 -07:00
Tim Abbott
4c3118b39f Document new zulip-ios mailing list. 2016-04-29 14:21:01 -07:00
Ashish Kumar
48be2e33f8 Delete old route for /json/get_public_streams. 2016-04-29 12:57:57 -07:00
Ashish Kumar
b5ab4d45f9 Replace /json/get_public_streams with REST style route. 2016-04-29 12:57:57 -07:00
Tim Abbott
362a622f1f Add documentation on translating Zulip. 2016-04-28 21:57:10 -07:00
Tim Abbott
27b8e8b294 Add the Zulip 2016 roadmap document. 2016-04-28 21:55:33 -07:00
Tim Abbott
a626f4558c README.md: Clean up guide to new contributions. 2016-04-28 21:07:42 -07:00
Eklavya Sharma
d3f2d17ee9 Use a shallow copy of Zulip's Django fork.
This will substantially improve the performance of running provision
on systems with a relatively slow network.

Fixes #704.
2016-04-28 16:07:53 -07:00
Tim Abbott
af4203b41b Stop using initial password for newly activated users.
Previously we needed to use a specified password when activating a
formerly mirror dummy user, in order for that user to be able to
(re)set their password and login.  Now that we have our own password
reset form, this is no longer required.
2016-04-28 14:28:09 -07:00
Tim Abbott
89d9060aab Add logging for failures in password reset form.
This may be useful for monitoring abuse issues.
2016-04-28 14:28:09 -07:00
Tim Abbott
a0430c02ce Allow users who haven't set a password to set one.
Previously, if a user had only authenticated via Google auth, they
would be unable to reset their password in order to set one (which is
needed to setup the mobile apps, for example).
2016-04-28 14:27:43 -07:00
Antek Grzanka
646ea3214a Add Taiga integration. 2016-04-28 13:44:53 -07:00
Tim Abbott
755695d3c0 bugdown: Add type: ignore for fenced_code import.
This is a workaround to allow us to type-check files that depend on
this.  Ideally in the future we'll fix the type errors in
fenced_code.py.
2016-04-28 12:50:47 -07:00
Tim Abbott
7a81524c97 event_queue: Fix import from wrong file. 2016-04-28 12:46:21 -07:00
Tim Abbott
d61c8f91cf run-mypy: Link to docs on ReadTheDocs. 2016-04-28 12:35:54 -07:00
Eklavya Sharma
b60141fd84 Add documentation on the using the mypy static type checker.
[with substantial tweaks by tabbott]
2016-04-28 12:29:45 -07:00
Eklavya Sharma
4310e6d224 Add tools/install-mypy.
This provides a way for users not using provision.py to install mypy.

[with substantial tweaks by tabbott]
2016-04-28 12:29:12 -07:00
Eklavya Sharma
1041115b38 Add code to install mypy from provision.py. 2016-04-28 12:28:24 -07:00
Eklavya Sharma
3601b9eda9 tools/run-mypy: Use mypy from zulip-py3-venv if present. 2016-04-28 12:28:24 -07:00
Eklavya Sharma
c80f699321 Add tools/run-mypy to Travis checks.
Fixes #635.
2016-04-28 10:03:35 -07:00
Eklavya Sharma
1af4334887 Add tools/run-mypy.
Since a lot of files don't pass the mypy check, a long list of
files to be excluded from mypy check has been specified.
2016-04-28 10:03:35 -07:00
Eklavya Sharma
c220c61dbd tools/check-py3: Speed up and add --find-fixers.
Now tools/check-py3 will by default run all fixers together.  This is
quicker but doesn't indicate which fixers caused the failure.  The
newly added option --find-fixers falls back to the old way of checking
each fixer separately if the quick check fails.

Fixes #710.
2016-04-28 10:01:17 -07:00
Eklavya Sharma
22d407fe0b docs/testing.rst: Fix typo and name of a package.
* Remove duplicate words.
* Replace `futurize` by `future`.
2016-04-28 15:19:22 +05:30
Tim Abbott
3e5ad69ffc Extract camo encoding to a library. 2016-04-27 22:23:40 -07:00
Tim Abbott
302da832fa lint: Enforce whitespace between : and value in dicts. 2016-04-27 22:23:40 -07:00
Tim Abbott
aebe7334a4 style: Fix missing :s between dict keys and values. 2016-04-27 22:23:40 -07:00
Tim Abbott
02ab03ec7a MITNameTest: Mock network access from Hesiod lookups.
The purpose of these tests is to check the logic, not that DNS is
working on the relevant machine.
2016-04-27 22:23:40 -07:00
Tim Abbott
e9a76f98c3 Vagrantfile: Fix using Vagrant with LXC >= 2.
Apparently LXC 2 removed support for the `-B best` option in
lxc-create, and Vagrant hasn't been updated appropriately yet, so we
need to add a workaround to explicitly specify a backing store.

Fixes #718.

This manifested as errors of the form:

"""
There was an error executing ["sudo",
"/usr/local/bin/vagrant-lxc-wrapper", "lxc-create", "-B", "best",
"--template",
"/home/tabbott/.vagrant.d/gems/gems/vagrant-lxc-1.2.1/scripts/lxc-template",
"--name", "zulip_default_1461801696512_85064", "--", "--tarball",
"/home/tabbott/.vagrant.d/boxes/fgrehm-VAGRANTSLASH-trusty64-lxc/1.2.0/lxc/rootfs.tar.gz",
"--config",
"/home/tabbott/.vagrant.d/boxes/fgrehm-VAGRANTSLASH-trusty64-lxc/1.2.0/lxc/lxc-config"]
"""
2016-04-27 17:07:03 -07:00
Tim Abbott
c9359bd75a test_hooks: Fix missing assert_json_success checks.
Several recently merged webhooks were incorrectly not checking that
the actual webhook result didn't return an error.  While they would
usually still fail in most cases when checking whether the message
came back correctly, this hid the root cause errors and thus made it
much harder to debug.
2016-04-27 13:25:21 -07:00
Tim Abbott
e6cfd917a5 Fix settings.RATE_LIMITING=False for webhooks.
We were incorrectly applying the rate limiting rules to webhooks even
if rate limiting was disabled (as in the test suite), causing test
failures when the total number of webhook tests in Zulip got too high.
2016-04-27 13:17:28 -07:00
Eklavya Sharma
b4555e58c8 tools/check-py3: Update references in output.
Replace occurrences of 'py3k' by 'check-py3' in echo output.
2016-04-27 10:34:52 -07:00
Tim Abbott
c83999fe52 Fix EXTRA_INSTALLED_APPS in development.
In theory, tools like populate_db should probably be in zerver, not
zilencer, but until we migrate them out, we need to include these in
EXTRA_INSTALLED_APPS in development.
2016-04-26 21:55:31 -07:00
Tim Abbott
8905216df5 Automate inclusion of urls.py files for EXTRA_INSTALLED_APPS.
By removing this hardcoding of the list of valid extra apps, we make
it a lot easier to add additional pluggable apps to the Zulip
codebase.
2016-04-26 21:39:39 -07:00
Tim Abbott
bf50dd7771 Simplify zilencer urls.py configuration to a single file.
The previous separated-out configuration wasn't helping us, and this
makes it easier to make the extra installed applications pluggable in
the following commits.
2016-04-26 21:35:07 -07:00
Tim Abbott
2b30b670e0 Factor out EXTRA_INSTALLED_APPS setting. 2016-04-26 21:28:51 -07:00
Tim Abbott
6e1e4aaef6 postgres-init-db: Add POSTGRES_USER argument. 2016-04-26 15:27:35 -07:00
Tim Abbott
dc772518e7 Don't chown supervisor socket if it doesn't exist. 2016-04-26 15:27:35 -07:00
Tim Abbott
6a3c775842 install: Ensure prod-static/serve is created. 2016-04-26 15:27:35 -07:00
Tim Abbott
bb25b6060e install: Avoid unnecessarily storing apt key under /root. 2016-04-26 15:07:53 -07:00
Tim Abbott
e9416a9fb2 install: Add PUPPET_CLASSES variable. 2016-04-26 15:06:37 -07:00
Tim Abbott
a9d86a3620 install: Add DEPLOYMENT_TYPE variable. 2016-04-26 15:04:32 -07:00
Tim Abbott
68c6d514e8 install: Add ADDITIONAL_PACKAGES option. 2016-04-26 15:02:28 -07:00
Vladislav Manchev
f5e6176aea Add custom realm emoji UI to administration page. 2016-04-26 13:15:54 -07:00
Tim Abbott
f5fe2d4bf7 Fix case-insensitive typeahead for emoji. 2016-04-26 13:14:28 -07:00
Tim Abbott
abacd9b2da Integration guide: Document need to edit urls.py. 2016-04-26 11:50:19 -07:00
Tim Abbott
e4aab64464 Sort webhook integration URL definitions.
This will merge conflict with every new integraiton in flight, which
is unfortunate, but will make there be fewer merge conflicts as people
add new webhooks in the future (currently, every pair of new
integrations conflict because folks are adding them all at the end,
whereas after this change, there will only be merge conflicts when
adding two integrations near each other alphabetically).
2016-04-26 11:49:33 -07:00
Vishnu Ks
fe4a03fd01 Move narrowed_msg_list to message_list.js. 2016-04-26 10:25:11 -07:00
Tomasz Kolek
12fc4f047c test_helpers: Create get_last_message helper. 2016-04-26 09:54:02 -07:00
Tomasz Kolek
5fbda3a9c1 Add codeship integration. 2016-04-26 09:54:01 -07:00
David Payne
8c62a27769 Add teamcity webhook integration.
This integration relies on the Teamcity "tcWebHooks" plugin which is
available at
https://netwolfuk.wordpress.com/category/teamcity/tcplugins/tcwebhooks/

It posts build fail and success notifications to a stream specified in
the webhook URL.

It uses the name of the build configuration as the topic.

For personal builds, it tries to map the Teamcity username to a Zulip
username, and sends a private message to that person.
2016-04-26 09:45:26 -07:00
Tim Abbott
672a431fba Expand documentation on tools/check-py3. 2016-04-25 16:46:46 -07:00
Eklavya Sharma
ae46d425b6 Add info about tools/check-py3 in docs/testing.rst.
Fixes #701.
2016-04-26 03:32:29 +05:30
Vishnu Ks
ae49ad383d Rename all function on MessageList to all_messages. 2016-04-25 13:45:18 -07:00
Eklavya Sharma
cbba7202e6 Add future and modernize to requirements.txt
Also improve tools/travis/setup-py3k in these ways:
* remove sudo
* add --no-deps to pip install
* specify versions in pip install
2016-04-25 09:50:32 -07:00
Eklavya Sharma
1ce2d26679 Prevent check-py3 from failing on no files.
Now tools/travis/check-py3 does not fail unexpectedly when there are
no python files in the current directory.
2016-04-25 09:50:32 -07:00
Eklavya Sharma
b4009c28d0 Move py3k and add a travis wrapper for it.
Move tools/travis/py3k to tools/check-py3.
Add tools/travis/py3k which calls tools/check-py3.
2016-04-25 09:50:32 -07:00
Eklavya Sharma
101148c49e Fix typo and formatting in docs. 2016-04-25 20:29:29 +05:30
Tim Abbott
21161a8adb Add memcached_prefix to .gitignore. 2016-04-22 17:32:44 -07:00
Tim Abbott
74ed9fabd0 Integration guide: Expand instructions on screenshots. 2016-04-21 18:17:26 -07:00
Vishnu Ks
35b0af2852 Move all_msg_list to message_list.js. 2016-04-21 17:46:21 -07:00
Tomasz Kolek
c74483e69e github_webhook: change double quotes to single quotes for consistency. 2016-04-21 17:04:25 -07:00
Tomasz Kolek
09e40b27c2 github_webhook: throw an exception on unhandled events types. 2016-04-21 17:03:58 -07:00
Tomasz Kolek
fafc9cb742 github_webhook: remove redundant parenthesis. 2016-04-21 17:02:49 -07:00
Tomasz Kolek
43b0cfaebc github_webhook: Use more one-line pythonic assignments. 2016-04-21 17:00:47 -07:00
Tomasz Kolek
decb686255 github_webhook: factor out is_test_repository function. 2016-04-21 16:57:19 -07:00
Tomasz Kolek
e1079d8475 github_webhook: extract the constants to the top of the file. 2016-04-21 16:56:44 -07:00
Tim Abbott
84e23dd015 Document code copied from Django and then modified. 2016-04-21 14:59:39 -07:00
Tim Abbott
ae047f8551 Fix slightly ugly login page URL of /login?next=/. 2016-04-21 14:59:39 -07:00
Tim Abbott
8a278cbe3a Switch to using a Zulip version of @login_required.
Currently the code is the unmodified Django upstream implementation;
this commit is preparation for modifying it.
2016-04-21 14:59:39 -07:00
Tim Abbott
d9dba5d2c2 deactivate_realm: Improve error handling for unknown realm. 2016-04-21 09:02:00 -07:00
Tim Abbott
c2237c60c0 deactivate_realm: Fix help string. 2016-04-21 09:02:00 -07:00
Tim Abbott
d890011442 Add a script to reactivated deactivated realms. 2016-04-21 09:02:00 -07:00
Tim Abbott
79297898f1 Remove obsolete AppleDeviceToken model. 2016-04-20 21:51:52 -07:00
Tim Abbott
49799440a4 Replace use of django-guardian with fields on UserProfile.
As documented in https://github.com/zulip/zulip/issues/441, Guardian
has quite poor performance, and in fact almost 50% of the time spent
running the Zulip backend test suite on my laptop was inside Guardian.

As part of this migration, we also clean up the old API_SUPER_USERS
variable used to mark EMAIL_GATEWAY_BOT as an API super user; now that
permission is managed entirely via the database.

When rebasing past this commit, developers will need to do a
`manage.py migrate` in order to apply the migration changes before the
server will run again.

We can't yet remove Guardian from INSTALLED_APPS, requirements.txt,
etc. in this release, because otherwise the reverse migration won't
work.

Fixes #441.
2016-04-20 21:51:52 -07:00
Vishnu Ks
ee39f5009f Make message_list.js work like the other modules. 2016-04-20 15:29:30 -07:00
Tim Abbott
28d1a3105c models: Add a __repr__ for Client. 2016-04-20 15:26:51 -07:00
Tim Abbott
552caf661a Caching: Fix 'update_fields' not being present in .delete() 2016-04-20 15:12:53 -07:00
Tim Abbott
9c56027627 lint: Add CSS lint rule for whitespace after {. 2016-04-20 11:50:01 -07:00
Tim Abbott
a46b5d7bbe Add lint check for missing whitespace after =. 2016-04-20 11:37:03 -07:00
Tim Abbott
a72385246e Fix missing whitespace after '=' in python/js code. 2016-04-20 11:36:14 -07:00
David Payne
ece96ef3fe Jira's "issue created" message should @-notify the assignee. 2016-04-20 10:54:30 -07:00
Tomasz Kolek
82f1cdb085 Add send_webhook_fixture_message command.
This tool simplifies the process of producing nice screenshots for
documenting webhook integrations.

Fixes #658.
2016-04-20 10:45:27 -07:00
Eklavya Sharma
c7a93cba22 Add tests for checking image validity in SetAvatarTest. 2016-04-20 12:27:23 +05:30
Eklavya Sharma
af7c3de5f5 Add SetAvatarTest to test_upload.py.
Test multiple file uploads for /json/set_avatar.
Test no file upload for /json/set_avatar.
Add test images for SetAvatarTest.
2016-04-20 12:23:22 +05:30
Eklavya Sharma
126273b1e7 Add a test for local file uploads. 2016-04-20 12:00:13 +05:30
Eklavya Sharma
4e18d856e3 Prevent 500 error when user uploads invalid avatar.
When uploaded avatar image is not a valid image file, PIL raises
IOError. Catch the IOError raised by PIL and raise JsonableError.
This will return a response with status code 400.
2016-04-20 12:00:13 +05:30
Eklavya Sharma
2d60a1d0f3 Move upload-related tests to test_upload.py.
Move S3Test, FileUploadTest and SanitizeNameTests from
test_external.py to test_upload.py.
2016-04-19 16:48:30 -07:00
Eklavya Sharma
c75c5fb3e1 Use a different uploads directory when running tests. 2016-04-19 16:48:30 -07:00
Tim Abbott
1b988de30a Integration guide: clean up description of plugin integrations. 2016-04-19 16:21:33 -07:00
Tim Abbott
92f9a789b8 integration guide: Improve introduction. 2016-04-19 16:21:33 -07:00
Tim Abbott
0669262ccb /integrations: Document how to contribute integrations. 2016-04-19 16:21:33 -07:00
Vishnu Ks
3179434f93 Move keep_pointer_in_view to pointer.js. 2016-04-19 15:23:45 -07:00
Vishnu Ks
b655e090a6 check_all: Move viewport to modules list.
It was previously incorrectly listed as a global variable.
2016-04-19 15:23:24 -07:00
Tim Abbott
a2b59b8b51 lint: Check whitespace rules for txt files. 2016-04-14 14:36:29 -07:00
Tim Abbott
78febc3abb Fix missing newlines at end of .txt files. 2016-04-14 14:36:29 -07:00
Tim Abbott
39950b8f4f lint: Check whitespace rules in markdown files too. 2016-04-14 14:30:29 -07:00
Tim Abbott
1a162ecb97 Fix tab-based whitespace in stress-test README file. 2016-04-14 14:30:29 -07:00
Tim Abbott
2b76f6223e Make 'no newline at end of file' lint error more actionable.
There's a handy sed command to fix this, so we might as well document
it.
2016-04-14 10:55:06 -07:00
Tim Abbott
e71d8bb4b6 lint-all: Require newlines at end of JSON files. 2016-04-14 10:49:12 -07:00
Tim Abbott
5195d1ecb7 Fix missing newlines at ends of JSON files. 2016-04-14 10:48:52 -07:00
Tim Abbott
1bf11f6b7f Split FileUploadTest out of S3Test.
S3Test is now only the S3-specific test (which isn't even run), so we
can now invest in making FileUploadTest have good coverage of the
(local) file upload code paths.
2016-04-14 10:35:10 -07:00
Sumana Harihareswara
4ce4f88a03 Fix formatting in directory-structure.rst. 2016-04-13 15:44:10 -07:00
Tim Abbott
74abd47684 Fix EMAIL_GATEWAY_BOT not being set by default in production.
Previously the DEFAULTS value of None for EMAIL_GATEWAY_BOT was
overriding the initialization code.
2016-04-13 13:19:02 -07:00
Tim Abbott
ae48f6394b migrations: Disable prompting about content-type deletion.
The main function of prompting inside `manage.py migrate` is to ask
the user if they want to delete stale content-types, which is
unimportant and likely scary, so we disable doing so.
2016-04-13 13:19:02 -07:00
Tim Abbott
d0f2c46f25 generate_test_credentials: Use the email variable properly.
This makes it a bit easier to change the email in the test
credentials.
2016-04-13 13:19:02 -07:00
Tim Abbott
26463bb34d Fix nondeterministic subscriptions for default test users.
Previously, the UserProfile objects were created in the order
generated by a Set, which meant tests would randomly start failing if
the code that runs before this part of populate_db changed (and thus
caused the Set object used to pass users into bulk_create_users to
have a different order when enumerated).

This fixes the issue in two ways -- one by sorting the users inside
bulk_create_users, and second by attaching subscriptions to users
based on a deterministic ordering.
2016-04-13 13:19:02 -07:00
Tim Abbott
81143a8c98 02-narrow: Use Denmark as the test second stream.
It's less easily confused with "Verona", and prevents the next commit
from breaking the tests (since Iago will lose his subscription to
"Venice").
2016-04-13 13:19:02 -07:00
Tim Abbott
f6edc21981 Change stream used in test_get_old_messages_with_only_searching_anchor.
This prevents this test from breaking when in a few commits we fix a
nondeterminism issue in the populate_db test fixtures.
2016-04-13 13:19:02 -07:00
Tim Abbott
ffccb572f0 Don't autoreload Tornado when running inside test suite.
The restarted Tornado processes seemed to escape the process group and
thus continue running after run-dev.py finished.

While we're at it, we don't need to dump/reload event queues in the
test suite either.
2016-04-13 13:19:01 -07:00
Tim Abbott
98d5f64f36 webpack: Use the correct port in Casper tests.
Previously we used 9994 unconditionally, whereas we should be using
9984 or 9994 depending whether it's being run manually or via the
Casper tests.
2016-04-13 13:18:38 -07:00
Tim Abbott
47879c5e00 Fix nondeterminism in test_successful_subscriptions_add.
Previously this test would fail if the streams list generated by
populate_db contained more than 2 streams.
2016-04-13 13:18:24 -07:00
Tim Abbott
2e32a7f05d Move by-hand proxy setup section closer to the actual instructions. 2016-04-13 09:06:20 -07:00
Vishnu Ks
859a4eeaf4 Add support for using and configuring vagrant-proxyconf.
Users can now specify proxy settings for vagrant in a new
~/.zulip-vagrant-config configuration file.
2016-04-13 09:06:03 -07:00
Vishnu Ks
35f70e9dac Move 5 legacy global variables to pointer.js.
Move recenter_pointer_on_display, suppress_scroll_pointer_update,
fast_forward_pointer, furthest_read, and server_furthest_read to
a new pointer module in pointer.js.
2016-04-12 10:56:54 -07:00
Tim Abbott
fb55fcef1e Fix missing zerver/tests/__init__.py. 2016-04-11 22:34:22 -07:00
Tim Abbott
be96cf809d Move Zulip backend tests to zerver.tests. 2016-04-11 22:16:09 -07:00
Ashish
1bf644369f Delete old route for json/update_active_status. 2016-04-11 21:38:23 -07:00
Ashish
78b9f45bf7 Delete old route for json/update_pointer. 2016-04-11 21:38:23 -07:00
Ashish
9429358795 Delete old route for /json/get_profile. 2016-04-11 21:38:23 -07:00
Ashish
86fb7103fa Delete old route for json/change_enter_sends. 2016-04-11 21:38:23 -07:00
Ashish
42fe918138 Delete old route for json/get_old_messages. 2016-04-11 21:38:23 -07:00
Ashish
cfefc94200 Delete old route for json/set_alert_words. 2016-04-11 21:38:23 -07:00
Ashish
c0a218edfc Delete old route for /json/update_message_flags. 2016-04-11 21:38:23 -07:00
Ashish
a12006d86f Replace /json/update_active_status with REST style route. 2016-04-11 21:38:23 -07:00
Ashish
6356584f84 Replace /json/update_pointer with REST style route. 2016-04-11 21:38:23 -07:00
Ashish
b8ec8f5ef0 Replace /json/get_profile with REST style route. 2016-04-11 21:38:23 -07:00
Ashish
679b4e5807 Replace /json/change_enter_sends with REST style route. 2016-04-11 21:38:23 -07:00
Ashish
cb8da46bbf Replace /json/get_old_messages with REST style route. 2016-04-11 21:38:23 -07:00
Ashish
8fc8717409 Replace json/set_alert_words with REST style route. 2016-04-11 21:38:22 -07:00
Ashish
41993ef2f5 Replace /json/update_message_flags with REST style route. 2016-04-11 21:38:22 -07:00
Ashish
dac4e58b91 Changes REST API backend route for /json/change_enter_sends. 2016-04-11 21:11:51 -07:00
Tim Abbott
73f2d67ba1 Document how to configure Vagrant LXC with passwordless sudo. 2016-04-10 17:37:52 -07:00
Tim Abbott
7d64bd51f5 provision: Don't install recursive pip dependencies.
This should prevent future issues like the wrong cryptography module
being in requirements.txt.
2016-04-10 17:37:52 -07:00
Tim Abbott
00a92b5827 Add missing requests_oauthlib dependency. 2016-04-10 17:37:52 -07:00
Tim Abbott
b29cb1dfb8 provision: Remove now-unnecessary patching of PATH. 2016-04-10 17:37:52 -07:00
Tim Abbott
6de15606f9 provision: Add preliminary support for Ubuntu Xenial.
This won't actually work because we don't have a tsearch_extras
package built for postgres 9.5.
2016-04-10 17:37:52 -07:00
Tim Abbott
f6a7b192a4 requirements: Upgrade cffi and cryptography libs in development.
The older versions apparently don't build on Ubuntu Xenial.
2016-04-10 17:37:52 -07:00
Tim Abbott
3c74bf000f provision: Add installing recent npm to provisioning process.
This fixes a problem where the version of NPM installed in development
environments was too old.
2016-04-10 17:37:43 -07:00
Tim Abbott
5733c32705 Fix install-phantomjs being called before chdir to ZULIP_PATH. 2016-04-10 17:33:37 -07:00
Tim Abbott
52fc1c71bc provision: Rewrite using subprocess module instead of sh.
The `with sh.sudo` pattern that we were using in python-sh was
deprecated, and emperically hangs on Ubuntu xenial.  Since in general
the use of python-sh/python-pbs caused trouble (requiring extra
dependencies, confusing syntax), this just removes it.

We replace it with a new zulip_tools.py library function that echoes
the command line and streams the output.

We do the same to install-phantomjs so we can remove that dependency.
2016-04-10 17:33:19 -07:00
Vishnu Ks
2ac5271091 Move global variable have_scrolled_away_from_top to ui.js. 2016-04-10 10:55:16 -07:00
Tim Abbott
fcced9561d provision: Add dependency on ipython.
ipython dramatically improves the experience of `manage.py shell`.
2016-04-09 10:23:13 -07:00
Kumar
4eced69228 Make subscriptions page error bar visible even when scrolled down.
Previously, the Zulip subscriptions page's error bar would always be
at the very top of the scrollable view, and thus would likely be out
of view when an error happened.  This fixes it by having the error bar
always placed below the search box (and thus visible regardless of
where in the scrollable streams view we are).

Fixes: #515.

[commit message and comments expanded by tabbott]
2016-04-08 21:04:43 -07:00
Tim Abbott
9584ae1ab8 Add CSS linter for missing space after : in rules. 2016-04-08 21:04:43 -07:00
Tim Abbott
f4bd35678e Fix missing whitespace after :s in CSS. 2016-04-08 21:04:43 -07:00
Tim Abbott
64e527ff34 Fix ordering of documentation blocks in /integrations.html. 2016-04-08 20:29:45 -07:00
Anindya Chakravarti
efb7c902de Correct alphabetical order of integrations page. 2016-04-08 20:26:47 -07:00
Tim Abbott
b61d73fc93 Delete unused old StreamColor model. 2016-04-08 13:06:04 -07:00
Tim Abbott
877b4af24a Replace platform.codename and friends with lsb_release.
The old code was producing incorrect output of "debian" as the release
on Travis CI's Ubuntu Trusty nodes.
2016-04-08 12:35:08 -07:00
Tim Abbott
6969c26dfa provision: Fix hardcoding of trusty codename. 2016-04-08 12:17:45 -07:00
Tim Abbott
64973fc4e6 provision: Refactor postgres version to be a variable. 2016-04-08 12:17:45 -07:00
Tim Abbott
7fe9a6b74b provision: check arch and codename earlier in setup process. 2016-04-08 12:17:45 -07:00
Tim Abbott
7dd9e93f9b provision: Exit with an error with unsupported platform. 2016-04-08 12:17:45 -07:00
Tim Abbott
5d13d62057 provision: simplify logging configuration. 2016-04-08 12:17:45 -07:00
Tim Abbott
fc4e8730f3 provision: Compute ZULIP_PATH dynamically. 2016-04-08 12:17:45 -07:00
Aristeidis Fkiaras
0058ccbdb0 Move global unread_messages_read_in_narrow to unread.js. 2016-04-08 12:11:47 -07:00
Tim Abbott
209e6ef7a1 Run trailing whitespace linter on bash files. 2016-04-08 11:52:11 -07:00
Tim Abbott
caba24b2af Fix existing trailing whitespace in bash scripts. 2016-04-08 11:52:11 -07:00
Tim Abbott
4fa63c29ca Run whitespace linters on html files. 2016-04-08 11:52:11 -07:00
Tim Abbott
ba30713078 Fix whitespace linting errors in html files. 2016-04-08 11:52:11 -07:00
Tim Abbott
d670e902a9 Run whitespace linters on handlebars templates. 2016-04-08 11:52:11 -07:00
Tim Abbott
88b0c12193 Fix whitespace linting errors in handlebars templates. 2016-04-08 11:52:11 -07:00
Tim Abbott
c6d01ab76b Run whitespace linters on CSS files. 2016-04-08 11:47:10 -07:00
Tim Abbott
1b84617771 Don't skip running python custom linters inside comments.
This fixes an issue where we weren't checking for trailing whitespace
in comments.
2016-04-08 11:47:10 -07:00
Tim Abbott
14b5e265c2 Remove unuseful suspicious code lint check. 2016-04-08 11:47:10 -07:00
Ashish
9cfa7d5765 Annotation of zerver/lib/handlers.py. 2016-04-08 11:18:36 -07:00
Ashish
86a8d3d0f5 Annotation of zerver/lib/rate_limiter.py 2016-04-08 11:18:36 -07:00
Ashish
2f8c717e52 List to tuple conversion for consistency in user rules zerver/lib/rate_limiter.py. 2016-04-08 11:18:35 -07:00
Ashish
8abca4f319 Annotation of zerver/lib/migrate.py 2016-04-08 11:18:35 -07:00
Ashish
038af80889 Annotation of zerver/lib/statistics.py 2016-04-08 11:11:58 -07:00
Ashish
2cf8731444 Annotation of zerver/lib/alert_words.py 2016-04-08 11:11:58 -07:00
Anindya Chakravarti
f3d03d89b4 Add integration for Yo App.
[includes some small tweaks by tabbott]
2016-04-08 11:02:10 -07:00
Tomasz Kolek
44ed9da7f0 Add pingdom integration. 2016-04-08 10:36:29 -07:00
Vishnu Ks
fe77559164 Fix broken link to Google Play store badge. 2016-04-08 08:37:17 -07:00
Tim Abbott
efd14e7ad9 Revert "Exclude 'from typing import *' from linter."
This reverts commit d936bf61f9.

We no longer need this since we've migrated to specifying the
dependencies in the typing module that we're actually using.
2016-04-07 14:12:18 -07:00
Tim Abbott
a1b306f9ce Finish purging 'fromt typing import *' from Zulip codebase. 2016-04-07 14:11:21 -07:00
Varshit
4e1060076d Purge 'from typing import *' from zerver/.
This is a partial implementation of #636.
2016-04-07 14:07:07 -07:00
Eklavya Sharma
5f03c1444e Remove duplicate module zerver/views/webhooks.py.
Also move type annotations from zerver/views/webhooks.py to
appropriate files in zerver/views/webhooks.py.
2016-04-07 12:37:22 +05:30
Tim Abbott
a7f83c9e05 Fix check_postgres_replication_lag nagios command. 2016-04-06 15:30:51 -07:00
Tim Abbott
991341867c nagios: Remove unnecessary dependency on netcat. 2016-04-06 15:30:40 -07:00
Tim Abbott
c92221dcd3 Remove old humbughq apache configuration. 2016-04-06 15:30:36 -07:00
Tim Abbott
4855296771 puppet: Migrate check_postgres plugins to postgres_common.pp. 2016-04-06 15:20:36 -07:00
Tim Abbott
e413d4e153 Move webpack configuration to tools/. 2016-04-06 08:09:55 -07:00
Tim Abbott
69a8925076 check_user_zephyr_mirror_liveness: Fix importing settings. 2016-04-05 13:27:04 -07:00
Tim Abbott
b229767605 Update Zulip Nagios plugin documentation.
This completes the effort to move the Zulip Nagios plugins to be
available in the modules that they actually are a part of.

Fixes: #371.
2016-04-05 13:27:04 -07:00
Tim Abbott
55172e2e0c Remove old zulip_internal nagios_plugins installation. 2016-04-05 13:27:04 -07:00
Tim Abbott
934e8641ee Migrate Zephyr mirror Nagios plugins to subdirectory. 2016-04-05 13:27:04 -07:00
Tim Abbott
7b753e5882 Migrate check_debian_packages to zulip/. 2016-04-05 13:27:04 -07:00
Tim Abbott
2da9fc56d6 Migrate check_pg_replication_lag to zulip/. 2016-04-05 13:27:04 -07:00
Tim Abbott
c2e210ca0d Migrate check_website_response.sh to new zulip::nagios.pp. 2016-04-05 13:27:04 -07:00
Tim Abbott
eb72cecd9e Migrate check_fts_update_log to zulip/. 2016-04-05 13:27:04 -07:00
Tim Abbott
92d696d007 Migrate check_postgres plugins to zulip/. 2016-04-05 13:27:04 -07:00
Tim Abbott
e155ecdc49 Migrate check_rabbitmq plugins to zulip/. 2016-04-05 13:27:04 -07:00
Tim Abbott
3ed7d658f8 Migrate check_send_receive_time to zulip/. 2016-04-05 13:27:04 -07:00
Tim Abbott
ca45ec3f3f Migrate check_email_deliverer plugins to zulip/. 2016-04-05 13:27:04 -07:00
Tim Abbott
4e10424512 Migrate check_worker_memory to zulip/. 2016-04-05 13:27:04 -07:00
Tim Abbott
59b46278be Move check_queue_worker_errors into subdirectory.
This fixes an issue where this worker wasn't even being installed
properly in a way that sets us up for doing further reorganization of
the Zulip Nagios plugins.
2016-04-05 13:27:04 -07:00
Tim Abbott
6f20c43097 Move dependency on nagios_plugins into base.pp. 2016-04-05 13:27:04 -07:00
Eklavya Sharma
05ab57e373 In py3k, exit with 1 if repository is not clean. 2016-04-05 13:22:51 -07:00
Eklavya Sharma
569d1240d0 Exit with 1 in py3k when fixers find an issue.
tools/travis/py3k used to always exit with exit code 0.
It should exit with 1 when fixers detect a compatibility issue.

py3k used [ -z "$failed" ] to check if there was a failure.
This is wrong, since if no failure has occured, failed=0,
and -z checks if a string is of zero length. This commit also
fixes this bug.
2016-04-05 13:22:51 -07:00
Eklavya Sharma
dd501830a6 Change position where git reset is called in py3k.
In py3k, "git reset --hard" was called only if
libmodernize.fixes.fix_dict_six changed files and some of those
changes are not considered false positives by py3k.
But if all of those changes are not considered false positives
by py3k, then "git reset --hard" is not called and the repository
is no longer clean.

This commit fixes this bug.
2016-04-05 13:22:51 -07:00
Eklavya Sharma
5e71777975 Add --no-pager option to git diff in py3k.
This is needed because py3k hangs when a pager opens up.
2016-04-05 13:22:51 -07:00
Eklavya Sharma
adff674b0e tools/travis/py3k now checks all python files.
tools/travis/py3k used to only check files whose names ended with .py.
Now it also checks python scripts which don't have an extension.
It uses tools/lister.py to get a list of all python files.
2016-04-05 13:22:51 -07:00
Eklavya Sharma
ab02ab31e3 Change len(obj.keys()) to len(obj) in tools/get-handlebar-vars.
This prevents libmodernize.fixes.fix_dict_six from reporting
this on running tools/travis/py3k.
2016-04-05 13:22:51 -07:00
Eklavya Sharma
0af154a301 Apply Python 3 futurize transform libfuturize.fixes.fix_absolute_import. 2016-04-05 13:22:51 -07:00
Eklavya Sharma
8a81f8c125 Apply Python 3 futurize transform libfuturize.fixes.fix_print_with_import. 2016-04-05 13:22:51 -07:00
Eklavya Sharma
f4aa609aea Apply Python 3 futurize transform libmodernize.fixes.fix_file. 2016-04-05 13:22:51 -07:00
Eklavya Sharma
be0a4f349d Apply Python 3 futurize transform libmodernize.fixes.fix_filter. 2016-04-05 13:22:51 -07:00
Tim Abbott
78e289f904 Exclude puppet-common tests from puppet linter. 2016-04-04 17:08:29 -07:00
Tim Abbott
e6fb5bb1ea changelog: Add more changes since 1.3.10. 2016-04-03 17:55:06 -07:00
Tim Abbott
75d134a9b2 Import tornado.autoreload explicitly.
Fixes #623.
2016-04-03 16:52:23 -07:00
Ashish
909b0635c8 Add management command to test sending email.
Fixes: #622.

[With cleanups/doc tweaks by tabbott]
2016-04-03 16:50:16 -07:00
Varshit
e0ef1a991e Rewrite sanitize_name to better preserve filenames.
The previous version of sanitize_name dropped all unicode characters
and mangled filenames with multiple `.`s in the extension, leading to
confusing URLs for files uploaded to Zulip.

Fixes #321.

[tweaked significantly by tabbott]
2016-04-03 16:26:12 -07:00
Tim Abbott
4a50336476 Add type: Any for tornado.ioloop.add_timeout return value. 2016-04-03 15:40:24 -07:00
Tim Abbott
4352a022cd Add type: ignore to wildcard imports in pythonrc.py. 2016-04-03 15:40:24 -07:00
Tim Abbott
b6dd6413d0 Add type: ignore for tornado_ioloop_logging Tornado versioning code. 2016-04-03 15:40:24 -07:00
Tim Abbott
53ab18eea0 Add type: ignore for chain.from_iterable. 2016-04-03 15:40:24 -07:00
Tim Abbott
9abd332c07 Add type: ignore for mock.Mock() monkey-patching. 2016-04-03 15:40:24 -07:00
Tim Abbott
0d40473818 Add type: ignore for empty list mypy bug. 2016-04-03 15:40:24 -07:00
Tim Abbott
2c1377319f Add type: ignore for mypy __cmp__ bug. 2016-04-03 15:40:24 -07:00
Tim Abbott
3a2d5266d8 Add type: ignore for mypy super() bug. 2016-04-03 15:40:24 -07:00
Tim Abbott
e3ec3e2526 Add type: ignore for test_helpers monkey-patching. 2016-04-03 15:40:24 -07:00
Tim Abbott
6c999927ac Add type: ignore for csrf_exempt decorator. 2016-04-03 15:40:23 -07:00
Tim Abbott
b7dcf2181f Add PEP-484 type annotations to management commands. 2016-04-03 15:40:23 -07:00
Tim Abbott
b437fe2924 Add PEP-484 annotations to bots/. 2016-04-03 15:40:23 -07:00
Tim Abbott
5d5976e4ae Add PEP-484 type annotations to api/.
It's not clear this is net constructive since it makes our API
bindings harder to install.
2016-04-03 15:40:23 -07:00
Tim Abbott
2d2282ada8 Add PEP-484 type annotations to confirmation/. 2016-04-03 15:40:23 -07:00
Tim Abbott
b8c82d5b43 Add PEP-484 type annotations to analytics/. 2016-04-03 15:40:23 -07:00
Tim Abbott
32f8f85f8b Add PEP-484 type annotations to zerver/*.py. 2016-04-03 15:40:23 -07:00
Tim Abbott
ee8be22160 Add PEP-484 type annotations to zerver/worker/. 2016-04-03 15:40:23 -07:00
Tim Abbott
ec7bb0b011 Add PEP-484 type annotations to zerver/views/. 2016-04-03 15:40:23 -07:00
Tim Abbott
2059f650ab Add PEP-484 type annotations to zerver/lib/. 2016-04-03 15:40:23 -07:00
Tim Abbott
d8f7d89fb4 Add PEP-484 type annotations to zerver/models.py.
Done pair-programming with Guido.
2016-04-03 15:40:06 -07:00
Tim Abbott
b99313545e Add PEP-484 type annotations to global dictionaties. 2016-04-03 15:40:06 -07:00
Tim Abbott
77be524dc4 Add PEP-484 type annotations to generator functions. 2016-04-03 15:40:05 -07:00
Tim Abbott
2c88085572 test_decorators: Clean up Request.REQUEST mocking. 2016-04-03 15:40:05 -07:00
Tim Abbott
70c1b0a01d lister: Add file type detection for node and ruby. 2016-04-01 15:27:32 -07:00
Eklavya Sharma
aead933c14 Add command-line interface to lister.py using argparse. 2016-04-01 15:27:32 -07:00
Eklavya Sharma
81fdeae0ea Remove '.'s from extensions in lister.py interface and lint-all.
In lint-all, change occurences of '.py', '.js', ... to 'py', 'js', ....
2016-04-01 15:27:16 -07:00
Eklavya Sharma
ad4c20a3e6 Migrate lint-all to lister.py for getting files.
This has the side effect of making lint-all check all shell scripts,
not just those under scripts/, tools/, and bin/.

[commit message expanded by tabbott]
2016-04-01 15:24:43 -07:00
Eklavya Sharma
ec8ae1f4c5 Add option to determine file type in lister.py using shebang. 2016-04-01 15:19:13 -07:00
Eklavya Sharma
5063f16f82 Add options for file type in lister.py
Add option to filter files by their extension.
Add option to return a dict of list of files keyed by their file type.
2016-04-01 15:19:13 -07:00
Eklavya Sharma
81aabb5831 Add option to exclude files from lister.py. 2016-04-01 15:19:13 -07:00
Eklavya Sharma
422fef2e24 Add argument modified_only to lister.py.
Add option of only showing modified files in tools/lister.py.
2016-04-01 15:19:13 -07:00
Eklavya Sharma
6954eb072c Create lister.py.
Make module tools/lister.py which lists all files in a directory
tracked by git.  This is done because lister.py will be used by other
scripts in the future which have to introspect files in the repository,
like linters, static code checkers, etc.
2016-04-01 15:19:13 -07:00
Tim Abbott
5c810ad0bc Add new markdown documentation to ReadTheDocs. 2016-04-01 14:57:30 -07:00
Tim Abbott
a1683b1eaf Reorganize postgres docs. 2016-04-01 10:01:07 -07:00
Tim Abbott
52764763c6 Add some docs on schema migrations. 2016-04-01 09:57:00 -07:00
Tim Abbott
94cca8b758 Expand documentation on postgres with Zulip. 2016-04-01 09:56:59 -07:00
Tim Abbott
37b79deb60 Expand documentation on frontend build process. 2016-04-01 09:56:59 -07:00
Tim Abbott
7a671c2652 Add documentation on the Zulip RabbitMQ queues. 2016-04-01 09:56:59 -07:00
Tim Abbott
96eb81e5d5 Add documentation of Zulip's markdown implementation. 2016-04-01 09:56:59 -07:00
Tim Abbott
82831231b5 Document postgres vacuuming alert and health check command. 2016-04-01 09:56:59 -07:00
Tim Abbott
342b4eb457 Add a detailed integration writing guide.
Fixes: #70.
2016-04-01 09:56:59 -07:00
Tim Abbott
7d74c64f75 Add hackish tool for finding unused CSS. 2016-04-01 09:34:46 -07:00
Tim Abbott
b8c7cfb77e docs: Add Javascript manual testing section. 2016-04-01 09:34:45 -07:00
Tim Abbott
a407f090e1 models: Document some of the more interesting model classes. 2016-04-01 09:34:45 -07:00
Ryan Moore
2fe0700f55 Update memcache -> remote cache in inline documentation. 2016-03-31 12:56:42 -07:00
Ryan Moore
beac606ce6 switch output stats memcached -> remote_cache 2016-03-31 12:54:29 -07:00
Ryan Moore
15cc3fde7b s/memcache/remote_cache/ in models 2016-03-31 12:54:29 -07:00
Ryan Moore
1489f0992c s/fill_memcached_cache/fill_remote_cache/g 2016-03-31 12:54:29 -07:00
Ryan Moore
18139fd86f s/memcached_prefix/remote_cache_prefix/g 2016-03-31 12:54:29 -07:00
Ryan Moore
85b05d4e2b s/memcached_output/remote_cache_output/g 2016-03-31 12:54:29 -07:00
Ryan Moore
5346e2ac23 s/memcached_count_delta/remote_cache_count_delta/g 2016-03-31 12:54:29 -07:00
Ryan Moore
1f120aa3a8 s/memcached_total/remote_cache_total/g 2016-03-31 12:54:29 -07:00
Ryan Moore
3c180b43df s/memcached_stats/remote_cache_stats/g 2016-03-31 12:54:28 -07:00
Ryan Moore
1a2117292f s/memcached_requests/remote_cache_requests/g 2016-03-31 12:54:28 -07:00
Ryan Moore
16c936f638 s/memcached_time/remote_cache_time/g 2016-03-31 12:54:28 -07:00
Ryan Moore
9f29b80f8a s/items_for_memcached/items_for_remote_cache/g 2016-03-31 12:54:28 -07:00
Tim Abbott
93b3feda43 Fix node test broken by reloading changes. 2016-03-30 23:40:00 -07:00
Tim Abbott
723d8c288a Add tornado autoreload hook to dump event queues on reload.
It's always been the case that in production, Tornado dumps all the
event queues when shut down so that they can be reloaded by the
replacement Tornado process.  This never worked in development because
the codepath for auto-reload didn't go through either a signal or
sys.exit (it re-execs the process instead).

This meant that we didn't have a mechanism for testing the event queue
dump/load functionality in the development environment.  We fix this
by adding such dumping/loading.  However, this breaks the automatic
reloading of open browser windows on a server restart, so we add that
back in by adjusting the special `restart` events to pass a special
`immediate` flag when used in development.

This also has the benefit of removing the "Bad event queue" errors one
would get on every file save induced restart on the Python console.
2016-03-30 23:09:16 -07:00
Tim Abbott
6d2ae9abbc Fix cleanup_event_queue being called multiple times during reload.
Apparently it isn't always the case that removal of jquery and the DOM
prevents cleanup_event_queue from being called via the postunload
hook, so add a check to avoid it being double-called.
2016-03-30 23:09:16 -07:00
Tim Abbott
59e2be2f5f Notify clients when an event queue is garbage collected. 2016-03-30 23:09:14 -07:00
Tim Abbott
44ed90db85 Fix get_events restarting during an ongoing reload.
Previously, the browser might restart a get_events operation even
while it was in the middle of executing a `DELETE /events` query to
cause its event queue to be de-allocated.  This was a rare race
condition when we weren't notifying clients when event queues were
de-allocated, but this will become a common case in the next commit.
2016-03-30 22:28:07 -07:00
Tim Abbott
bf43db0dad Send responses from fetch_events in dict format. 2016-03-30 22:04:09 -07:00
Tim Abbott
485e46f136 Wrap most of fetch_events in a try/except JsonableError.
This is a no-op right now, but we'll want the new structure for the
next commit, and splitting this out makes it a lot easier to read what
is actually changed in the next commit.
2016-03-30 22:02:32 -07:00
Tim Abbott
ad1494f8e0 Use dictionaries for passing data into event server subsystem.
This marshalls data in a portable format in preparation for splitting
the event queue server from the Tornado server.
2016-03-30 22:01:08 -07:00
Tim Abbott
6cd14af18f events: Migrate client_type => client_type_name in marshalling code. 2016-03-30 22:00:50 -07:00
Tim Abbott
d936bf61f9 Exclude 'from typing import *' from linter. 2016-03-30 21:50:31 -07:00
Tim Abbott
8c0b110e9a Add python-typing dependency. 2016-03-30 21:50:25 -07:00
Tim Abbott
e9637a545f Rename zerver.handlers to zerver.logging_handlers for clarity. 2016-03-30 21:48:38 -07:00
Tim Abbott
10777c85d4 Move npm install to end of development installation process.
This should make it easier for users to recover from failed `npm
install` commands when setting up their environment.
2016-03-29 21:56:19 -07:00
Ashish
62cb36c9e0 Add proxy notes to new README.dev.md troubleshooting section.
[with some fixups by tabbott]
2016-03-29 21:54:05 -07:00
Tim Abbott
c16749d783 Add missing dependency on netcat in both dev and prod.
Fixes #474.
2016-03-29 21:30:48 -07:00
Tim Abbott
d8493b071b Fetch tsearch_extras packages from GitHub dist repository. 2016-03-29 21:25:33 -07:00
Tim Abbott
970d697e88 Fetch PhantomJS packages from a GitHub URL.
This should fix a problem we've been having with errors downloading
the PhantomJS packages from their original hosting service.

Eventually we should move it to an S3 bucket.
2016-03-29 21:24:38 -07:00
goelakash
36cf398ec3 Factor out phantomjs download script for use in by-hand instructions.
Also, modify README.dev.md to document need to run this script to
download PhantomJS.

Fixes #499.

[cleaned up a bit by tabbott]
2016-03-29 20:10:17 -07:00
Eklavya Sharma
20f4bcd86e Delete tools/python-proxy since it is not used. 2016-03-29 20:02:26 -07:00
Ashish
2050f5c7fa Add API example for fetching historical messages.
Fixes: #269.
2016-03-29 19:04:43 -07:00
akashnimare
41c0b92668 Optimize images on landing page to improve load performance. 2016-03-29 18:26:29 -07:00
SummerBulb
d3d9dc1557 README.prod.md - fix botsq typo. 2016-03-29 11:15:53 -07:00
goelakash
25a75bcefe Change LOCAL_UPLOAD_DIR to 'uploads' in development.
Fixes #488.
2016-03-29 11:12:29 -07:00
Tim Abbott
2adf6d822f puppet: Fix process_queue command lines to use the new argument style.
cd2348e9ae broke installing Zulip in
production since it didn't correctly update the puppet configuration
to call the process_queue script using the new argument format.

This commit isn't ideal in that I'd prefer to not require updating
puppet in sync with the actual running code, but we don't have a great
mechanism for doing that.

Fixes #586.
2016-03-27 23:17:16 -07:00
Tim Abbott
06b33da709 process_queue: Fix missing worker.setup() in single-threaded codepath. 2016-03-27 23:17:16 -07:00
Kunal Gupta
6d0e868897 README.prod.md: Fix installation instructions to not hardcode version.
Previously, we needed to update the installation instructions with the
current version of Zulip in production every time we did a release,
which was kinda a pain (and hadn't happened since 1.3.6).

Fixes #576.

[commit message details expanded by tabbott]
2016-03-27 13:55:49 -07:00
Kartik Maji
2b3312cd6e Update unread counts for streams when muting topics.
Fixes #427.
2016-03-27 13:49:52 -07:00
SummerBulb
cc118824d5 README.prod.md: Fix a formatting typo. 2016-03-27 13:20:24 -07:00
Vladislav Manchev
294030ca04 Fix Travis failures due to redirects when downloading PhantomJS. 2016-03-23 21:54:56 -07:00
Zev Benjamin
965f923ac3 Remove postgres2 configuration 2016-03-23 20:41:42 -07:00
Zev Benjamin
ae2560a027 Add postgres3 configuration 2016-03-23 20:41:25 -07:00
Tim Abbott
6137ae9902 Fix incorrect shell quoting in check_worker_memory. 2016-03-23 20:40:06 -07:00
Tim Abbott
210c2897e7 Fix check_worker_memory regular expression. 2016-03-23 20:40:02 -07:00
Tim Abbott
9607144bf2 Fix off-by-one error in presence list updating logic.
The original logic for incremental presence list updating from
668d0d9dfa incorrectly attempted to
insert the user 1 spot later than its proper index in the listing.
2016-03-21 20:28:05 -07:00
Tim Abbott
29b8d71871 Remove throttling of presence updates coming from server events.
Now that we're doing presence updates in a performant fashion, we
don't need to throttle processing these events, and in fact the
throttling of these events created a correctness problem, since we're
now doing incremental updates rather than just rerendering everything
after each event.
2016-03-21 20:28:05 -07:00
Tim Abbott
4bb48abc0d Fix quoting bug in user presence update function.
The code in 668d0d9dfa for removing an
existing user from the user list to update the status didn't correctly
quote the email address of the user in its jquery selector.
2016-03-21 20:28:05 -07:00
Luke Faraone
5c28b0340a Don't show Zulip.com terms on other sites
While we already don't link to /terms anywhere on the site, they can still be
accessed if you navigate to /terms directly. Now, those routes will only be
exported on the Zulip.com service.

We should ideally provide a mechanism for deployments to specify their own
terms without modifying source code; in the interim, sites that have already
customised the provided Zulip.com terms can simply carry a patch reverting this
commit.
2016-03-21 05:46:28 +00:00
Luke Faraone
85d2e8d249 Add missing periods to some bullet point headings 2016-03-21 05:42:40 +00:00
Luke Faraone
27e346302c Consistently use ':'s when describing bugs in README.md. 2016-03-21 03:51:50 +00:00
Luke Faraone
b92e829d94 Fix incorrect dash used in non-Python dependency list. 2016-03-21 03:51:50 +00:00
Luke Faraone
1b4d8542a0 Minor edit to non-Python dependency description 2016-03-21 03:51:50 +00:00
Luke Faraone
d93a2bcf11 Reformat README.*.md to 70 characters uniformly.
There are some stragglers, but this is better than the previous SOTW
where line length was all over the place.
2016-03-21 03:51:49 +00:00
Tim Abbott
cd2348e9ae Run queue processers multithreaded in development.
This change drops the memory used for Python processes run by Zulip in
development from about 1GB to 300MB on my laptop.

On the front of safety, http://pika.readthedocs.org/en/latest/faq.html
explains "Pika does not have any notion of threading in the code. If
you want to use Pika with threading, make sure you have a Pika
connection per thread, created in that thread. It is not safe to share
one Pika connection across threads.".  Since this code only connects
to rabbitmq inside the individual threads, I believe this should be
safe.

Progress towards #32.
2016-03-20 18:04:24 -07:00
Tim Abbott
49b55af9cd Fix trello-to-zulip URL.
The original author had deleted his repository.
2016-03-20 17:53:43 -07:00
Alexander Pushin
888f53de13 Fix collapsing messages in narrowed views.
First user-fasing problem is that when user click to "Collapse" button
of message from narrowed list, buttons "Uncollapse" and "[More...]" does
not work. Second, is that when user collapse/uncollapse some message
from narrowed list, the collapsing/uncollapsing of the same message in
home list does not work in appropriate way.

In "popovers.js" there is the function that is called on click to the
buttons "Collapse" or "Un-collapse". It should show and hide body of a
message. If a message list is narrowed, it should show/hide message in
home list too. So, the first problem is that "toggle_row()" in this
function call methods "collapse(row)" or "uncollapse(row)" from
"condense.js" twice (for row and home_row) using condition
"if (message.collapsed)". When it happen the first time, the variable
"message.collapsed" is changed. That is why next call of "toggle_row()"
work incorrectly.

The second problem is that the function in "condense.js" that is
called on click to the button "[More...]" contains no code for
collapsing/uncollapsing message from home list. It just calls
"collapse(row)" or "uncollapse(row)" for row from narrowed list.

Now, functions "collapse(row)" and "uncollapse(row)" get row from
current list and change both messages (from current list and home
list). On-click functions call them just once for making all of needed
message changes. So, when user collapse or uncollapse message from
home or narrowed list it works correctly.

Fixes: #516
2016-03-20 16:58:57 -07:00
Tim Abbott
06e68d52ce Remove dead AsyncDjangoHandler field. 2016-03-20 16:53:13 -07:00
Tim Abbott
0419430000 Enhance Tornado logging with Handler stats.
This was useful data for debugging handler/memory leaks.
2016-03-20 16:53:13 -07:00
Tim Abbott
e51811aa9e Add comment documenting logic flow of fetch_events. 2016-03-20 16:53:13 -07:00
Tim Abbott
7fabfe9cb9 Add __repr__s for ClientDescriptor and AsyncDjangoHandler. 2016-03-20 16:53:13 -07:00
Tim Abbott
0b96e5e43f Fix connection not being closed cleanly on event queue GC.
Apparently, our event queue garbage collection logic never actually
disconnected any existing handler objects.

We fix this by disconnecting the handler inside cleanup(), adding a
special check to avoid creating a pointless timeout object.
2016-03-20 16:53:13 -07:00
Tim Abbott
3f55e26a9f Fix Tornado memory leak with synchronously handled requests.
The new Tornado handler tracking logic properly handled requests that
threw an exception or followed the RespondAsynchronously code path,
but did not properly de-allocated the handler in the syncronous case.

An easy reproducer for this is to load a new Zulip browser window;
that will leak 2 handler objects for the 2 synchronous requests made
from Django to Tornado as part of initial state fetching.
2016-03-20 16:53:13 -07:00
Tim Abbott
12a5a3a6e1 Actually fix main Tornado memory leak of handler objects.
This line appears to have been lost in rebasing from the original
implementation of 1396eb7022faec4c2d91553800a35781a96dd5bd; so the
previous fix actually only addressed the issue in a rare exception
case.
2016-03-20 16:53:12 -07:00
Vladislav Manchev
7aab17d0c0 Add several major Hubot integrations to integration docs.
Related to #335.
2016-03-20 11:50:21 -07:00
Tim Abbott
320428052a Fix AsyncDjangoHandler view exception code path.
The recent Tornado memory leak fix
(1396eb7022) didn't use the correct
variable name for the current handler ID, causing this cleanup code to
fail in the event that a view raised an exception.
2016-03-19 22:50:35 -07:00
Eklavya Sharma
9e3c3e14f5 Partially apply Python 3 libmodernize.fixes.fix_dict_six.
Refer to #256
2016-03-19 15:52:58 -07:00
Eklavya Sharma
176c507b0a Removed calls to ifilterfalse.
Replaced calls to ifilterfalse by list comprehensions because
ifilterfalse is not part of python 3.  Also changed some lists to sets
for faster lookup.

Refer to #256.
2016-03-19 15:46:31 -07:00
Eklavya Sharma
851b0a871d Fix python 3 decode error in zerver/tests.py.
Refer to #256.
2016-03-19 15:46:18 -07:00
Eklavya Sharma
186efc6a6d Handle unicode properly in camo.
In Bugdown's InlineHttpsProcessor.run, hex_encoded_url was not being
decoded to utf-8. This was causing problems in python 3.

Refer to #256.
2016-03-19 15:46:07 -07:00
Tim Abbott
f9222de83e Auto-load commonly used modules in manage.py shell.
This automatically loads settings, zerver.models.* and
zerver.lib.actions.* when you start `manage.py shell`, which should
save a bit of time basically every time someone uses it.

Fixes #275.
2016-03-19 11:32:49 -07:00
Josh Mandel
b06739df11 Move email digest triggering to default zulip config.
Previously, even though the Zulip digest emails were documented in the
settings, the cron job to run the script that actually sends the daily
digest emails wasn't included in the non-zulip.com part of the Zulip
production distribution.  The overall consequence is that digest
emails didn't work for non-zulip.com users.  This fixes that issue by
moving that cron job into the zulip manifests.

[commit message details expanded by tabbott]
2016-03-19 10:34:41 -07:00
Tim Abbott
02ccb68f7e code style: Document auto-closing GitHub issues. 2016-03-19 10:17:25 -07:00
Tim Abbott
ecc66d6eec code style: Improve the commit message style documentation. 2016-03-19 10:09:21 -07:00
Varshit
72033069ed Extend lint-all to check for newlines at the end of files. 2016-03-17 23:03:56 -07:00
Tim Abbott
3a46bae542 Fix shell script list computation to exclude files not in git.
This fixes an issue where the next commit's no-newline-and-end-of-file
check was incorrectly firing on tools/phantomjs.
2016-03-17 23:03:56 -07:00
Anindya Chakravarti
d72b8b83f7 Fixed a typo in documentation. 2016-03-17 22:53:42 -07:00
Tim Abbott
1396eb7022 Fix Tornado memory leak of handler objects.
In 2ea0daab19, handlers were moved to
being tracked via the handlers_by_id dict, but nothing cleared this
dict, resulting in every handler object being leaked.  Since a Tornado
process uses a different handler object for every request, this
resulted in a significant memory leak.  We fix this by clearing the
handlers_by_id dict in the two code paths that would result in a
Tornado handler being de-allocated: the exception codepath and the
handler disconnect codepath.

Fixes #463.
2016-03-17 18:33:59 -07:00
Vladislav Manchev
753ccf67b1 Fix regression when saving organization settings on administration page.
Saving the organization settings form in the administration did not
work due to a trivial form name mismatch caused by following
revisions: 472898c and 58aba59.
2016-03-17 18:29:04 -07:00
Tomasz Kolek
3e3a224607 Moved pagerduty webhook into its own file pagerduty.py 2016-03-14 20:44:50 -07:00
Tomasz Kolek
05dce01cee Moved travis webhook into its own file travis.py 2016-03-14 20:44:45 -07:00
Tomasz Kolek
f640470fa4 Moved zendesk webhook into its own file zendesk.py 2016-03-14 20:44:42 -07:00
Tomasz Kolek
b3e5a256f5 Moved freshdesk webhook into its own file freshdesk.py 2016-03-14 20:44:41 -07:00
Tomasz Kolek
021c66fd9a Moved stash webhook into its own file stash.py 2016-03-14 20:44:41 -07:00
Tomasz Kolek
7a4c9d243f Moved deskdotcom webhook into its own file deskdotcom.py 2016-03-14 20:44:41 -07:00
Tomasz Kolek
087bd72814 Moved bitbucket webhook into its own file bitbucket.py 2016-03-14 20:44:41 -07:00
Tomasz Kolek
93b52f6f8e Moved newrelic webhook into its own file newrelic.py 2016-03-14 20:44:41 -07:00
Tomasz Kolek
a2b31da045 Moved pivotal webhook into its own file pivotal.py 2016-03-14 20:44:41 -07:00
Tomasz Kolek
5ade895936 Moved jira webhook into its own file jira.py 2016-03-14 20:44:41 -07:00
Tomasz Kolek
a0512244b3 Moved beanstalk webhook into its own file beanstalk.py 2016-03-14 20:44:41 -07:00
Tomasz Kolek
6a3ab0605d Moved github webhook into its own file github.py 2016-03-14 20:44:41 -07:00
Tomasz Kolek
8a0ed47751 moved webhooks to python package 2016-03-14 20:44:41 -07:00
Tim Abbott
b3f731e2b5 Update documentation on Frontend buddy list performance. 2016-03-13 10:33:23 -07:00
Tim Abbott
307f25308c provision: Add support for 32-bit x86 platform.
The only places we use the architecture were for finding the
tsearch_extras and phantomjs binaries; Luke Faraone kindly uploaded
both 32-bit and 64-bit binaries for tsearch_extras 0.1.3, so with a
bit of refactoring, we can now support 32-bit.

Fixes #505.
2016-03-13 10:11:19 -07:00
Eklavya Sharma
37f9520666 Make the remaining ambiguous divisions python 3 compatible.
Refer to #256
2016-03-12 10:53:51 -08:00
Eklavya Sharma
14130a84ca Partially apply Python 3 transform libpasteurize.fixes.fix_newstyle
Refer to #256
2016-03-12 23:19:56 +05:30
Josh Mandel
d3d044ba00 Don't hide the streams gear menu.
The previous behavior of only showing it on hover was not discoverable
enough.
2016-03-12 09:28:12 -08:00
Eklavya Sharma
3ab567db98 Add call to generate-fixtures in test-backend.
Add call to tools/generate-fixtures in tools/test-backend before
starting the tests.  Previously, test-backend could fail if called
after tools/test-js-with-casper had failed.

Fixes #501.
2016-03-12 09:24:32 -08:00
Eklavya Sharma
01bfa2d94d Apply Python 3 futurize transform libmodernize.fixes.fix_unicode_type
Refer to #256
2016-03-10 22:04:15 -08:00
Eklavya Sharma
b9e792c4e6 Apply Python 3 futurize transform libmodernize.fixes.fix_xrange_six
Refer to #256
2016-03-10 22:03:58 -08:00
Eklavya Sharma
aa505b0d55 Apply Python 3 futurize transform libmodernize.fixes.fix_map
Refer to #256
2016-03-10 22:03:44 -08:00
Eklavya Sharma
7b8cb105bf Apply Python 3 futurize transform libmodernize.fixes.fix_imports_six
Refer to #256
2016-03-10 22:03:30 -08:00
Eklavya Sharma
def027a1ec Apply Python 3 futurize transform libmodernize.fixes.fix_filter
Refer to #256
2016-03-10 22:03:06 -08:00
Eklavya Sharma
d3b63f9a2d Apply Python 3 futurize transform libmodernize.fixes.fix_file
Refer to #256
2016-03-10 22:02:34 -08:00
Eklavya Sharma
e83a2c8cc2 Apply Python 3 futurize transform libmodernize.fixes.fix_basestring
Refer to #256
2016-03-10 22:02:27 -08:00
Eklavya Sharma
1941201075 Apply Python 3 futurize transform libfuturize.fixes.fix_raise
Refer to #256
2016-03-10 22:02:22 -08:00
Eklavya Sharma
c59185e119 Apply Python 3 futurize transform libfuturize.fixes.fix_print_with_import
Refer #256
2016-03-10 22:02:17 -08:00
Eklavya Sharma
3e7827358e Apply Python 3 futurize transform libfuturize.fixes.fix_next_call 2016-03-10 22:02:12 -08:00
Eklavya Sharma
e2d5ec1868 Apply Python 3 futurize transform lib2to3.fixes.fix_ws_comma 2016-03-10 22:02:04 -08:00
Eklavya Sharma
4fb549abe8 Apply Python 3 futurize transform lib2to3.fixes.fix_idioms
Refer to #256
2016-03-10 22:02:01 -08:00
Eklavya Sharma
ab7287474e Apply Python 3 futurize transform lib2to3.fixes.fix_has_key
Refer to #256
2016-03-10 22:01:55 -08:00
Eklavya Sharma
f3d387e727 Apply Python 3 futurize transform lib2to3.fixes.fix_except 2016-03-10 22:01:50 -08:00
Kartik Maji
e804185ae6 Fix subscription button in notification bot announcements.
Fixes #456.
2016-03-09 20:36:42 -08:00
Kartik Maji
3bf54e7da7 Fix opacity for muted topics within muted streams in left sidebar.
Fixes #428.

[Comment and commit message tweaked by tabbott]
2016-03-09 10:28:19 -08:00
Eklavya Sharma
4ec0d76586 Fixed a typo in README.dev.md 2016-03-08 09:19:26 -08:00
Tim Abbott
df0d2a726d python3: Add missing utf-8 encoding/decoding in various places. 2016-03-08 09:14:15 -08:00
Tim Abbott
a46647a87a python3: Mark certain strings as unicode strings.
This is required in Python 3 since these strings are combined with
other unicode strings.
2016-03-08 09:14:11 -08:00
Karambir Singh Nain
fc0a414fe6 Fixed markdown links in README and README.dev
[Patched with some tweaks by tabbott]
2016-03-08 08:44:44 -08:00
Luke Faraone
c8de86894f Add Travis CI button to README.md 2016-02-21 00:47:04 +00:00
Luke Faraone
9d9bfb27ef Correct shell quoting around $DEFAULT_USER in terminate-psql-sessions
Previously, we used shell quoting that would result in the shell variable not
being substituted. Instead, we use `"`s that will allow for variable
substitution.
2016-02-19 02:09:50 +00:00
Luke Faraone
c89d675462 Add missing wget dependency to provision.py
We also explicitly include `ca-certificates`, as it is needed for the install
to complete. Usually this is brought in as a `Recommends` of `wget`, but some
systems may not automatically include such dependencies.

Fixes #470.
2016-02-18 03:41:16 +00:00
Vladislav Manchev
668d0d9dfa Fix performance issues with user presence list in large realms.
Whenever a user became active, this triggers an immediate presence
update event (to show that user as active).  The implementation for
that event (running on the browsers of all other users in the realm)
would fully rerender the presence list, which can be an expensive
operation in a large realm, just to update the status for that one
user.  This fixes that case to just remove the user from the list and
then re-insert it at the appropriate index.

[Commit message expanded with more details by Tim Abbott]
2016-02-12 20:04:43 -08:00
Tim Abbott
784a662707 Fix documentation around iOS not supporting a custom server. 2016-02-09 21:19:57 -08:00
Tim Abbott
3a6889e19f Vagrantfile: Don't error on platforms where lxc-ls doesn't exist.
Apparently vagrant executes the configuration code for all providers,
not just the one that's actually selected.

Fixes #461.
2016-02-07 21:11:05 -08:00
Tim Abbott
cbf9b7605a Add test that all functions defined in urls.py actually exist.
This would have caught the create_user_backend issue introduced recently.
2016-02-07 19:21:53 -08:00
Reid Barton
6c6dc1d81d Allow create user API to create any user in an open realm. 2016-02-07 19:19:19 -08:00
Reid Barton
9735025167 Refactor logic around restricted_to_domain.
Add a function email_allowed_for_realm that checks whether a user with
given email is allowed to join a given realm (either because the email
has the right domain, or because the realm is open), and use it
whenever deciding whether to allow adding a user to a realm.

This commit is not intended to change any behavior, except in one case
where the Zulip realm's domain was not being converted to lowercase.
2016-02-07 10:54:52 -05:00
Reid Barton
0755b51c2e Move create_user_backend into zerver.views.users.
Commit aa33a0da moved users views into their own file, but missed this one.
2016-02-07 10:54:48 -05:00
Reid Barton
4e5f18407d Add comment in create_user_backend about not needing to invite users first. 2016-02-07 10:52:50 -05:00
Tim Abbott
d05bdbd919 Document letsencrypt in the SSL instructions. 2016-02-03 20:05:40 -08:00
Tim Abbott
34cf1f55bf Link to nginx certificate chaining documentation in SSL docs.
Fixes #430.
2016-02-03 20:05:40 -08:00
Tim Abbott
1af7cbfd64 runtornado: Move more imports to the top of the file.
This is needed for adding more specific type annotations but is
otherwise counterproductive since it increases the diff from the
original.
2016-02-03 19:47:14 -08:00
Tim Abbott
2259ce62f8 tornado: Fix AsyncDjangoHandler get() and friends missing args/kwargs. 2016-02-03 19:47:14 -08:00
Tim Abbott
1d008576f2 QueueProcessingWorker: Add stub consume function and queue_name.
QueueProcessingWorker will now throw errors if there's a misconfigured
queue processor.
2016-02-03 19:47:14 -08:00
Tim Abbott
3469fd4bb2 Fix last remaining use of file() -> open(). 2016-02-03 19:31:46 -08:00
Tim Abbott
d7b7ae2d0f rundjango: Fix confusing return line in log_message_monkey. 2016-02-03 19:31:45 -08:00
Tim Abbott
05a40f11b3 runtornado: Add explicit return None. 2016-02-03 19:31:45 -08:00
Tim Abbott
5f9cd4d7c8 populate_db: Refactor saved_data to use a consistent type. 2016-02-03 19:29:45 -08:00
Tim Abbott
c55ac01ae6 populate_db: Rename confusing sub local variable.
While the code was technically correct, elsewhere in that function sub
a Subscription object, not a tuple of ints.
2016-02-03 19:29:45 -08:00
Tim Abbott
37e987e250 Make realm_filters --show's empty list output more consistent. 2016-02-03 19:29:44 -08:00
Tim Abbott
3475a5c1ed Fix test_runner.py fast_test_only return type. 2016-02-03 19:29:44 -08:00
Tim Abbott
fcc32b1093 Fix check_redis abuse of setting self.trim global. 2016-02-03 19:29:44 -08:00
Tim Abbott
693b9110df Fix weird import of get_user_profile_by_email from decorator.py. 2016-02-03 19:29:44 -08:00
Tim Abbott
a2ef1642d1 Fix buggy report_error return value. 2016-02-03 19:29:44 -08:00
Tim Abbott
7595e4b05f process_queue: Fix worker variable being accessed before initialization. 2016-02-03 19:29:44 -08:00
Tim Abbott
b34768837d storage: Fix type error returning nothing in dry run case. 2016-02-03 19:29:44 -08:00
Tim Abbott
1ee0706511 Fix missing UTF-8 encoding. 2016-02-03 19:29:30 -08:00
Tim Abbott
df4ab3c788 run_dev: Fix return for twisted finish function.
This was flagged by mypy; it's not clear this should be needed.
2016-02-03 19:29:07 -08:00
Tim Abbott
10f15a2d00 middleware: Fix str/unicode type mismatch in statsd_path. 2016-02-03 19:29:07 -08:00
Tim Abbott
2436ad19ba analytics: Cleanup confusingly type-variable all_records. 2016-02-03 19:29:07 -08:00
Tim Abbott
23705f4f16 Remove duplicate self._log_data initialization. 2016-02-03 19:29:07 -08:00
Tim Abbott
df1670ef59 Fix various float initialization to use 0.0 instead of 0.
This is needed to type-check these values.
2016-02-03 19:29:07 -08:00
Tim Abbott
999e4688d4 Fix missing return None in ZulipRemoteUserBackend.authenticate. 2016-02-03 19:29:07 -08:00
Tim Abbott
fc02ea9f67 do_add_default_stream: Fix return value if stream exists.
Discovered using mypy static type checker.
2016-02-03 19:28:48 -08:00
Tim Abbott
ff3555734d provision: Return success from main function. 2016-02-03 19:25:19 -08:00
Tim Abbott
620411c0ea Fix type mismatches in streams.py. 2016-02-03 19:25:19 -08:00
Tim Abbott
e6e2584c5a test_runner: Cleanup fast_tests_only types. 2016-02-03 19:25:19 -08:00
Tim Abbott
ee6062691a Fix missing None in check_none_or return. 2016-02-03 19:25:18 -08:00
Tim Abbott
f03bfc5816 Fix missing prefix cache error output. 2016-02-03 19:25:18 -08:00
Tim Abbott
8654b57c7b bugdown: Move definition of current_node above set_text function using it. 2016-02-03 19:25:18 -08:00
Tim Abbott
eee36618fe run-dev: Fix overwritten manage_args variable with the wrong type.
manage_args is set to a list of arguments a few lines later in the
function, making this initialization as the empty string useless and
confusing.

Discovered using mypy.
2016-02-03 19:25:18 -08:00
Tim Abbott
8dcdb1d8a8 actions: Remove duplicate import of RealmFilter.
Apparently we were importing it twice in the same import statement.

Discovered using mypy.
2016-02-03 19:25:17 -08:00
Tim Abbott
294b7aa7bd EventsRegisterTest: Remove unused variable maxDiff.
Discovered using mypy.
2016-02-03 19:25:17 -08:00
Tim Abbott
e9f39922a0 notify_subscriptions_*: Fix use of leaked stream variable.
While I believe this actually produced correct output since users are
always subscribed to streams within their realm, this code was
definitely wrong.

Discovered using the mypy type-checking tool.
2016-02-03 19:25:17 -08:00
Tim Abbott
6c5cee2400 Cleanup 500s due to Google oauth2 errors.
These are user errors, albeit somewhat interesting ones, so they
should be logged (and return a user error response), not throw an
exception.
2016-02-02 23:08:20 -08:00
Tim Abbott
aad3bff193 Harden style rule for % comprehensions and fix existing errors. 2016-02-02 23:08:19 -08:00
Zev Benjamin
4887a79d21 Make the nginx log directory owned by zulip
This is required to make log2zulip not error out when reading the nginx
error.log.
2016-02-02 23:05:44 -08:00
Zev Benjamin
e780f5dab5 Make log2zulip error message more accurate.
In particular, in the case of a permissions issue reading the log
file, it would claim the log file doesn't exist.
2016-02-02 23:04:48 -08:00
Tim Abbott
206dc3aafc Add python 3 compatibility check for libmodernize.fixes.fix_dict_six.
It's not clear whether this will end up being net negative in value in
the long term since it's kinda hard to understand the output, but in
the short term it should prevent regressions.
2016-01-26 21:11:25 -08:00
Tim Abbott
5bacda3662 python3: Fix usage of .keys()/.values() to handle iterators.
This fixes the places where we use the result of .keys(), .items(),
and .values() that wouldn't work with an iterator to wrap them with
list().
2016-01-26 21:11:25 -08:00
Tim Abbott
f5de149976 python3: specify explicit sorting algorithm for subscriptions. 2016-01-26 21:11:25 -08:00
Tim Abbott
05a827c520 need_to_render_content: Fix comparison with None.
If the content wasn't rendered, both rendered_content and
rendered_content_version would be None.  In addition to being
confusing, in Python 3, `None < 2` is an error and this code breaks.
2016-01-26 21:11:25 -08:00
Tim Abbott
bd0918cd5a python3: Use zip from the six.moves package. 2016-01-26 21:11:24 -08:00
Tim Abbott
757e89260e Migrate use of StringIO to Python 2+3 compatible six.moves.cStringIO.
And add a check for additional usage of the original StringIO module.
2016-01-26 21:09:43 -08:00
Tim Abbott
1f44417fc1 Switch to using Python 3 style division everywhere.
Also add testing for this to our Python 3 compatibility test suite.
2016-01-26 21:09:43 -08:00
Tim Abbott
6528b18ad3 Switch all urllib/urlparse usage to six.moves.urllib.
This provides Python 2+3 compatibility for our use of urllib.

Also add a test to avoid future regressions.
2016-01-26 21:09:43 -08:00
Tim Abbott
52f9574047 Fix missing python-six dependency for Zulip API. 2016-01-26 21:09:42 -08:00
Tim Abbott
700055c194 Apply modernize transform libmodernize.fixes.fix_file.
This replaces use of file() with open() which is python 3 compatible,
and also adds it to our python 3 support test suite.
2016-01-26 21:09:42 -08:00
Tim Abbott
83dd51dcd6 Remove now-obsolete get_message_by_id_dbwarn transition code. 2016-01-26 21:05:11 -08:00
Tim Abbott
eecd1513b3 Don't access/store full Client objects in Tornado queue servers.
At present, we only do a few simple checks on the client type inside
the event system, and this saves database/memcached queries.

Note that this preserves the structure of the marshalled name in
to_dict/from_dict as client_type to avoid an unnecessary migration.
2016-01-26 21:04:32 -08:00
Tim Abbott
e3b6bfa3ca Remove code for pickle event queue store.
Since we've had the JSON store in all environments for some time, we
no longer need this legacy code.
2016-01-26 20:59:34 -08:00
Tim Abbott
f6073d1708 Move HTTPResponse construction out of event_queue.py. 2016-01-26 20:59:19 -08:00
Tim Abbott
a9bf4b4cc7 Store the client name for the current handler in ClientDescriptor. 2016-01-26 20:58:01 -08:00
Tim Abbott
c7e3c3ce38 Look up client descriptors by handler_id.
Previously, client descriptors were referenced directly from the
handler object.  Once we split the Tornado process into separate queue
and connection servers, these will no longer be in the same process,
so we need to reference them by ID instead.
2016-01-26 20:57:25 -08:00
Tim Abbott
ea6211c041 Allocate handler ids in AsyncDjangoHandler setup process. 2016-01-26 20:56:53 -08:00
Tim Abbott
ae760a351e Move most of ClientDescriptor.finish_current_handler into library. 2016-01-26 20:56:08 -08:00
Tim Abbott
7df61fccbd Add user_profile_email field to ClientDescriptor. 2016-01-26 20:55:59 -08:00
Tim Abbott
2ea0daab19 Track Tornado handlers by uniquely assigned IDs rather than objects.
This is early preparation for splitting apart Tornado into a queue
server and a frontend server.
2016-01-26 20:55:41 -08:00
Tim Abbott
8b42fdd0d7 Move get_events logic into a backend function in event_queue.py.
This commit is somewhat ugly, but its purpose is to be early
preparation for splitting Tornado into a queue server and a frontend
server, and this code belongs, by and large, in the queue server
component.
2016-01-26 20:51:54 -08:00
Tim Abbott
5a6154c8ba test_helpers: Fetch streams from cache in subscribe_to_stream. 2016-01-26 20:41:01 -08:00
Tim Abbott
a5d4d0aae0 test_backend: Add option to profile the backend test suite. 2016-01-26 20:41:01 -08:00
Tim Abbott
f9791558e9 test_runner: Support continuing running tests after a failure. 2016-01-26 20:41:01 -08:00
Tim Abbott
b43aadad8b test-backend: Rewrite in python to support computing test coverage.
The code for doing test coverage is just a lot cleaner this way over
adding it to the shell script version.

Based on the basic test runner code here:
https://docs.djangoproject.com/en/1.9/topics/testing/advanced/
2016-01-26 20:41:01 -08:00
Tim Abbott
24fd3bbf55 travis: Test whether migrations are consistent with models.
This should automatically catch mistakes where someone updates the
database models but forgets to generate migrations afterwards.
2016-01-26 20:38:46 -08:00
Tim Abbott
5ef57a07e1 Add missing migrations present in models.py.
89a2765553 didn't include the database
migration corresponding to the change, which means it didn't take full
effect when it was merged.

I noticed this because `manage.py makemigrations` would generate these
migrations; that suggests a good idea for a test to add.
2016-01-26 20:38:46 -08:00
Tim Abbott
1c73c992dd Fix missing puppet dependencies on postgres package. 2016-01-26 20:32:33 -08:00
Tim Abbott
2e16b44b24 puppet: Use $postgres_version in postgres template.
This eliminates hardcoding of the postgres version from the Zulip
puppet configuration.
2016-01-26 20:32:33 -08:00
Tim Abbott
806aa986b7 puppet: Use a variable to configure the postgres version. 2016-01-26 20:32:33 -08:00
Tim Abbott
a3ac56efe2 puppet: Make apt repository conditional on the Ubuntu version.
We still will need to address this in the install script as well.
2016-01-26 20:32:33 -08:00
Tim Abbott
f6c59feb05 Document the puppet configuration somewhat in zulip::voyager. 2016-01-26 20:32:33 -08:00
Tim Abbott
345b5254d7 puppet: Move default nginx configuration out of voyager.pp. 2016-01-26 20:32:33 -08:00
Tim Abbott
dd61e3f97d puppet: Move memcached and rabbitmq include out of app_frontend_base.pp. 2016-01-26 20:32:33 -08:00
Tim Abbott
c3153274c1 puppet: Move memcached into its own puppet module. 2016-01-26 20:32:33 -08:00
Tim Abbott
8a0e07fe1a puppet: Rename app_frontend.pp to app_frontend_base.pp.
This will enable us to move the remaining app-frontend related content
out of voyager.pp.
2016-01-26 20:32:33 -08:00
Tim Abbott
91286d00aa puppet: Move Zulip apt repository to its own manifest. 2016-01-26 20:32:33 -08:00
Tim Abbott
69dd17dfb6 puppet: Move prod-static creation from voyager.pp to app_frontend.pp.
Every app frontend will need this directory and this should help
enable more modular puppet rules.
2016-01-26 20:32:33 -08:00
Tim Abbott
702f501638 puppet: Move tuned postgres configuration out of voyager.pp.
This should make it easier for someone to run just the tuned Zulip
database on one server and the Zulip frontend on another.
2016-01-26 20:32:28 -08:00
Tim Abbott
d5f04bd20b Rename zulip::postgres_appdb to zulip::postgres_appdb_base.
The purpose of this rename is to allow us to move the postgres-related
configuration out of voyager.pp.
2016-01-26 20:30:12 -08:00
Tim Abbott
3f27573cb2 puppet: Move several debugging tool dependencies out of base.pp. 2016-01-26 20:30:11 -08:00
Tim Abbott
fdc7f5b86a Vagrantfile: Default to using LXC when Virtualbox is also available.
This solves the problem reported in #331 with needing to specify
--provider=lxc to use the LXC provider in an Ubuntu Linux environment;
additionally, it adds the LXC option needed to run LXC on Ubuntu
15.10, but not on 14.04 where that option is unavailable and would
totally break LXC.
2016-01-23 11:45:47 -08:00
Tim Abbott
50bc32dc95 integrations: Document server-side setup for twitter integration. 2016-01-23 11:44:53 -08:00
Tim Abbott
c6d06b0c4e Add zulip distribution tarballs to backups. 2016-01-23 11:44:15 -08:00
Tim Abbott
529d7a2877 Release API version 0.2.5. 2016-01-23 11:38:47 -08:00
Tim Abbott
d3588cb7d0 api: Include get_subscribers endpoint in public release.
It's possible we should just eliminate this mechanism, but this fixes
a proximal problem where the multi-line get_subscribers endpoint
description was being handled wrong.
2016-01-23 11:38:42 -08:00
Tim Abbott
fdf708039b Disable empty-stream notifications for email gateway bot. 2016-01-23 11:37:52 -08:00
Vladislav Manchev
df4d1b3c14 Add linting code for detecting shebang bashisms.
This will prevent regressions in OpenBSD compatibility, since OpenBSD
doesn't support passing arguments in the #! line.
2016-01-21 22:33:55 -08:00
Vladislav Manchev
dfbea01c8f Add support for running OpenBSD in development environment. 2016-01-21 22:33:55 -08:00
Alexander Trost
84f7a1f1ea Make rabbitmq, redis, and memcached configurable via user settings.py.
Previously these were hardcoded in zproject/settings.py to be accessed
on localhost.

[Modified by Tim Abbott to adjust comments and fix configure-rabbitmq]
2016-01-21 22:07:56 -08:00
Tim Abbott
6943a142ea Fix postgres errors in Travis CI again.
Travis CI's model of installing every version of postgres on the test
VM and then shutting all the versions other than the one requested
down seems to not work very well with doing apt upgrades.  It seems
the best way to resolve this is to just uninstall the versions we
don't need.
2016-01-21 22:07:10 -08:00
Tim Abbott
e1e7ea01ca Add changelog for Zulip 1.3.10 release. 2016-01-21 20:24:53 -08:00
Vladislav Manchev
62d021f399 Change administration UI to utilize tabs. 2016-01-12 22:08:10 -08:00
Reid Barton
ed412281d0 Fix typo in Google OAuth error message. 2016-01-12 09:32:09 -05:00
Tim Abbott
5d54f66047 get_deployment_lock: Flush output when reporting lock delays.
This fixes an issue where the output that the lock wasn't unavailable
showed up all at once after the 5 minute timeout.
2016-01-11 21:36:42 -08:00
Tim Abbott
26e9d55e16 deployments: Refactor locking libraries into zulip_tools.py.
The code in update-deployment and upgrade-zulip for managing the
deployment lock was nearly identical.
2016-01-11 21:36:42 -08:00
Tim Abbott
f871090bb6 upgrade-zulip: Archive release tarballs at /home/zulip/archives.
A common issue when doing a Zulip upgrade is trying to pass
upgrade-zulip a tarball path under /root, which doesn't work because
the Zulip user doesn't have permission to read the tarball.  We
could fix this by just unpacking the tarballs as root, but it seemed
like a nicer approach would be to archive the release tarballs
somewhere readable by the Zulip user (/home/zulip/archives) and unpack
them from there.

Fixes #208.
2016-01-11 21:36:42 -08:00
Tim Abbott
c101bf663d Run upgrade-zulip-stage-2 from an absolute path.
This should make it more obvious in tracebacks that we are running the
script from the version of Zulip we're upgrading to, not the old
version.
2016-01-11 21:36:42 -08:00
Tim Abbott
52d0423591 Document structure of upgrade-zulip-stage-2 more clearly. 2016-01-11 21:36:41 -08:00
Tim Abbott
186f563176 Fix deployment locks being leaked when a deployment fails.
The point of the lock is to prevent two deployments happening at the
same time and racing with each other, not to prevent doing any future
deployments after an error happens (which is what the current
implementation does in practice).

Addresses part of #208.
2016-01-11 21:36:41 -08:00
Tim Abbott
2b0394d807 Add documentation explaining what process_fts_updates does. 2016-01-11 08:56:03 -08:00
Tim Abbott
0162dc4bc0 process_fts_updates: Cleanup and document new settings import logic. 2016-01-11 08:56:03 -08:00
Javier Ros
a6a47aacde Add easy support for using a remote postgres database. 2016-01-11 08:56:03 -08:00
Tim Abbott
e3435b9613 Fix broken link to the cute guinea pig image in tutorial.
This link was broken when we hardened the access model for user file
uploads to not work cross-realm.  The right solution is just to
include the image in the codebase so it's guaranteed to exist.

Fixes #205.
2016-01-09 22:52:35 -08:00
Tim Abbott
6d29dd2884 Fix do_remove_default_stream handling of nonstandard input.
Previously:
* It wouldn't raise an exception if the stream didn't exist
* It didn't correctly handle being passed a stream name
that differed in case from the stream name in the database.
2016-01-09 22:52:35 -08:00
Tim Abbott
8099aa5470 Fix passing notifications_stream to set_default_streams.
Previously, this would throw an IntegrityError, because it had just
been added in the loop.
2016-01-09 22:52:35 -08:00
Tim Abbott
c661bc17fb Fix support for having a unique, open realm.
The previous implementation didn't work because HomepageForm rejected
the email as not having a domain.  Additionally, the logic in
accounts_register didn't work with Google auth because that code path
doesn't pass through accounts_home.  Since whether there's a unique
open realm for the server is effectively a configuration property, we
can fix the bug and make the logic clearer by moving it into the
"figure out the user's realm" function.
2016-01-09 22:52:34 -08:00
Tim Abbott
515249ce0a trac: Cleanup documentation of TRAC_NOTIFY_FIELDS. 2016-01-09 20:21:39 -08:00
Tim Abbott
85a8a742e2 Remove unused json_events_register route.
The browser registers for events via loading the home view, not this
interface, and this functionality is available via the API-format
register route anyway.
2016-01-09 20:01:38 -08:00
Tim Abbott
bddf971554 alert_words: Only fetch and cache non-null alert word sets.
This removes from our cache a moderate amount of totally useless alert
word data corresponding to users who don't have any alert words.

Thanks to @dbiollo for the suggestion!
2016-01-09 20:01:38 -08:00
Tim Abbott
84114ab31f Simplify realm_user_count to do just do a database count() query.
Just doing the database query is more readable, and has about the same
performance as before in the case where active user dicts for the
realm are in cache (and is substantially better in the rare case that
this isn't in the cache).

Thanks to @dbiollo for the perf investigation and suggestion!
2016-01-09 20:01:37 -08:00
Tim Abbott
01f613751a Limit DevAuthBackend user list display to 100 users.
This makes it possible to use DevAuthBackend when doing
performance/scalability testing on Zulip with many thousands of users.

It's unlikely that anyone testing this backend will find it valuable
to have more than 100 login buttons on the same page, and if they do,
they can always just change this limit.

Thanks to @dbiollo for the suggestion!
2016-01-09 20:01:37 -08:00
Tim Abbott
dd4ca2f934 Add case-insensitive index on PreregistrationUser.email.
This fixes a performance issue joining a server with a large number of
users.

Thanks to @dbiollo for the suggestion!
2016-01-09 20:01:37 -08:00
Tim Abbott
2ea0fce47e Add UserProfile indexes on is_active and is_bot.
Since we frequently do filters for only active users, these indexes
may help performance in some cases.
2016-01-09 20:01:37 -08:00
Tim Abbott
ebcb569c96 Add case-insensitive index on UserProfile.email.
This fixes a performance issue looking up UserProfile objects for
realms with a large number of users in the case that a UserProfile
object is not in the cache.

Thanks to @dbiollo for the suggestion!
2016-01-09 20:01:37 -08:00
Tim Abbott
a98b0cf35d travis: Workaround postgres 9.1 conflict issues on trusty.
We ran into a bug with the Travis CI infrastructure where it postgres
9.1 is installed on the system, and so when we'd do an apt upgrade
with a new version of 9.1, the 9.1 daemon would end up getting started
and conflict with the 9.3 daemon we were trying to run.
2016-01-09 16:59:43 -08:00
Tim Abbott
e7353902df upgrade-zulip: Restart process-fts-updates if also a DB host.
Previoulsy, process-fts-updates wouldn't be restarted on a server
upgrade in Voyager configurations.
2016-01-09 16:59:43 -08:00
Tim Abbott
75b5a1b8da upgrade-zulip: Stop zulip-senders too when shutting down services. 2016-01-09 16:59:43 -08:00
Tim Abbott
bed847e029 travis: Cache the phantomjs package downloads between builds.
This should hopefully fix the issue we've been seeing with
bitbucket.org rejecting connections from Travis CI by not needing to
connect to them.
2016-01-09 15:46:29 -08:00
Tim Abbott
408ff14be8 Fix parsing html_unescape.py in py3k test.
This file was using print as a function but didn't import
print_function; as a result futurize threw an error every time it
parsed this file.
2016-01-09 15:43:30 -08:00
Tim Abbott
24ebc10ec8 Travis: Display all errors, not just first one, in py3k testing. 2016-01-09 15:43:26 -08:00
Tim Abbott
1cfde054ff Initialize new_message_count to 0 by default.
860cf68716 introduced calls to
notifications.redraw_title() on narrow activation.  This introduced a
bug when the Zulip desktop app reloads while narrowed --
new_message_count would still be set to undefined when
narrow.activate() is called as the page (re)loads, and thus we'd call
window.bridge.updateCount(undefined), resulting in a traceback.

We fix this by just initializing it to 0, rather than using the old
default value of undefined.
2016-01-09 15:43:20 -08:00
Tim Abbott
24e4a33a0e Document the Zulip security model. 2016-01-08 07:52:25 -08:00
Tim Abbott
7f7bb1caee Add extensive new documentation on backups, monitoring, scalability. 2016-01-08 07:52:25 -08:00
Josh Mandel
9ebd80ddba Add "apple-mobile-web-app-capable" meta to HTML.
This allows full-screen mode when launching from a saved app link
(mobile browser -> save link to home screen).  This works on Android,
too, despite the "apple-" prefix.
2016-01-07 23:08:52 -08:00
Josh Mandel
bdb9535251 Don't require link tags to close when checking templates. 2016-01-07 23:08:49 -08:00
Tim Abbott
7ad7e7a082 Changelog: Update with items since the last release. 2015-12-25 16:50:05 -08:00
Tim Abbott
99975400df Move LDAP password configuration to zulip-secrets.conf. 2015-12-25 16:47:48 -08:00
Tim Abbott
af8d75332c Move email_gateway_password to zulip-secrets.conf. 2015-12-25 16:47:48 -08:00
Tim Abbott
8b1d7d7018 Fix missing step in postfix_localmail installation documentation. 2015-12-25 16:47:48 -08:00
Tim Abbott
f4e87936da Silence 'Starting new HTTP connection' logs from requests library. 2015-12-25 16:23:57 -08:00
Tim Abbott
870734fca2 Configure webpack to only display output in case of errors. 2015-12-25 16:23:57 -08:00
Tim Abbott
9d108989f3 Silence SimpleQueueClient info output by default. 2015-12-25 16:23:57 -08:00
Tim Abbott
c5f08022f9 tools/clean-repo: Don't print out the list of .pyc files deleted.
This was never useful output and was pretty spammy.
2015-12-25 16:23:57 -08:00
Tim Abbott
b879b7ff42 Use logger.debug when logging 200/304 output on static assets. 2015-12-25 16:23:57 -08:00
Tim Abbott
dfaf45b2b6 Wrap Django runserver to prevent spammy logging.
Django's `manage.py runserver` prints a relatively low-information log
line for every request of the form:

[14/Dec/2015 00:43:06]"GET /static/js/message_list.js HTTP/1.0" 200 21969

This is pretty spammy, especially given that we already have our own
middleware printing a more detailed version of the same log lines:

2015-12-14 00:43:06,935 INFO     127.0.0.1       GET     200   0ms /static/js/message_list.js (unauth via ?)

Since runserver doesn't have support controlling whether these log
lines are printed, we wrap it with a small bit of code that silences
the log lines for 200/304 requests (aka the uninteresting ones).
2015-12-25 16:23:57 -08:00
Tim Abbott
be9939b2ad Fix tracebacks if HTTP_USER_AGENT is not specified.
Previously, we handled this correctly in some places (like the
decorators) but not in the website flows (accepting ToS, loading /).
2015-12-25 16:23:11 -08:00
Tim Abbott
39e80b351d Add simple tools for fetching content of a pull request by ID. 2015-12-25 16:22:00 -08:00
Reid Barton
b2a92877ff Don't print echo commands in initialize-database post-success message. 2015-12-25 10:38:44 -08:00
Reid Barton
4c3334908a Document that 'localhost' is necessary in ALLOWED_HOSTS.
It's needed for the tornado server. Otherwise, you get errors like

2015-12-20 09:33:55,124 ERROR    Internal Server Error: /api/v1/events
Traceback (most recent call last):
  File "/home/zulip/deployments/2015-12-20-13-44-47/zerver/management/commands/runtornado.py", line 209, in get_response
    response = middleware_method(request)
  File "/usr/lib/python2.7/dist-packages/django/middleware/common.py", line 62, in process_request
    host = request.get_host()
  File "/usr/lib/python2.7/dist-packages/django/http/request.py", line 101, in get_host
    raise DisallowedHost(msg)
DisallowedHost: Invalid HTTP_HOST header: 'localhost:9993'. You may need to add u'localhost' to ALLOWED_HOSTS.
2015-12-25 10:07:12 -08:00
Reid Barton
64a142f0a2 Fix running postgres-init-db via a relative path.
If the user runs ./scripts/setup/postgres-init-db, then dirname "$0"
would no longer refer to the correct directory after cd /.
2015-12-25 10:06:45 -08:00
Kara McNair
fd66d9f703 Show 5 most recent "Private messages" when clicked.
Like the Stream Subject lists, Private messages are now shown
when the user clicks on the "Private message" link. User can drill in
to get more than 5 conversations. Selecting PMs from the user or group
PM lists on the right sidebar also opens the list & highlights the
selected conversation.

[Edited by tabbott@mit.edu to fix some small bugs.]
2015-12-15 07:52:54 -08:00
Tim Abbott
29fa601328 Rename active-subject-filter to active-sub-filter.
This makes the name more generic so we can reuse it for private
message filters as well.
2015-12-15 07:52:54 -08:00
Tim Abbott
87acb2be09 stream_list: Factor out reset_to_unnarrowed helper. 2015-12-15 07:52:54 -08:00
Tim Abbott
c404f3189c stream_list: move remove_expanded_subjects earlier in file. 2015-12-15 07:52:54 -08:00
Tim Abbott
7bb11fe09a topic zoom: Clean up unnecessary jquery selectors. 2015-12-15 07:52:54 -08:00
Liz Sander
860cf68716 Show current narrow in page title.
Fixes issue #157.
2015-12-14 21:21:30 -08:00
Javier Ros
ab89ef501f Add support for a development environment with Docker. 2015-12-14 18:22:56 -08:00
Tim Abbott
e95739961f Remove now obsolete /json/send_message route. 2015-12-12 18:14:08 -08:00
Tim Abbott
9cec758854 Remove now obsolete /json/subscriptions/add endpoint. 2015-12-12 18:14:08 -08:00
Allie Jones
1bd1291f3c Replace json/send_message endpoint usage with json/message. 2015-12-12 18:14:08 -08:00
Allie Jones
29a4b51e52 Replace /json/subscriptions/add usage with /json/users/me/subscription. 2015-12-12 18:14:08 -08:00
Tim Abbott
023f45190f rest_dispatch: Add support for using with websockets integration. 2015-12-12 18:14:08 -08:00
Kara McNair
c947f3ed3c Add Zulip-specific details in jslint used_before_a error message.
Previously, it wasn't clear why you were getting an error when trying
to reference a newly added global variable.
2015-12-07 20:33:36 -08:00
Tim Abbott
2be7ac8d70 travis: Fix prompting for user input in production-helper. 2015-12-07 20:33:36 -08:00
Tim Abbott
0fe819eb57 lint: Tighten lint rules around whitespace around '%' comprehensions. 2015-12-05 15:29:42 -08:00
Tim Abbott
69b6b60017 lint: Clean up whitespace_rules.
Several of these rules only apply to one of Python and Javascript, and
this simplifies the logic and should make our linter code more readable.

In the process, we add support for per-rule/file pair exclusions to
handle the tab exception for codehilite.py.
2015-12-05 15:29:42 -08:00
Tim Abbott
a712954c59 lint: Rewrite custom checks to use a more consistent framework. 2015-12-05 15:29:42 -08:00
Tim Abbott
8a18e78a65 Add lint rules checking for our % comprehension style. 2015-12-05 15:29:42 -08:00
Tim Abbott
a79e89b28f Cleanup remaining usage of % comprehensions without explicit tuples. 2015-12-05 15:29:42 -08:00
Tim Abbott
74853709a8 Rename NOTIFICATION_STREAM_NAME to clarify it's a default. 2015-12-05 14:14:44 -08:00
Tim Abbott
6b1494927d set_default_streams: Don't force-create notifications stream. 2015-12-05 14:14:44 -08:00
Tim Abbott
0ce14bec44 test_set_default_streams: Use a newly created test realm.
The test "zulip.com" realm seems to not have notifications_stream set.
2015-12-05 14:11:45 -08:00
Josh Mandel
716e2d9184 Add integration for Travis CI. 2015-11-30 20:41:33 -08:00
Tim Abbott
05acd510c0 Make reload save options required explicit arguments. 2015-11-30 08:49:39 -08:00
Tim Abbott
12bff0441c Save compose state when reloading due to 'declare bankruptcy'. 2015-11-30 08:49:37 -08:00
Dylan Dumesnil
2f4037ae2f Save compose state when reloading due to /json/get_events error.
Fixes #203.
2015-11-30 08:47:36 -08:00
Dylan Dumesnil
24b63f30ba Refactor reload.js to allow saving only some state when reloading.
The reload state is now divided into 3 different components:
  pointer, narrow, compose
2015-11-30 08:47:36 -08:00
Jason Michalski
9a3331acaf Run provision.py outside of the virtualenv
By default we are placed inside a virtualenv by the .bash_profile using
/usr/bin/python forces the provisioning script to run outside of this
virtualenv.
2015-11-25 19:29:13 -08:00
Tim Abbott
cd0a8e7e5a Marshall tutorial route inputs as JSON strings.
These routes previously didn't follow our standard convention of
sending arguments in JSON format, and so broke when we started
checking the argument format in
123d51e3aa.

Fixes #333.
2015-11-24 22:46:25 -08:00
Chris Chapman
44a9e1dff5 Fix for setting file upload size through settings file.
(Slightly tweaked by Tim Abbott to change the variable name, docs, and
default values).

Fixes #276.
2015-11-24 06:06:46 -08:00
Tim Abbott
07419104a5 nginx: Enable gzip compression on main content types.
Apparently, previously nginx was only compressing text/html content.
This should result in a substantial savings in network traffic -- some
quick testing I did found it cut the total data transferred for
loading a logged-in zulip.com instance from 3MB to 1.2MB.
2015-11-24 05:21:49 -08:00
Tim Abbott
123d51e3aa Add string validators to tutorial routes. 2015-11-24 05:20:37 -08:00
Tim Abbott
aa33a0daec Move users views into their own file. 2015-11-24 05:20:37 -08:00
Tim Abbott
4d79083cf5 Move tutorial views into their own file. 2015-11-24 05:20:37 -08:00
Tim Abbott
f77b0bdb43 Move alert_words views into their own file. 2015-11-24 05:20:37 -08:00
Tim Abbott
e64a3d0fae Move reporting views to their own file. 2015-11-24 05:20:37 -08:00
Tim Abbott
8526d02370 Move settings views into their own file. 2015-11-24 05:20:37 -08:00
Tim Abbott
37d4a11610 Move streams views into their own file. 2015-11-24 05:20:37 -08:00
Tim Abbott
6a8318ddcd Add istanbul for running node coverage reports.
`tools/test-js-with-node cover` needs istanbul to be installed in
order to work; we might as well install it by default rather than
having it be an extra step users need to deal with.

Of course, since this is only needed in the development environment,
this could suggest we want to fork/conditionalize package.json, but I
think for now it's reasonable to just install everything we use
somewhere -- the npm list is still pretty short and we have that issue
anyway with webpack-dev-server.
2015-11-24 05:20:15 -08:00
Josh Mandel
15dae10383 Only show "Sign up with google" when enabled 2015-11-24 06:13:09 +00:00
Luke Faraone
db5c460cfc Run django.setup() in nagios plugins to avoid exceptions on 1.8
If running on Django 1.8, running these plugins would die with the below. A fix
for this is to run `django.setup()` before interacting with Django.

Refs:
    https://docs.djangoproject.com/en/1.8/ref/applications/#troubleshooting

```

Traceback (most recent call last):
  File "/usr/lib/nagios/plugins/check_send_receive_time", line 103, in <module>
    sender = get_user_profile_by_email(settings.NAGIOS_SEND_BOT)
  File "/home/zulip/deployments/current/zerver/lib/cache.py", line 113, in func_with_caching
    val = func(*args, **kwargs)
  File "/home/zulip/deployments/current/zerver/models.py", line 1073, in get_user_profile_by_email
    return UserProfile.objects.select_related().get(email__iexact=email.strip())
  File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 328, in get
    num = len(clone)
  File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 144, in __len__
    self._fetch_all()
  File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 977, in _fetch_all
    self._result_cache = list(self.iterator())
  File "/usr/lib/python2.7/dist-packages/django/db/models/query.py", line 238, in iterator
    results = compiler.execute_sql()
  File "/usr/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 829, in execute_sql
    sql, params = self.as_sql()
  File "/usr/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 378, in as_sql
    extra_select, order_by, group_by = self.pre_sql_setup()
  File "/usr/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 48, in pre_sql_setup
    self.setup_query()
  File "/usr/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 39, in setup_query
    self.select, self.klass_info, self.annotation_col_map = self.get_select()
  File "/usr/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 206, in get_select
    related_klass_infos = self.get_related_selections(select)
  File "/usr/lib/python2.7/dist-packages/django/db/models/sql/compiler.py", line 700, in get_related_selections
    [f.name], opts, root_alias)
  File "/usr/lib/python2.7/dist-packages/django/db/models/sql/query.py", line 1471, in setup_joins
    names, opts, allow_many, fail_on_missing=True)
  File "/usr/lib/python2.7/dist-packages/django/db/models/sql/query.py", line 1372, in names_to_path
    if field.is_relation and not field.related_model:
  File "/usr/lib/python2.7/dist-packages/django/utils/functional.py", line 60, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/usr/lib/python2.7/dist-packages/django/db/models/fields/related.py", line 110, in related_model
    apps.check_models_ready()
  File "/usr/lib/python2.7/dist-packages/django/apps/registry.py", line 131, in check_models_ready
    raise AppRegistryNotReady("Models aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
```
2015-11-23 18:54:08 +00:00
Allie Jones
11c69fb0b2 Add documentation on the front end build process and webpack. 2015-11-20 20:32:01 -08:00
Allie Jones
4f9ef4ca29 Update list of by-hand installation apt-get packages to match the list in provision.py 2015-11-20 10:22:15 -08:00
Allie Jones
8f24beec21 Update by-hand installation instructions to include node/npm 2015-11-20 10:22:13 -08:00
Tim Abbott
1a01e65be2 Expand and reorganize .gitignore content.
Primarily this makes sure all the log files we generate are ignored.

A good follow-up project to this would be to move all the log files to
a fixed directory so that they're not creating a mess in the main
filespace.
2015-11-19 09:12:08 -08:00
Tim Abbott
4474a11a3a Administration: Move deactivated users section to more sensible place. 2015-11-16 21:10:06 -08:00
Tim Abbott
58aba59e36 Apply the nice settings page CSS to the Administration page. 2015-11-16 21:10:06 -08:00
Tim Abbott
be112d2c9d SlowQueryWorker: Don't reference potentially unset STATSD_PREFIX. 2015-11-16 21:10:06 -08:00
Tim Abbott
5fa6260ae8 Add changelog for Zulip 1.3.9 release. 2015-11-16 08:46:48 -08:00
Tim Abbott
7395003e6a Fix buggy #! lines using "/usr/bin/env python2.7 -u".
The #! line processing interpreted the argument to pass to `env` as
"python2.7 -u", which obviously isn't a real program.

We fix this by setting the PYTHONUNBUFFERED environment variable
inside the program, which has the same effect.

Thanks to Dan Fedele for the bug report and suggested solution!
2015-11-16 08:46:48 -08:00
Tim Abbott
ac35d26868 Add changelog for Zulip 1.3.8 release. 2015-11-15 14:58:52 -08:00
Tim Abbott
788b688935 Document upgrade process complications around puppet. 2015-11-15 14:58:52 -08:00
Tim Abbott
bd817fba97 Expand documentation on how to use the development environment.
* Reorganize to cover how to use the VM regardless of install process
  used.
* Document exactly what you need to do in order to see your changes.
* Remove the now-inaccurate documentation about flaky casper tests.
* Point to the testing documentation.
2015-11-15 14:31:40 -08:00
Tim Abbott
abdb148f42 Clarify instructions for setting up the S3 integration.
These instructions still aren't great due to #291, but at least this
is clear about how to get this working.
2015-11-15 13:50:12 -08:00
Tim Abbott
d06cb5d55a Expand documentation on writing and debugging Casper tests. 2015-11-11 21:36:00 -08:00
Tim Abbott
0cbedd6b0c Add casper tests for administration page user/bot (re/de)activation.
This should prevent future regressions like the one fixed in #243.
2015-11-11 21:35:55 -08:00
Tim Abbott
827babdf29 terminate-psql-sessions: Remove dependency on bc.
Fixes #281.
2015-11-11 21:35:16 -08:00
Tim Abbott
9d75fd33d9 Add new test for management commands running with --help.
This test caught a few bugs where refactoring had made management
commands fail (and would have caught a few more recent ones).

Ideally we'd replace this with a more advanced test that actually
tests that the management command do something useful, but it's a
start.
2015-11-11 21:34:39 -08:00
Tim Abbott
16ae985807 profile_request: Fix get_old_messages_backend import. 2015-11-11 21:34:39 -08:00
Tim Abbott
3e794351ab Remove expunge_* management commands.
These management commands never worked and given that we removed the
retention_policy code that they call, it makes sense to remove them as
well.
2015-11-11 21:34:39 -08:00
Tim Abbott
6718c85b13 Add troubleshooting documentation for the remote user SSO setup. 2015-11-11 21:33:52 -08:00
Tim Abbott
b81ecc4064 Add whitespace lint rules checking for missing spaces before {. 2015-11-10 10:06:47 -08:00
Tim Abbott
5f25974737 Fix Javascript whitespace issues with {. 2015-11-10 10:01:34 -08:00
Walter Heck
f145b01d91 Update create_user management command.
notify_new_user was recently moved to zerver.lib.actions from
zerver.views and this wasn't properly updated. This would give an
error when doing a `manage.py create_user` from the command line.
2015-11-08 19:41:00 -08:00
Tim Abbott
9b4c440e0d apps: Fix linking to SSO versions of desktop app.
The SSO build of the desktop app is intended only for those users who
who have settings.SSO_ONLY set, i.e. the only way to login is via the
site's SSO REMOTE_USER authentication.  We were incorrectly linking to
it on all production installations :(.
2015-11-06 09:51:25 -08:00
Tim Abbott
123f21c46b README.prod: Fix old requirements documentation. 2015-11-06 09:47:26 -08:00
Tim Abbott
2d0fbd068f Document how to revert to a previous version in upgrade process. 2015-11-06 09:45:41 -08:00
Tim Abbott
29706275df Document how to find the old realm if you've changed ADMIN_DOMAIN. 2015-11-06 09:45:41 -08:00
Tim Abbott
c3c4062ec7 Fix missing quotes in ADMIN_DOMAIN change docs. 2015-11-06 09:45:41 -08:00
Tim Abbott
61cb2ce883 Document how to clone the Zulip repository on Windows.
Fixes #272.
2015-11-06 09:45:41 -08:00
Tim Abbott
7c1b438ab0 Expand the Vagrant installation documentation significantly.
Thanks to Omar Farooq (o3dwade) for an early version of this!
2015-11-06 09:45:41 -08:00
Tim Abbott
5ffa2186d0 Merge common portions of the Fedora/CentOS development instructions.
There's still some parts of the CentOS 7 instructions that we may be
able to just delete.
2015-11-06 09:45:41 -08:00
Tim Abbott
0b77eb0291 Fix headings in installation instructions. 2015-11-06 09:45:41 -08:00
Tim Abbott
55ddc35b90 Move development installations instructions to a separate file.
This will make the core README.md file cleaner.
2015-11-06 09:45:41 -08:00
Tim Abbott
8181a0423f Fix some small issues with the CentOS/Fedora instructions. 2015-11-06 09:45:41 -08:00
Марко М. Костић (Marko M. Kostić)
7f4b82af18 Added CentOS 7 specific instructions to the manual install guide. 2015-11-06 09:45:41 -08:00
Allie Jones
85809e6140 Add webpack build process. 2015-11-06 09:13:25 -08:00
Allie Jones
e20a1bc73c Remove the committed handlebars package and install it via npm. 2015-11-06 09:09:41 -08:00
Allie Jones
4de0325a9d Install node dependencies using npm.
The node packages 'jQuery' and 'jquery' are different--'jQuery' is the
legacy support package that is needed for Zulip so the require statements
in the tests were updated.

Travis uses node 4.0 by default and we are using 0.10, so the command to
install the correct version had to be added to the .travis.yml file.
2015-11-06 09:08:59 -08:00
Allie Jones
46e267f4dc Add node-legacy package.
Some dependencies aren't configured to find the node binary correctly on
Debian (since it is called nodejs instead of node). The node-legacy package
fixes this.
2015-11-06 09:08:50 -08:00
Tim Abbott
ae04744606 admin: Refactor to remove unnecessary selections of active_user_row. 2015-11-04 08:15:55 -08:00
Tim Abbott
958ada9f44 admin: Fix deactivating bot users.
The previous code was using the same codepath as for real users, which
was unfortunate in two ways:
* It hit the wrong endpoint on the server and thus failed
* It popped up the "remove a user prompt" which described a bunch of
  things not relevant to bots.
2015-11-04 08:03:28 -08:00
Tim Abbott
5161891fbd admin: Fix reactivating bot users.
Because the `owner` field had the class email, we were sending the
concatination of the user and owner email addresses as the email
address in the reactivate requests.

Fixes #243.
2015-11-04 08:03:17 -08:00
Tim Abbott
f6f8f1fe36 Use new-style classes consistently for Python 3 support.
Also add the fixer for this to our list of fixers we check.
2015-11-04 08:01:52 -08:00
Tim Abbott
f52ffa7923 travis: Add Python 3 compatibility test.
This tests whether a new patch introduces any regressions related to
any of the Python 3 compatibility fixers we've run in the past, so
that we can make continuous forward progress on our path towards
Python 3 compatibility.

This produces error output that looks like this:
"""
Testing for additions of Python 2 patterns we've removed as part of moving towards Python 3 compatibility.

Running Python 3 compatibility test lib2to3.fixes.fix_apply
Running Python 3 compatibility test lib2to3.fixes.fix_except
diff --git a/zerver/views/__init__.py b/zerver/views/__init__.py
index b5c0102..2defd46 100644
--- a/zerver/views/__init__.py
+++ b/zerver/views/__init__.py
@@ -296,7 +296,7 @@ def accounts_register(request):
                 do_activate_user(user_profile)
                 do_change_password(user_profile, password)
                 do_change_full_name(user_profile, full_name)
-            except UserProfile.DoesNotExist, e:
+            except UserProfile.DoesNotExist as e:
                 user_profile = do_create_user(email, password, realm, full_name, short_name,
                                               prereg_user=prereg_user,
                                               newsletter_data={"IP": request.META['REMOTE_ADDR']})

Python 3 compatibility error(s) detected!  See diff above for what you need to change.
"""
2015-11-04 08:00:25 -08:00
Shumbashi
123791bfdd Fix 'manage.py makemessages' errors.
Running 'manage.py makemessages' produced two errors previously.

Closes #265.
2015-11-04 07:39:48 -08:00
Ahmed Shibani
4f29cfee9e Mark strings for translation in templates/zerver
In order to enable internationalization support in Zulip, and to use
Django internationalization tools, all strings in Zulip frontend needs
to be marked for translation.
2015-11-03 23:06:31 -08:00
Ahmed Shibani
47d8d784a2 Add 'blocktrans' to tools/check-templates.
Running check-templates test fails when there are 'blocktrans' tags in
django templates. The fix is to add 'blocktrans' to
is_django_block_tag function in check-templates.
2015-11-03 08:06:48 -08:00
Tim Abbott
6eb670097c Expand testing done via Travis CI to cover production pipeline.
With this change, we are now testing the production static asset
pipeline and installation process in a new testing job (and also run
the frontend/backend tests separately).

This means that changes that break the Zulip static asset pipeline or
production installation process are more likely to fail tests.  The
testing is imperfect in that it does not have proper isolation -- we
build a complete Zulip development environment and then install a
Zulip production environment on top of it, so e.g. any apt
dependencies installed for Zulip development will still be available
for the Zulip production environment.  But, it's better than nothing!

A good v2 of this would be to have the production setup process just
install the minimum stuff needed to run `build-release-tarball` and
then uninstall it / clean it up so that we can do a more clear
production installation, but that's more work.
2015-11-01 18:11:39 -08:00
Tim Abbott
421560af21 postgres-init-db: Stop all services before recreating database. 2015-11-01 18:11:39 -08:00
Tim Abbott
3c31f9a2e3 Drop database users prior to DROP/CREATE database.
This fixes an annoying issue where one tries to rebuild the database,
and it fails due to there being existing connections.

The one thing that is potentially scary about this implementation is
that it means it's now a lot easier to accidentally drop your
production database by running the wrong script; might be worth adding
a "--force" flag controlling this behavior or something.

Thanks to Nemanja Stanarevic and Neeraj Wahi for prototypes of this
implementation!  They did most of the work and testing for this.
2015-11-01 18:11:39 -08:00
Tim Abbott
b7cd000af6 install: Check nginx configuration is valid.
It's better to fail here and have the user correct the issue than fail
later.
2015-11-01 18:06:59 -08:00
Tim Abbott
33295180a9 Apply Python 3 futurize transform libmodernize.fixes.fix_unicode_type. 2015-11-01 09:35:06 -08:00
Tim Abbott
607eedfc25 Apply Python 3 futurize transform libmodernize.fixes.fix_zip. 2015-11-01 09:35:06 -08:00
Tim Abbott
f7878a61e1 Apply Python 3 futurize transform libmodernize.fixes.fix_xrange_six. 2015-11-01 09:35:06 -08:00
Tim Abbott
5ffb4deb8d Apply Python 3 futurize transform libmodernize.fixes.fix_raise_six. 2015-11-01 09:35:05 -08:00
Tim Abbott
cd6f8e9191 Apply Python 3 futurize transform libmodernize.fixes.fix_map. 2015-11-01 09:35:05 -08:00
Tim Abbott
ffc900fe6e Apply Python 3 futurize transform libmodernize.fixes.fix_int_long_tuple. 2015-11-01 09:26:17 -08:00
Tim Abbott
3b185ad4de Apply Python 3 futurize transform libmodernize.fixes.fix_input_six. 2015-11-01 09:26:17 -08:00
Tim Abbott
2ea0663a4a Apply Python 3 futurize transform libmodernize.fixes.fix_imports_six. 2015-11-01 09:26:16 -08:00
Tim Abbott
b3ac668779 Apply Python 3 futurize transform libmodernize.fixes.fix_filter. 2015-11-01 09:26:16 -08:00
Tim Abbott
651b011514 Apply Python 3 futurize transform libmodernize.fixes.fix_basestring. 2015-11-01 09:26:16 -08:00
Tim Abbott
7e63842003 Apply Python 3 futurize transform libfuturize.fixes.fix_raise. 2015-11-01 09:26:16 -08:00
Tim Abbott
f3783fb4a1 Apply Python 3 futurize transform libfuturize.fixes.fix_print_with_import. 2015-11-01 09:26:16 -08:00
Tim Abbott
f97649b35c Apply Python 3 futurize transform libfuturize.fixes.fix_next_call. 2015-11-01 09:26:16 -08:00
Tim Abbott
9c66229456 Apply Python 3 futurize transform libfuturize.fixes.fix_absolute_import. 2015-11-01 09:26:16 -08:00
Tim Abbott
43abd83d1c Apply Python 3 futurize transform lib2to3.fixes.fix_ws_comma. 2015-11-01 09:26:14 -08:00
Tim Abbott
2b61c0203d Apply Python 3 futurize transform lib2to3.fixes.fix_repr. 2015-11-01 09:25:49 -08:00
Tim Abbott
daddf7c519 Apply Python 3 futurize transform lib2to3.fixes.fix_numliterals. 2015-11-01 09:25:49 -08:00
Tim Abbott
2398a370e2 Apply Python 3 futurize transform lib2to3.fixes.fix_ne. 2015-11-01 09:25:49 -08:00
Tim Abbott
06f6ee6566 Apply Python 3 futurize transform lib2to3.fixes.fix_idioms. 2015-11-01 09:25:47 -08:00
Tim Abbott
e9243d0f0b Apply Python 3 futurize transform lib2to3.fixes.fix_has_key. 2015-11-01 08:10:01 -08:00
Tim Abbott
5ce6a3c8f9 Apply Python 3 futurize transform lib2to3.fixes.fix_funcattrs. 2015-11-01 08:09:54 -08:00
Tim Abbott
8c34c40924 Apply Python 3 futurize transform lib2to3.fixes.fix_except. 2015-11-01 08:08:33 -08:00
Shane Kearns
6e3426fe10 python api: allow control over the server certificate verification
The --insecure option ("insecure=true" in .zuliprc) disables
verification entirely, similar to other tools like curl.

The --cert_bundle ("cert_bundle=<file>" in .zuliprc) allows
a file to be specified containing the CA certificates to verify
against.
When using self-signed certificates, the server's public key
can be used as the only cerificate in the file.

This change incidentally fixes an issue where the "site" parameter
in .zuliprc was ignored when specifying --user and --api-key on
the command line.

Fixes: #104
2015-10-31 21:20:34 -07:00
Kara McNair
97a2e70d2b Add passing tests for emails replying to missed personal messages
Covers both direct PMs and huddle message recipients.
2015-10-31 17:28:21 -07:00
Kara McNair
a8e5755c7b Add tests for processing emailed-in stream messages (success & fail)
Prior to adding reply-to-missed-message-email functionality, adding
automated tests for simpler case - incoming stream messages. Added
to new file test_email_mirror.py.
Also removed the "if not body" code from process_stream_message that
will never run because of an upstream ZulipEmailForwardError exception.
2015-10-31 17:26:23 -07:00
Tim Abbott
10657c1d53 Move node tests to node_tests/. 2015-10-28 10:11:47 -07:00
Tim Abbott
81f32f4aa1 casper: Rename frontend_tests/run to clarify it uses casper. 2015-10-28 10:11:47 -07:00
Tim Abbott
5aa89fd6af casper: Move common.js and test-credentials.js to casper-lib/. 2015-10-28 10:11:47 -07:00
Tim Abbott
01f0d362d9 Move test_credentials.js into casper_tests/. 2015-10-28 10:11:47 -07:00
Tim Abbott
2294063361 Move casper server.log into casper_tests/. 2015-10-28 10:11:47 -07:00
Tim Abbott
988a9acead Move casper tests to a clearer directory name. 2015-10-28 10:11:47 -07:00
Tim Abbott
f1074aa491 Move frontend tests out of zerver/tests/.
This fixes an unfortunate bug where the backend tests in
zerver/tests.py were not being run automatically, and also makes these
a bit easier to find.
2015-10-28 10:11:47 -07:00
Tim Abbott
a36ac151ef Fix newly invited users receiving private stream history.
Also add a test to avoid this regressing in the future.

Fixes #230.
2015-10-26 23:36:37 -07:00
Tim Abbott
c1686235cd Fix construction of names in LDAP integration.
Previously these users' names were being set to 1-element lists
containing the name, not the names themselves.  This bug caused
existing users to have their people module state (e.g. @-mentions,
etc.) to break whenever a new user joined.

Fixes #222.
2015-10-26 22:49:10 -07:00
Kara McNair
8e429759e2 Replace 'flaky' and 'freaking out' with less personified words.
The tests to recognize a misbehaving/unpredictable worker task use
the words 'flaky' and 'freaking out' in personifying the system
behavior. This terminology isn't inclusive of people with
mental health issues or mood disorders, so this change updates
the wording to have less personification and more objective system
description. (http://www.ncbi.nlm.nih.gov/pmc/articles/PMC1925070/)
2015-10-26 20:14:48 -07:00
Gautam Kotian
fb5192e85b Fix typo in README.md. 2015-10-26 20:04:55 -07:00
Elizabeth Sander
2ba01f4900 Defer permission for notifications until after tutorial.
In the process, remove old mozilla notifications hack since the
notifications_api shim should handle that case correctly.

Fixes #17.
2015-10-26 09:44:15 -07:00
Bernhard Morgenstern
dd2ccff22b Fix indentation for Trac ticket description changes.
Before this fix, the "to" was included in the markdown blocks.
2015-10-22 15:02:35 -07:00
Steven Oud
d5435fad1d Consistently use /usr/bin/env python2.7 in shebangs and commands. 2015-10-21 22:58:21 +00:00
Tim Abbott
136c55e43d Document new zulip-help@ mailing list for installation help. 2015-10-19 21:45:44 -07:00
Tim Abbott
b76e78c4dd Expand documentation on contributing to Zulip. 2015-10-19 21:01:18 -07:00
Tim Abbott
3bb0ce2383 Changelog: Simplify formatting and document 1.3.7 release. 2015-10-19 20:32:47 -07:00
Tim Abbott
54c964a332 Rewrite the email gateway integration instructions. 2015-10-19 10:10:20 -07:00
Tim Abbott
a6ddd28c9e Clarify the steps in the outgoing SMTP setup process. 2015-10-19 10:09:45 -07:00
Tim Abbott
494797ea0a Fix has_valid_realm logic following get_realm refactor. 2015-10-19 09:59:06 -07:00
Tim Abbott
3e1f4e611c Clarify on zulip.com signup form that we're not taking new teams. 2015-10-19 09:37:24 -07:00
Tim Abbott
758baca01a run-dev.py: Report a nice error if you run it as root.
Fixes #172.
2015-10-15 12:45:38 -04:00
Tim Abbott
3167b64d1c Extend changelog with other unreleased improvemenets since 1.3.6. 2015-10-15 12:31:28 -04:00
Nicholas Bergson-Shilcock
89a2765553 Turn off desktop notifications by default for new users.
New users will no longer get desktop and audible notifications for all streams
by default.

This also updates the `day1` follow-up email to let users know they can
customize how and when Zulip notifies them of new messages.

Lastly, this adds a `changelog.md` file, following the conventions from
keepachangelog.com, to track changes for new releases.
2015-10-15 12:25:32 -04:00
Tim Abbott
e75ba630fb initialize-database: Make management command errors fatal again.
We accidentally made this non-fatal when we added the nice error
output telling users to run postgres-init-db.
2015-10-15 12:21:46 -04:00
Tim Abbott
bf694fa832 Flush memcached whenever we drop the databases.
This fixes some issues that we've had where commands will fail is
confusing ways after the database is rebuilt because data from before
the database was dropped is still in the memcached cache.
2015-10-15 12:18:41 -04:00
Tim Abbott
32aea4c9dd Fix get_unique_open_realm always returning None in production.
Fixes #186.
2015-10-15 10:21:04 -04:00
Tim Abbott
5d22f5ee0a Improve LDAP_APPEND_DOMAIN default.
The documentation suggests the default is None; this change makes that
true.  Also make the actual code robust to this being set to "" instead.
2015-10-15 09:16:59 -04:00
Tim Abbott
71a06d58de Convert uses of Realm.objects.get() to get_realm().
get_realm is better in two key ways:
* It uses memcached to fetch the data from the cache and thus is faster.
* It does a case-insensitive query and thus is more safe.
2015-10-15 09:16:58 -04:00
Tim Abbott
51ed5028dc Remove unnecessary get_realm_name function. 2015-10-15 09:16:58 -04:00
Tim Abbott
419d31a007 Expand documentation for the LDAP auth integration.
Fixes #134, #173.
2015-10-15 09:16:58 -04:00
Tim Abbott
784ba7e066 Fix support for LDAP Authentication mechanism.
This addresses a few issues:
* The LDAP authentication integration now creates an account a new
  Zulip account if the user authenticated correctly but didn't have a
  Zulip account.
* The previous code didn't correctly disable the LDAP group
  permissions functionality.  We're not using groups support from the
  Django LDAP extension and not doing so can cause errors trying to
  fetch data from LDAP.

Huge thanks to @toaomatis for the initial implementation of this.

Fixes #72.
2015-10-15 09:16:58 -04:00
Tim Abbott
90e61d3b61 Call process_new_human_user consistently when creating new users.
Previously we only did this when new human users were created via the
login process, which meant the management command to create a user did
not add the user to default streams (for example) and any future code
that might want to register a new Zulip user (such as the LDAP
integration) would need to import views/__init__.py in order to
properly set this up.
2015-10-15 09:16:58 -04:00
Tim Abbott
355e1bbd94 Move process_new_human_user and helpers from views to actions.py. 2015-10-15 09:16:58 -04:00
Tim Abbott
792075ddeb sync_api_key: Don't throw a messy exception when user doesn't exist. 2015-10-15 09:16:58 -04:00
Tim Abbott
3e735d36d1 Rename tools/postgres-init-db to tools/postgres-init-dev-db.
The previous name was confusing because we also have
scripts/setup/postgres-init-db.
2015-10-15 09:14:21 -04:00
Allie Jones
99a2ba38b1 Expand new feature tutorial. 2015-10-15 09:12:22 -04:00
Tim Abbott
e8e38e911b Fix casperjs tests in Travis CI.
For reasons I don't understand, it appears that in Travis CI we're now
seeing errors using Casper that seem to correspond to a compatibility
issue introduced in PhantomJS 2, even though we're still using 1.9.8.

The solution for that compatability issue of patching casper's
bootstrap.js to get arguments from system.args at a slightly different
time than before seems to work in our setting as well, and that's what
this implements.

Probably the right long-term solution involves upgrading both
phantomjs and Casper to the latest versions.
2015-10-14 21:49:09 -04:00
Tim Abbott
eac6ea75dd emoji_dump: Exit with nonzero status when there are failures.
Previously, emoji_dump would happily exit successfully even if it
wasn't able to generate all the emoji.
2015-10-14 21:48:13 -04:00
Tim Abbott
5ee50cdced Install libfreetype6-dev in the development environment.
This fixes a problem where the emoji_dump tool was not generating the
black-and-white emoji.  The issue is that Pillow compiled without
libfreetype cannot extract those emoji (and gives an error of the form
"The _imagingft C module is not installed"), and if libfreetype-dev
isn't installed, pip will happily build and install Pillow without
libfreetype.
2015-10-14 18:58:36 -04:00
Tim Abbott
1dc09f3abd Document need to restart run-dev.py when developing queue workers. 2015-10-14 16:11:04 -04:00
Tim Abbott
4309f92062 Pass worker errors through to the run-dev.py console. 2015-10-14 16:08:32 -04:00
Kara McNair
d72f75a7e1 email-mirror: Support missed message email token string format.
The do_send_missedmessage_events_reply_in_zulip function in the email
mirror didn't support EMAIL_GATEWAY_PATTERN that wasn't of the form
%s@example.com (which resulted in replies to missed message emails failing
to be parsed).
2015-10-14 16:02:15 -04:00
Tim Abbott
0d85ab2062 README: Clean up Mac installation instructions for Virtualbox/Vagrant.
* Removes the hardcoding of an old version of Virtualbox (and doesn't
  specify the version to avoid getting stale again over time).
* Flips around the langauge to assume you don't have Vagrant already.
* Makes clear that the first-time installation is a lot slower than
  future runs will be.

Fixes #5.
2015-10-14 12:05:23 -04:00
Tim Abbott
c6761e8604 provision.py: Check whether git repository is present.
Fixes #148.
2015-10-14 10:18:59 -04:00
Tim Abbott
6569018de7 Disable apt caching in Travis CI configuration.
Apparently it isn't supposed to work reliably with the container-based
infrastructure that we're using and empirically it's causing build
failures.

Thanks to @mijime for tracking this down.
2015-10-14 10:04:27 -04:00
Andrew Drozdov
f6311478e6 Add docs on how to update default streams. 2015-10-13 11:09:37 -04:00
David Farrell
59dfec8f8b Add Fedora-specific instructions to the manual install guide. 2015-10-07 15:23:59 -04:00
Raphael
0608e32eeb Cause install to return 1 on failure.
This fixes issue #123. Namely, the script in scripts/setup/install was
returning 0. Adding `set -e` and `set -o pipeline` causes the install
script to exit and return 1 if any part fails, including piping output
(`set -o pipeline` does this).
2015-10-07 08:46:16 -04:00
Darius Bacon
741e9d00d8 Install zulip_english.stop in 'By hand' install instructions.
This step was previously only present in provision.py.
2015-10-06 23:00:18 -04:00
Darren Worrall
77fad7a16e Add an api endpoint to fetch GOOGLE_CLIENT_ID
Further to #102, this provides an endpoint suitable for mobile apps to
consume the GOOGLE_CLIENT_ID if configured.
2015-10-06 23:28:08 +00:00
Raphael
ea65715ef8 manage.py: Give a nice error message if run as root on posix systems.
If the os is posix, this will check to see if the user is root and
alert them to run as zulip user if so.

Fixes #114.
2015-10-05 21:41:35 -04:00
David Farrell
e4cea98ccd Correct the filepath for rebuild test database script. 2015-10-05 21:28:54 -04:00
Luna Lunapiena
0ec99a0838 README: Add explicit instruction to clone Zulip repository. 2015-10-05 21:27:08 -04:00
David Farrell
411531ecaf Update script paths in by-hand instructions to execute as written. 2015-10-05 20:36:07 -04:00
Nicholas Bergson-Shilcock
759ab33981 Add note about installing Vagrant on Mac to README. 2015-10-05 20:34:27 -04:00
Justin Valentini
d490779307 Add a relative link to production README. 2015-10-04 16:28:36 +00:00
Luke Faraone
e014b68b84 Include license text in THIRDPARTY 2015-10-03 15:44:13 +00:00
Darren Worrall
14389145cd Make twitter settings validation test more explicit 2015-10-02 12:01:25 +01:00
Tim Abbott
a65656dd9d Fix backwards-compatibility for old python-requests .json property.
In b59b5cac35, we upgraded our Google
Oauth code to support new python-requests, but because Ubuntu precise
still has old python-requests, this broke the codepath for older
systems.
2015-10-01 18:54:17 -07:00
Tim Abbott
8e0479e7a0 Clarify Zulip upgrade process instructions. 2015-10-01 12:56:18 -07:00
Tim Abbott
ea7e5527be README.prod.md: Expand documentation on filling in settings.py. 2015-10-01 12:42:36 -07:00
Tim Abbott
feca065dd8 README.prod.md: Improve instructions for downloading server tarball. 2015-10-01 12:42:35 -07:00
Liam Marshall
a822118dcb Fix a bunch of formatting issues in README.prod.md.
Removes:
* Several unused <hr>s

Fixes:
* Odd linebreaks
* Inconsistent headers
* URLs which should be links
* Headers which should be headers

Code-formats:
* envvars
* FQDNs
* commands and command options
* config options
* code
2015-10-01 12:42:16 -07:00
Allie Jones
cd1fa6a42e Fix notifications in Firefox by calling the constructor with 'new'. 2015-10-01 09:31:05 -07:00
Tim Abbott
ad75959b92 README.prod: Add documentation for how to create an SSL certificate. 2015-10-01 09:31:05 -07:00
mijime
2db2fcea18 Fix a puppet config to use SSO.
puppet::enterprise was renamed to puppet::voyager.
2015-10-01 09:31:05 -07:00
Darren Worrall
8b002040e0 Correct twitter library in requirements.
This also requires updating the required version of oauthlib; previously an
appropriate version was being installed only because it was a dependency of
the wrong twitter library.

This only affects development environments and/or hand-built
installations relying on the contents of requirements.txt.

To fix existing environments, the incorrect api needs to be explicitly
removed with `pip uninstall twitter`.

Fixes #86.
2015-09-30 13:49:33 -07:00
Ged Lawrenson
21b7048e54 install: Verify that the script has sufficient privileges. 2015-09-30 10:55:49 -07:00
Darren Worrall
bec3c0943a Fix validation that twitter creds are present.
They are looked up as secrets which initialize to `None`, but the code
was checking for empty strings.

This, along with #80, fixes #81.
2015-09-30 09:27:37 -07:00
Jason Michalski
7352f31c4b Add documentation for the pagerduty integrations
Add pagerduty to the list of supported integrations and walks users
through the setup process.

Fixes #36
2015-09-30 09:24:00 -07:00
Jason Michalski
dafe69761e Use stock emoji in the pagerduty integration
The pagerduty integration was using realm emoji. Use stock replacements
in the open source release.
2015-09-30 09:23:59 -07:00
Guillaume Simon
956fd7c420 puppet: Ensure rabbitmq-server and epmd services are running.
[tabbott@mit.edu: Added a few comments]
2015-09-30 09:21:45 -07:00
Tim Abbott
f819c1e901 Update the Zulip development documentation.
Fixes a few major issues:
* Documents RAM requirements for running Zulip development
* Fixes missing steps in the "by hand" installation process
* Improves the emphasis in the section no how to run tests on the common case.
* Documents that you can use LXC on newer Ubuntu as well.
2015-09-30 09:04:16 -07:00
Tim Abbott
3b00029c52 Show the username/password form if ZulipLDAPAuthBackend is enabled. 2015-09-30 09:04:16 -07:00
Tim Abbott
1482a386c2 Fix documentation for how to enable ZulipLDAPAuthBackend. 2015-09-30 09:04:16 -07:00
Tim Abbott
92aebe595b Dramatically extend post-install documentation for production Zulip. 2015-09-30 09:04:14 -07:00
Tim Abbott
5ad84fd997 Improve documentation for the Zulip email integration.
* Document fix for the 'less insecure' email problem.
* Mention that general Django email documentation applies.
2015-09-29 18:58:27 -07:00
Tim Abbott
40ec59b93e install: Add nice error message for RabbitMQ not having started. 2015-09-29 18:41:31 -07:00
Tim Abbott
5bf66e04fc initialize-database: Print nice instructions for how to redo if fails.
Most of our installation process is idempotent, but this step in
particular is not, so it's important to provide a clear error message
about how to proceed.
2015-09-29 18:27:27 -07:00
Tim Abbott
3efdb7ebf3 Document how to setup the Zulip S3 integration. 2015-09-29 18:11:58 -07:00
Tim Abbott
80fa5006f8 Document the purpose of local_settings.py properly. 2015-09-29 18:05:04 -07:00
Tim Abbott
bda9d78092 Use settings.ZULIP_ADMINISTRATOR as contact list for deactivated users. 2015-09-29 17:59:47 -07:00
Waseem Daher
6bb9b129f7 Update Zulip support email to zulip-devel@googlegroups.com.
Ideally some of these templates should really point to the
local installation's support email address, but this is a
good start.

Exceptions:
* Where to report security incidents
* MIT Zephyr-related pages
* zulip.com terms and conditions
2015-09-29 17:59:47 -07:00
Thomas Butter
d93d4c7216 Fix settings documentation of twitter keys.
Twitter keys are stored in zulip-secrets.conf.
2015-09-29 17:45:05 -07:00
Tim Abbott
852ac66f8e Extend the Google oauth documentation in local_server_template.py. 2015-09-28 10:05:58 -07:00
Amanpreet Singh
e20bc9f9b3 Fix "by hand" installation instructions.
- Add missing `python-dev` in apt-get install command
2015-09-28 09:24:55 -07:00
Tim Abbott
1f2f497cab Unrevert run Zulip tests automatically using Travis CI.
This contains a fix written by nemeth from PR #63 for doing argument
parsing properly.
2015-09-28 09:18:51 -07:00
Luke Faraone
578f769f60 Revert "Run Zulip tests automatically using Travis CI."
Improper list access from `sys.argv` would result in an exception if no
arguments are passed.

This reverts commit d2f5937d89.
2015-09-28 14:33:13 +00:00
Ian Whitlock
54fd321941 Add Vagrant-caused permissions problem to Possible Issues. 2015-09-27 17:48:07 -07:00
Tim Abbott
b6c1f1d162 Fix incorrect name for email_password secret in settings template.
Fixes #49.
2015-09-27 17:06:03 -07:00
Tim Abbott
d2f5937d89 Run Zulip tests automatically using Travis CI.
This is a bit hackish in that ideally we'd use proper options parsing
in provision.py, but it works and I even ran the tests 100x for tests
for flakes and didn't get any, so it's definitely an improvement!

With this we'll be both testing the runtime and effectively the Dev VM
setup process, which is awesome; the additional thing I'd want to add
tests for is the production setup process...
2015-09-27 16:29:20 -07:00
Caleb Anderson
ed742fa847 small typo fix 2015-09-27 01:10:01 -06:00
Tim Abbott
a625ca49ec puppet: Move /var/lib/nagios_state creation to zulip::base.pp.
Previously, in Zulip voyager, the cron jobs would spew error emails
every time they ran, due to this directory not existing.

This also tightens the permissions for the folder and avoids needing
to create a nagios user for Zulip voyager; it should be writeable by
both root and the zulip user and world-readable (and thus readable by
the Nagios user on zulip.com systems).
2015-09-26 21:44:23 -07:00
Tim Abbott
96bd1c38dc install: Make sure python is installed before using it.
This is relevant for completely bare Ubuntu systems which might only
have python3 installed.

Fixes #40.
2015-09-26 21:34:36 -07:00
Tim Abbott
9748780192 Remove unnecessary puppet.conf configuration.
Fixes #23.
2015-09-26 21:34:19 -07:00
Tim Abbott
bc3f096918 Update redis config to be supported on Trusty.
Previously our redis config was built for precise.

Synced from redis-server 2:2.8.4-2 plus our one change, which is
disabling saving to disk, so just put that at the bottom for maximum
obviousness.

I wish there was a better way to represent the fact that this is all
we're doing, since this will make life more difficult for running on
precise as well.

Fixes #28.
2015-09-26 21:33:55 -07:00
Tim Abbott
af4aac6836 settings: Document SMTP firewall issues in email configuration. 2015-09-26 21:32:47 -07:00
Tim Abbott
e5f7000a23 Add description of Zulip at top of README.md.
Based on PR #22 by GedLawrenson.
2015-09-26 18:07:06 -07:00
Tim Abbott
00bf7b25b5 install: Remote the python-django-guardian hack.
This is no longer required since it's in the PPA now.
2015-09-26 18:01:18 -07:00
Tim Abbott
2c6bfe136a Remove confusing EMAIL_HOST_PASSWORD setting in SMTP configuration.
This was one of the various configuration options made confusing by
the secrets-to-configuration migration.

Fixes #27.
2015-09-26 17:48:21 -07:00
Jon Johnson
db51a1c547 Fix typo in jabber mirror error
assistence -> assistance
2015-09-26 22:03:00 +00:00
Tim Abbott
3f76745235 Reorder README.md to highlight contributing section earlier. 2015-09-26 14:02:28 -07:00
Yuvi Panda
b59b5cac35 Fix TypeError in Google OAuth authenticator.
requests 1.0 changed response.json attribute to response.json()
instancemethod. The code wasn't updated to match that change,
causing a TypeError when attempting to use the Google OAuth
Authenticator backend.

This is fixed simply by using response.json() instead of response.json.
2015-09-26 13:51:27 -07:00
Tim Abbott
5dd330e769 Document how to setup Google auth for Zulip voyager. 2015-09-26 13:50:46 -07:00
Tim Abbott
140e598a89 Update configuration examples to use current Google auth backend. 2015-09-26 13:50:28 -07:00
Alice Pote
8159c03205 Add backticks around 'apt-get install'. 2015-09-26 12:13:21 -07:00
Anders Kaseorg
0d12dfd06f Improve shell quoting hygiene
Most of these problems were found by ShellCheck
(http://www.shellcheck.net).

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2015-09-25 23:25:08 -04:00
Josh Nichols
6888826d5b Link to settings page with absolute path, rather than explicitly zulip.com 2015-09-25 22:59:35 -04:00
1029 changed files with 20584 additions and 43837 deletions

2
.gitattributes vendored
View File

@@ -14,7 +14,7 @@
/zproject/local_settings.py export-ignore
/zproject/test_settings.py export-ignore
/zerver/fixtures export-ignore
/zerver/tests.py export-ignore
/zerver/tests export-ignore
/frontend_tests export-ignore
/node_modules export-ignore
/humbug export-ignore

24
.gitignore vendored
View File

@@ -2,8 +2,18 @@
*~
/all_messages_log.*
/event_log/*
/server.log
/digest.log*
/errors.log*
/manage.log*
/server.log*
/workers.log*
/email-deliverer.log
/email-mirror.log
/sync_ldap_user_data.log
/update-prod-static.log
frontend_tests/casper_tests/server.log
frontend_tests/casper_lib/test_credentials.js
memcached_prefix
/prod-static
/errors/*
*.sw[po]
@@ -13,24 +23,24 @@ stats/
zerver/fixtures/available-migrations
zerver/fixtures/migration-status
zerver/fixtures/test_data1.json
zerver/tests/frontend/test_credentials.js
.kdev4
zulip.kdev4
memcached_prefix
remote_cache_prefix
coverage/
/queue_error
/workers.log
.test-js-with-node.html
digest.log
errors.log
manage.log
.kateproject.d/
.kateproject
*.kate-swp
event_queues.json
.vagrant
/zproject/dev-secrets.conf
static/js/bundle.js
static/third/gemoji/
static/third/zxcvbn/
tools/emoji_dump/bitmaps/
tools/emoji_dump/*.ttx
tools/phantomjs
node_modules
uploads/
test_uploads/

28
.travis.yml Normal file
View File

@@ -0,0 +1,28 @@
before_install:
- nvm install 0.10
install:
- tools/travis/setup-$TEST_SUITE
cache:
- apt: false
- directories:
- /srv/phantomjs
env:
- TEST_SUITE=frontend
- TEST_SUITE=backend
- TEST_SUITE=production
- TEST_SUITE=py3k
language: python
python:
- "2.7"
matrix:
include:
- python: "3.4"
env: TEST_SUITE=mypy
# command to run tests
script:
- ./tools/travis/$TEST_SUITE
sudo: required
services:
- docker
addons:
postgresql: "9.3"

12
Dockerfile Normal file
View File

@@ -0,0 +1,12 @@
FROM ubuntu:trusty
EXPOSE 9991
RUN apt-get update && apt-get install -y \
python-pbs \
wget
RUN useradd -d /home/zulip -m zulip && echo 'zulip ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
USER zulip
WORKDIR /srv/zulip

554
README.dev.md Normal file
View File

@@ -0,0 +1,554 @@
Installing the Zulip Development environment
============================================
You will need a machine with at least 2GB of RAM available (see
https://github.com/zulip/zulip/issues/32 for a plan for how to
dramatically reduce this requirement).
Start by cloning this repository: `git clone https://github.com/zulip/zulip.git`
Using Vagrant
-------------
This is the recommended approach for all platforms, and will install
the Zulip development environment inside a VM or container and works
on any platform that supports Vagrant.
The best performing way to run the Zulip development environment is
using an LXC container on a Linux host, but we support other platforms
such as Mac via Virtualbox (but everything will be 2-3x slower).
* If your host is Ubuntu 15.04 or newer, you can install and configure
the LXC Vagrant provider directly using apt:
```
sudo apt-get install vagrant lxc lxc-templates cgroup-lite redir
vagrant plugin install vagrant-lxc
```
You may want to [configure sudo to be passwordless when using Vagrant LXC][avoiding-sudo].
* If your host is Ubuntu 14.04, you will need to [download a newer
version of Vagrant][vagrant-dl], and then do the following:
```
sudo apt-get install lxc lxc-templates cgroup-lite redir
sudo dpkg -i vagrant*.deb # in directory where you downloaded vagrant
vagrant plugin install vagrant-lxc
```
You may want to [configure sudo to be passwordless when using Vagrant LXC][avoiding-sudo].
* For other Linux hosts with a kernel above 3.12, [follow the Vagrant
LXC installation instructions][vagrant-lxc] to get Vagrant with LXC
for your platform.
* If your host is OS X or older Linux, [download VirtualBox][vbox-dl],
[download Vagrant][vagrant-dl], and install them both.
* If you're on OS X and have VMWare, it should be possible to patch
Vagrantfile to use the VMWare vagrant provider which should perform
much better than Virtualbox. Patches to do this by default if
VMWare is available are welcome!
* On Windows: You can use Vagrant and Virtualbox/VMWare on Windows
with Cygwin, similar to the Mac setup. Be sure to create your git
clone using `git clone https://github.com/zulip/zulip.git -c
core.autocrlf=false` to avoid Windows line endings being added to
files (this causes weird errors).
[vagrant-dl]: https://www.vagrantup.com/downloads.html
[vagrant-lxc]: https://github.com/fgrehm/vagrant-lxc
[vbox-dl]: https://www.virtualbox.org/wiki/Downloads
[avoiding-sudo]: https://github.com/fgrehm/vagrant-lxc#avoiding-sudo-passwords
Once that's done, simply change to your zulip directory and run
`vagrant up` in your terminal to install the development server. This
will take a long time on the first run because Vagrant needs to
download the Ubuntu Trusty base image, but later you can run `vagrant
destroy` and then `vagrant up` again to rebuild the environment and it
will be much faster.
Once that finishes, you can run the development server as follows:
```
vagrant ssh -- -L9991:localhost:9991
# Now inside the container
cd /srv/zulip
source /srv/zulip-venv/bin/activate
./tools/run-dev.py --interface=''
```
To get shell access to the virtual machine running the server to run
lint, management commands, etc., use `vagrant ssh`.
(A small note on tools/run-dev.py: the `--interface=''` option will
make the development server listen on all network interfaces. While
this is correct for the Vagrant guest sitting behind a NAT, you
probably don't want to use that option when using run-dev.py in other
environments).
At this point you should [read about using the development
environment][using-dev].
[using-dev]: #using-the-development-environment
## Specifying a proxy
If you need to use a proxy server to access the Internet, you will
need to specify the proxy settings before running `Vagrant up`.
First, install the Vagrant plugin `vagrant-proxyconf`:
```
vagrant plugin install vagrant-proxyconf.
```
Then create `~/.zulip-vagrant-config` and add the following lines to
it (with the appropriate values in it for your proxy):
```
HTTP_PROXY http://proxy_host:port
HTTPS_PROXY http://proxy_host:port
NO_PROXY localhost,127.0.0.1,.example.com
```
Now run `vagrant up` in your terminal to install the development
server. If you ran `vagrant up` before and failed, you'll need to run
`vagrant destroy` first to clean up the failed installation.
Using provision.py without Vagrant
----------------------------------
If you'd like to install a Zulip development environment on a server
that's already running Ubuntu 14.04 Trusty, you can do that by just
running:
```
sudo apt-get update
python /srv/zulip/provision.py
cd /srv/zulip
source /srv/zulip-venv/bin/activate
./tools/run-dev.py
```
Note that there is no supported uninstallation process without Vagrant
(with Vagrant, you can just do `vagrant destroy` to clean up the
development environment).
By hand
-------
If you really want to install everything by hand, the below
instructions should work.
Install the following non-Python dependencies:
* libffi-dev — needed for some Python extensions
* postgresql 9.1 or later — our database (client, server, headers)
* nodejs 0.10 (and npm)
* memcached (and headers)
* rabbitmq-server
* libldap2-dev
* python-dev
* redis-server — rate limiting
* tsearch-extras — better text search
* libfreetype6-dev — needed before you pip install Pillow to properly generate emoji PNGs
### On Debian or Ubuntu systems:
```
sudo apt-get install closure-compiler libfreetype6-dev libffi-dev \
memcached rabbitmq-server libldap2-dev redis-server \
postgresql-server-dev-all libmemcached-dev python-dev \
hunspell-en-us nodejs nodejs-legacy npm git yui-compressor \
puppet gettext
# If on 12.04 or wheezy:
sudo apt-get install postgresql-9.1
wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.1-tsearch-extras_0.1.2_amd64.deb
sudo dpkg -i postgresql-9.1-tsearch-extras_0.1.2_amd64.deb
# If on 14.04:
sudo apt-get install postgresql-9.3
wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.3-tsearch-extras_0.1.2_amd64.deb
sudo dpkg -i postgresql-9.3-tsearch-extras_0.1.2_amd64.deb
# If on 15.04 or jessie:
sudo apt-get install postgresql-9.4
wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.4-tsearch-extras_0.1_amd64.deb
sudo dpkg -i postgresql-9.4-tsearch-extras_0.1_amd64.deb
```
Now continue with the "All systems" instructions below.
### On Fedora 22 (experimental):
These instructions are experimental and may have bugs; patches
welcome!
```
sudo dnf install libffi-devel memcached rabbitmq-server \
openldap-devel python-devel redis postgresql-server \
postgresql-devel postgresql libmemcached-devel freetype-devel \
nodejs npm yuicompressor closure-compiler gettext
```
Now continue with the Common to Fedora/CentOS instructions below.
### On CentOS 7 Core (experimental):
These instructions are experimental and may have bugs; patches
welcome!
```
# Add user zulip to the system (not necessary if you configured zulip
# as the administrator user during the install process of CentOS 7).
useradd zulip
# Create a password for zulip user
passwd zulip
# Allow zulip to sudo
visudo
# Add this line after line `root ALL=(ALL) ALL`
zulip ALL=(ALL) ALL
# Switch to zulip user
su zulip
# Enable EPEL 7 repo so we can install rabbitmq-server, redis and
# other dependencies
sudo yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
# Install dependencies
sudo yum install libffi-devel memcached rabbitmq-server openldap-devel
python-devel redis postgresql-server postgresql-devel postgresql \
libmemcached-devel wget python-pip openssl-devel freetype-devel \
libjpeg-turbo-devel zlib-devel nodejs yuicompressor \
closure-compiler gettext
# We need these packages to compile tsearch-extras
sudo yum groupinstall "Development Tools"
# clone Zulip's git repo and cd into it
cd && git clone https://github.com/zulip/zulip && cd zulip/
## NEEDS TESTING: The next few DB setup items may not be required at all.
# Initialize the postgres db
sudo postgresql-setup initdb
# Edit the postgres settings:
sudo vi /var/lib/pgsql/data/pg_hba.conf
# Change these lines:
host all all 127.0.0.1/32 ident
host all all ::1/128 ident
# to this:
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
```
Now continue with the Common to Fedora/CentOS instructions below.
### On OpenBSD 5.8 (experimental):
These instructions are experimental and may have bugs; patches
welcome!
```
doas pkg_add sudo bash gcc postgresql-server redis rabbitmq \
memcached node libmemcached py-Pillow py-cryptography py-cffi
# Get tsearch_extras and build it (using a modified version which
# aliases int4 on OpenBSD):
git clone https://github.com/blablacio/tsearch_extras
cd tsearch_extras
gmake && sudo gmake install
# Point environment to custom include locations and use newer GCC
# (needed for Node modules):
export CFLAGS="-I/usr/local/include -I/usr/local/include/sasl"
export CXX=eg++
# Create tsearch_data directory:
sudo mkdir /usr/local/share/postgresql/tsearch_data
# Hack around missing dictionary files -- need to fix this to get the
# proper dictionaries from what in debian is the hunspell-en-us
# package.
sudo touch /usr/local/share/postgresql/tsearch_data/english.stop
sudo touch /usr/local/share/postgresql/tsearch_data/en_us.dict
sudo touch /usr/local/share/postgresql/tsearch_data/en_us.affix
```
Now continue with the All Systems instructions below.
### Common to Fedora/CentOS instructions
```
# Build and install postgres tsearch-extras module
wget https://launchpad.net/~tabbott/+archive/ubuntu/zulip/+files/tsearch-extras_0.1.3.tar.gz
tar xvzf tsearch-extras_0.1.3.tar.gz
cd ts2
make
sudo make install
# Hack around missing dictionary files -- need to fix this to get the
# proper dictionaries from what in debian is the hunspell-en-us
# package.
sudo touch /usr/share/pgsql/tsearch_data/english.stop
sudo touch /usr/share/pgsql/tsearch_data/en_us.dict
sudo touch /usr/share/pgsql/tsearch_data/en_us.affix
# Edit the postgres settings:
sudo vi /var/lib/pgsql/data/pg_hba.conf
# Add this line before the first uncommented line to enable password
# auth:
host all all 127.0.0.1/32 md5
# Start the services
sudo systemctl start redis memcached rabbitmq-server postgresql
# Enable automatic service startup after the system startup
sudo systemctl enable redis rabbitmq-server memcached postgresql
```
Finally continue with the All Systems instructions below.
### All Systems:
```
pip install --no-deps -r requirements.txt
./tools/install-phantomjs
./tools/install-mypy
./tools/download-zxcvbn
./tools/emoji_dump/build_emoji
./scripts/setup/generate_secrets.py -d
if [ $(uname) = "OpenBSD" ]; then sudo cp ./puppet/zulip/files/postgresql/zulip_english.stop /var/postgresql/tsearch_data/; else sudo cp ./puppet/zulip/files/postgresql/zulip_english.stop /usr/share/postgresql/9.3/tsearch_data/; fi
./scripts/setup/configure-rabbitmq
./tools/postgres-init-dev-db
./tools/do-destroy-rebuild-database
./tools/postgres-init-test-db
./tools/do-destroy-rebuild-test-database
npm install
```
If `npm install` fails, the issue may be that you need a newer version
of `npm`. You can use `npm install -g npm` to update your version of
`npm` and try again.
To start the development server:
```
./tools/run-dev.py
```
… and visit [http://localhost:9991/](http://localhost:9991/).
#### Proxy setup for by-hand installation
If you are building the development environment on a network where a
proxy is required to access the Internet, you will need to set the
proxy in the environment as follows:
- On Ubuntu, set the proxy environment variables using:
```
export https_proxy=http://proxy_host:port
export http_proxy=http://proxy_host:port
```
- And set the npm proxy and https-proxy using:
```
npm config set proxy http://proxy_host:port
npm config set https-proxy http://proxy_host:port
```
Using Docker (experimental)
---------------------------
The docker instructions for development are experimental, so they may
have bugs. If you try them and run into any issues, please report
them!
You can also use Docker to run a Zulip development environment.
First, you need to install Docker in your development machine
following the [instructions][docker-install]. Some other interesting
links for somebody new in Docker are:
* [Get Started](https://docs.docker.com/linux/started/)
* [Understand the architecture](https://docs.docker.com/engine/introduction/understanding-docker/)
* [Docker run reference](https://docs.docker.com/engine/reference/run/)
* [Dockerfile reference](https://docs.docker.com/engine/reference/builder/)
[docker-install]: https://docs.docker.com/engine/installation/
Then you should create the Docker image based on Ubuntu Linux, first
go to the directory with the Zulip source code:
```
docker build -t user/zulipdev .
```
Now you're going to install Zulip dependencies in the image:
```
docker run -itv $(pwd):/srv/zulip -p 80:9991 user/zulipdev /bin/bash
$ /usr/bin/python /srv/zulip/provision.py --docker
docker ps -af ancestor=user/zulipdev
docker commit -m "Zulip installed" <container id> user/zulipdev:v2
```
Finally you can run the docker server with:
```
docker run -itv $(pwd):/srv/zulip -p 80:9991 user/zulipdev:v2 \
/srv/zulip/scripts/start-dockers
```
If you want to connect to the Docker instance to build a release
tarball you can use:
```
docker ps
docker exec -it <container id> /bin/bash
$ source /home/zulip/.bash_profile
$ <Your commands>
$ exit
```
To stop the server use:
```
docker ps
docker kill <container id>
```
If you want to run all the tests you need to start the servers first,
you can do it with:
```
docker run -itv $(pwd):/srv/zulip user/zulipdev:v2 /bin/bash
$ scripts/test-all-docker
```
You can modify the source code in your development machine and review
the results in your browser.
Using the Development Environment
=================================
Once the development environment is running, you can visit
<http://localhost:9991/> in your browser. By default, the development
server homepage just shows a list of the users that exist on the
server and you can login as any of them by just clicking on a user.
This setup saves time for the common case where you want to test
something other than the login process; to test the login process
you'll want to change `AUTHENTICATION_BACKENDS` in the not-PRODUCTION
case of `zproject/settings.py` from zproject.backends.DevAuthBackend
to use the auth method(s) you'd like to test.
While developing, it's helpful to watch the `run-dev.py` console
output, which will show any errors your Zulip development server
encounters.
When you make a change, here's a guide for what you need to do in
order to see your change take effect in Development:
* If you change Javascript or CSS, you'll just need to reload the
browser window to see changes take effect.
* If you change Python code used by the the main Django/Tornado server
processes, these services are run on top of Django's [manage.py
runserver][django-runserver] which will automatically restart the
Zulip Django and Tornado servers whenever you save changes to Python
code. You can watch this happen in the `run-dev.py` console to make
sure the backend has reloaded.
* The Python queue workers don't automatically restart when you save
changes (or when they stop running), so you will want to ctrl-C and
then restart `run-dev.py` manually if you are testing changes to the
queue workers or if a queue worker has crashed.
* If you change the database schema, you'll need to use the standard
Django migrations process to create and then run your migrations; see
the [new feature tutorial][new-feature-tutorial] for an example.
Additionally you should check out the [detailed testing
docs][testing-docs] for how to run the tests properly after doing a
migration.
(In production, everything runs under supervisord and thus will
restart if it crashes, and `upgrade-zulip` will take care of running
migrations and then cleanly restaring the server for you).
[django-runserver]: https://docs.djangoproject.com/en/1.8/ref/django-admin/#runserver-port-or-address-port
[new-feature-tutorial]: http://zulip.readthedocs.io/en/latest/new-feature-tutorial.html
[testing-docs]: http://zulip.readthedocs.io/en/latest/testing.html
Running the test suite
======================
For more details, especially on how to write tests, check out the
[detailed testing docs][tdocs].
[tdocs]: http://zulip.readthedocs.io/en/latest/testing.html
To run all the tests, do this:
```
./tools/test-all
```
For the Vagrant environment, you'll want to first enter the
environment:
```
vagrant ssh
source /srv/zulip-venv/bin/activate
cd /srv/zulip
```
This runs the linter (`tools/lint-all`) plus all of our test suites;
they can all be run separately (just read `tools/test-all` to see
them). You can also run individual tests which can save you a lot of
time debugging a test failure, e.g.:
```
./tools/lint-all # Runs all the linters in parallel
./tools/test-backend zerver.tests.test_bugdown.BugdownTest.test_inline_youtube
./tools/test-js-with-casper 10-navigation.js
./tools/test-js-with-node # Runs all node tests but is very fast
```
The above setup instructions include the first-time setup of test
databases, but you may need to rebuild the test database occasionally
if you're working on new database migrations. To do this, run:
```
./tools/postgres-init-test-db
./tools/do-destroy-rebuild-test-database
```
Possible testing issues
=======================
- When running the test suite, if you get an error like this:
```
sqlalchemy.exc.ProgrammingError: (ProgrammingError) function ts_match_locs_array(unknown, text, tsquery) does not exist
LINE 2: ...ECT message_id, flags, subject, rendered_content, ts_match_l...
^
```
… then you need to install tsearch-extras, described
above. Afterwards, re-run the `init*-db` and the
`do-destroy-rebuild*-database` scripts.
- When building the development environment using Vagrant and the LXC
provider, if you encounter permissions errors, you may need to
`chown -R 1000:$(whoami) /path/to/zulip` on the host before running
`vagrant up` in order to ensure that the synced directory has the
correct owner during provision. This issue will arise if you run `id
username` on the host where `username` is the user running Vagrant
and the output is anything but 1000.
This seems to be caused by Vagrant behavior; for more information,
see [the vagrant-lxc FAQ entry about shared folder permissions
][lxc-sf].
[lxc-sf]: https://github.com/fgrehm/vagrant-lxc/wiki/FAQ#help-my-shared-folders-have-the-wrong-owner)

310
README.md
View File

@@ -1,167 +1,163 @@
Zulip
=====
Zulip is a powerful, open source group chat application. Written in
Python and using the Django framework, Zulip supports both private
messaging and group chats via conversation streams.
Zulip also supports fast search, drag-and-drop file uploads, image
previews, group private messages, audible notifications,
missed-message emails, desktop apps, and much more.
Further information on the Zulip project and its features can be found
at https://www.zulip.org.
[![Build Status][1]][2]
[1]: https://travis-ci.org/zulip/zulip.svg?branch=master
[2]: https://travis-ci.org/zulip/zulip
Installing the Zulip Development environment
============================================
Using Vagrant
-------------
This is the recommended approach, and is tested on OS X 10.10 as well as Ubuntu 14.04.
* If your host is OS X, download VirtualBox from
<http://download.virtualbox.org/virtualbox/4.3.30/VirtualBox-4.3.30-101610-OSX.dmg>
and install it.
* If your host is Ubuntu 14.04:
sudo apt-get install vagrant lxc lxc-templates cgroup-lite redir && vagrant plugin install vagrant-lxc
Once that's done, simply change to your zulip directory and run
`vagrant up` in your terminal. That will install the development
server inside a Vagrant guest.
Once that finishes, you can run the development server as follows:
```
vagrant ssh -- -L9991:localhost:9991
# Now inside the container
cd /srv/zulip
source /srv/zulip-venv/bin/activate
./tools/run-dev.py --interface=''
```
You can now visit <http://localhost:9991/> in your browser. To get
shell access to the virtual machine running the server, use `vagrant ssh`.
(A small note on tools/run-dev.py: the `--interface=''` option will make
the development server listen on all network interfaces. While this
is correct for the Vagrant guest sitting behind a NAT, you probably
don't want to use that option when using run-dev.py in other environments).
The run-dev.py console output will show any errors your Zulip
development server encounters. It runs on top of Django's "manage.py
runserver" tool, which will automatically restart the Zulip server
whenever you save changes to Python code.
By hand
-------
Install the following non-Python dependencies:
* libffi-dev — needed for some Python extensions
* postgresql 9.1 or later — our database (also install development headers)
* memcached (and headers)
* rabbitmq-server
* libldap2-dev
* python-dev
* redis-server — rate limiting
* tsearch-extras — better text search
On Debian or Ubuntu systems:
```
sudo apt-get install libffi-dev memcached rabbitmq-server libldap2-dev redis-server postgresql-server-dev-all libmemcached-dev
# If on 12.04 or wheezy:
sudo apt-get install postgresql-9.1
wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.1-tsearch-extras_0.1.2_amd64.deb
sudo dpkg -i postgresql-9.1-tsearch-extras_0.1.2_amd64.deb
# If on 14.04:
sudo apt-get install postgresql-9.3
wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.3-tsearch-extras_0.1.2_amd64.deb
sudo dpkg -i postgresql-9.3-tsearch-extras_0.1.2_amd64.deb
# If on 15.04 or jessie:
sudo apt-get install postgresql-9.4
wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.4-tsearch-extras_0.1_amd64.deb
sudo dpkg -i postgresql-9.4-tsearch-extras_0.1_amd64.deb
# Then, all versions:
pip install -r requirements.txt
./scripts/setup/configure-rabbitmq
./tools/postgres-init-db
./tools/do-destroy-rebuild-database
./tools/emoji_dump/build_emoji
```
To start the development server:
```
./tools/run-dev.py
```
… and hit http://localhost:9991/.
Running the test suite
======================
One-time setup of test databases:
```
./tools/postgres-init-test-db
./tools/do-destroy-rebuild-test-database
```
Run all tests:
```
./tools/test-all
```
This runs the linter plus all of our test suites; they can all be run
separately (just read `tools/test-all` to see them). You can also run
individual tests, e.g.:
```
./tools/test-backend zerver.test_bugdown.BugdownTest.test_inline_youtube
./tools/test-js-with-casper 10-navigation.js
```
Possible issues
===============
The Casper tests are flaky on the Virtualbox environment (probably due
to some performance-sensitive races). Until this issue is debugged,
you may need to rerun them to get them to pass.
When running the test suite, if you get an error like this:
```
sqlalchemy.exc.ProgrammingError: (ProgrammingError) function ts_match_locs_array(unknown, text, tsquery) does not exist
LINE 2: ...ECT message_id, flags, subject, rendered_content, ts_match_l...
^
```
… then you need to install tsearch-extras, described above. Afterwards, re-run the `init*-db` and the `do-destroy-rebuild*-database` scripts.
Contributing to Zulip
=====================
Zulip welcomes all forms of contributions!
Before a pull request can be merged, you need to to sign the [Dropbox
Contributor License Agreement](https://opensource.dropbox.com/cla/).
Please run the tests (tools/test-all) before submitting your pull
request.
Zulip has a growing collection of developer documentation including
detailed documentation on coding style available on [Read The
Docs](https://zulip.readthedocs.org/).
Zulip also has a [development discussion mailing list](https://groups.google.com/forum/#!forum/zulip-devel)
Feel free to send any questions or suggestions of areas where you'd
love to see more documentation to the list!
We recommend sending proposals for large features or refactorings to
the zulip-devel list for discussion and advice before getting too deep
into implementation.
Please report any security issues you discover to support@zulip.com.
The Zulip development environment is the recommened option for folks
interested in trying out Zulip. This is documented in
[README.dev.md](README.dev.md).
Running Zulip in production
===========================
This is documented in https://zulip.org/server.html and README.prod.md.
Zulip in production only supports Ubuntu 14.04 right now, but work is
ongoing on adding support for additional platforms. The installation
process is documented in https://zulip.org/server.html and in more
detail in [README.prod.md](README.prod.md).
Contributing to Zulip
=====================
Zulip welcomes all forms of contributions! The page documents the
Zulip development process.
* **Pull requests**. Before a pull request can be merged, you need to
to sign the [Dropbox Contributor License Agreement][cla]. Also,
please skim our [commit message style guidelines][doc-commit-style].
* **Testing**. The Zulip automated tests all run automatically when
you submit a pull request, but you can also run them all in your
development environment following the instructions in the [testing
docs][doc-test].
* **Developer Documentation**. Zulip has a growing collection of
developer documentation on [Read The Docs][doc]. Recommended reading
for new contributors includes the [directory structure][doc-dirstruct]
and [new feature tutorial][doc-newfeat].
* **Mailing lists and bug tracker**. Zulip has a [development
discussion mailing list][gg-devel] and uses [GitHub issues
][gh-issues]. There are also lists for the [Android][email-android]
and [iOS][email-ios] apps. Feel free to send any questions or
suggestions of areas where you'd love to see more documentation to the
relevant list! Please report any security issues you discover to
zulip-security@googlegroups.com.
* **App codebases**. This repository is for the Zulip server and web
app; the [desktop][], [Android][], and [iOS][] apps are separate
repositories.
* **Translations**. Zulip is in the process of being translated into
10+ languages, and we love contributions to our translations. See our
[translating documentation](transifex) if you're interested in
contributing!
[cla]: https://opensource.dropbox.com/cla/
[doc]: https://zulip.readthedocs.io/
[doc-commit-style]: http://zulip.readthedocs.io/en/latest/code-style.html#commit-messages
[doc-dirstruct]: http://zulip.readthedocs.io/en/latest/directory-structure.html
[doc-newfeat]: http://zulip.readthedocs.io/en/latest/new-feature-tutorial.html
[doc-test]: https://github.com/zulip/zulip/blob/master/README.dev.md#running-the-test-suite
[gg-devel]: https://groups.google.com/forum/#!forum/zulip-devel
[gh-issues]: https://github.com/zulip/zulip/issues
[desktop]: https://github.com/zulip/zulip-desktop
[android]: https://github.com/zulip/zulip-android
[ios]: https://github.com/zulip/zulip-ios
[email-android]: https://groups.google.com/forum/#!forum/zulip-android
[email-ios]: https://groups.google.com/forum/#!forum/zulip-ios
[transifex]: https://www.transifex.com/zulip/zulip/
How to get involved with contributing to Zulip
==============================================
First, subscribe to the Zulip [development discussion mailing
list][gg-devel].
The Zulip project uses a system of labels in our [issue
tracker][gh-issues] to make it easy to find a project if you don't
have your own project idea in mind or want to get some experience with
working on Zulip before embarking on a larger project you have in
mind:
* [Integrations](https://github.com/zulip/zulip/labels/integrations).
Integrate Zulip with another piece of software and contribute it
back to the community! Writing an integration can be a great first
contribution. There's detailed documentation on how to write
integrations in [the Zulip integration writing
guide](https://zulip.readthedocs.io/en/latest/integration-guide.html).
* [Bite Size](https://github.com/zulip/zulip/labels/bite%20size):
Smaller projects that might be a great first contribution.
* [Documentation](https://github.com/zulip/zulip/labels/documentation):
The Zulip project loves contributions of new documentation.
* [Help Wanted](https://github.com/zulip/zulip/labels/help%20wanted):
A broader list of projects that nobody is currently working on.
* [Platform support](https://github.com/zulip/zulip/labels/Platform%20support):
These are open issues about making it possible to install Zulip on a
wider range of platforms.
* [Bugs](https://github.com/zulip/zulip/labels/bug): Open bugs.
* [Feature requests](https://github.com/zulip/zulip/labels/enhancement):
Browsing this list can be a great way to find feature ideas to
implement that other Zulip users are excited about.
* [2016 roadmap milestone](http://zulip.readthedocs.io/en/latest/roadmap.html): The
projects that are [priorities for the Zulip project](https://zulip.readthedocs.io/en/latest/roadmap.html). These are great projects if you're looking to make an impact.
If you're excited about helping with an open issue, just post on the
conversation thread that you're working on it. You're encouraged to
ask questions on how to best implement or debug your changes -- the
Zulip maintainers are excited to answer questions to help you stay
unblocked and working efficiently.
We also welcome suggestions of features that you feel would be
valuable or changes that you feel would make Zulip a better open
source project, and are happy to support you in adding new features or
other user experience improvements to Zulip.
If you have a new feature you'd like to add, we recommend you start by
opening a GitHub issue about the feature idea explaining the problem
that you're hoping to solve and that you're excited to work on it. A
Zulip maintainer will usually reply within a day with feedback on the
idea, notes on any important issues or concerns, and and often tips on
how to implement or test it. Please feel free to ping the thread if
you don't hear a response from the maintainers -- we try to be very
responsive so this usually means we missed your message.
For significant changes to the visual design, user experience, data
model, or architecture, we highly recommend posting a mockup,
screenshot, or description of what you have in mind to zulip-devel@ to
get broad feedback before you spend too much time on implementation
details.
Finally, before implementing a larger feature, we highly recommend
looking at the new feature tutorial and coding style guidelines on
ReadTheDocs.
Feedback on how to make this development process more efficient, fun,
and friendly to new contributors is very welcome! Just send an email
to the Zulip Developers list with your thoughts.
License
=======

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: Zulip
Upstream-Contact: Zulip Development Discussion <zulip-devel@googlegroups.com>
Source: https://zulip.org/
Comment:
Comment:
Unless otherwise noted, the Zulip software is distributed under the Apache
License, Version 2.0. The software includes some works released by third
parties under other free and open source licenses. Those works are
@@ -38,10 +38,6 @@ Files: confirmation/*
Copyright: 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
License: BSD-3-Clause
Files: node_modules/handlebars/*
Copyright: 2011 Yehuda Katz
License: Expat
Files: puppet/apt/*
Copyright: 2011, Evolving Web Inc.
License: Expat
@@ -55,28 +51,28 @@ Comment: https://github.com/DavidS/puppet-common
Files: puppet/stdlib/*
Copyright: 2011, Krzysztof Wilczynski
2011, Puppet Labs Inc
2011, Puppet Labs Inc
License: Apache-2.0
File: puppet/zulip_internal/files/mediawiki/Auth_remoteuser.php
Copyright: 2006 Otheus Shelling
Copyright: 2006 Otheus Shelling
2007 Rusty Burchfield
2009 James Kinsman
2010 Daniel Thomas
2009 James Kinsman
2010 Daniel Thomas
2010 Ian Ward Comfort
License: GPL-2.0
Comment: Not linked.
Files: puppet/zulip_internal/files/nagios_plugins/check_debian_packages
Files: puppet/zulip/files/nagios_plugins/zulip_base/check_debian_packages
Copyright: 2005 Francesc Guasch
License: GPL-2.0
Comment: Not linked.
Files: puppet/zulip_internal/files/nagios_plugins/check_postgres.pl
Files: puppet/zulip/files/nagios_plugins/zulip_postgres_appdb/check_postgres.pl
Copyright: 2007-2015 Greg Sabino Mullane
License: BSD-2-Clause
Files: puppet/zulip_internal/files/nagios_plugins/check_website_response.sh
Files: puppet/zulip/files/nagios_plugins/zulip_nagios_server/check_website_response.sh
Copyright: 2011 Chris Freeman
License: GPL-2.0
@@ -131,10 +127,6 @@ Copyright: Google, Inc.
License: Apache-2.0
Comment: These are actually Noto Emoji, not gemoji.
Files: static/third/handlebars/handlebars.runtime.js
Copyright: 2011 Yehuda Katz
License: Expat
Files: static/third/html5-formdata/formdata.js
Copyright: 2010 François de Metz
License: Expat
@@ -205,7 +197,7 @@ License: SIL-OFL-1.1
Files: static/third/spectrum/*
Copyright: 2013 Brian Grinstead
License: Expat
License: Expat
Files: static/third/spin/spin.js
Copyright: 2011-2013 Felix Gnass
@@ -226,7 +218,7 @@ Copyright: 2010 C. F., Wong
License: Expat
Files: static/third/zocial/*
Copyright: Sam Collins
Copyright: Sam Collins
License: Expat
Files: tools/inject-messages/othello
@@ -237,10 +229,6 @@ Files: tools/jslint/jslint.js
Copyright: 2002 Douglas Crockford
License: XXX-good-not-evil
Files: tools/python-proxy
Copyright: 2009 F.bio Domingues
License: Expat
Files: tools/review
Copyright: 2010 Ksplice, Inc.
License: Apache-2.0
@@ -254,11 +242,329 @@ Files: zerver/lib/ccache.py
Copyright: 2013 David Benjamin and Alan Huang
License: Expat
Files: zerver/tests/frontend/casperjs/*
Files: zerver/lib/decorator.py zerver/management/commands/runtornado.py scripts/setup/generate_secrets.py
Copyright: Django Software Foundation and individual contributors
License: BSD-3-Clause
Files: frontend_tests/casperjs/*
Copyright: 2011-2012 Nicolas Perriault
Joyent, Inc. and other Node contributors
License: Expat
Files: zerver/tests/frontend/casperjs/modules/vendors/*
Files: frontend_tests/casperjs/modules/vendors/*
Copyright: 2011, Jeremy Ashkenas
License: Expat
License: Apache-2.0
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
.
http://www.apache.org/licenses/LICENSE-2.0
.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
.
On Debian systems, the full text of the Apache License version 2 can
be found in /usr/share/common-licenses/Apache-2.0.
License: BSD-2-clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice(s), this list of conditions and the following disclaimer
unmodified other than the allowable addition of one or more
copyright notices.
2. Redistributions in binary form must reproduce the above copyright
notice(s), this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
License: BSD-3-Clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
.
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
License: CC-0-1.0
Creative Commons CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION
ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE
USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND
DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT
OR THE INFORMATION OR WORKS PROVIDED HEREUNDER.
.
Statement of Purpose
.
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work
of authorship and/or a database (each, a "Work").
.
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without
fear of later claims of infringement build upon, modify, incorporate in
other works, reuse and redistribute as freely as possible in any form
whatsoever and for any purposes, including without limitation commercial
purposes. These owners may contribute to the Commons to promote the
ideal of a free culture and the further production of creative, cultural
and scientific works, or to gain reputation or greater distribution for
their Work in part through the use and efforts of others.
.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or
she is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under
its terms, with knowledge of his or her Copyright and Related Rights in
the Work and the meaning and intended legal effect of CC0 on those
rights.
.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
.
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
.
ii. moral rights retained by the original author(s) and/or performer(s);
.
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
.
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
.
v. rights protecting the extraction, dissemination, use and reuse of
data in a Work;
.
vi. database rights (such as those arising under Directive 96/9/EC of
the European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
.
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or
future medium and for any number of copies, and (iv) for any purpose
whatsoever, including without limitation commercial, advertising or
promotional purposes (the "Waiver"). Affirmer makes the Waiver for the
benefit of each member of the public at large and to the detriment of
Affirmer's heirs and successors, fully intending that such Waiver shall
not be subject to revocation, rescission, cancellation, termination, or
any other legal or equitable action to disrupt the quiet enjoyment of
the Work by the public as contemplated by Affirmer's express Statement
of Purpose.
.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non
exclusive, irrevocable and unconditional license to exercise Affirmer's
Copyright and Related Rights in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or
future medium and for any number of copies, and (iv) for any purpose
whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed
effective as of the date CC0 was applied by Affirmer to the Work. Should
any part of the License for any reason be judged legally invalid or
ineffective under applicable law, such partial invalidity or
ineffectiveness shall not invalidate the remainder of the License, and
in such case Affirmer hereby affirms that he or she will not (i)
exercise any of his or her remaining Copyright and Related Rights in the
Work or (ii) assert any associated claims and causes of action with
respect to the Work, in either case contrary to Affirmer's express
Statement of Purpose.
.
4. Limitations and Disclaimers.
.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied, statutory
or otherwise, including without limitation warranties of title,
merchantability, fitness for a particular purpose, non infringement, or
the absence of latent or other defects, accuracy, or the present or
absence of errors, whether or not discoverable, all to the greatest
extent permissible under applicable law.
.
c. Affirmer disclaims responsibility for clearing rights of other
persons that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the Work.
.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
License: Expat
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.
License: GPL-2.0
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2, dated June, 1991.
.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
.
On Debian systems, the complete text of the GNU General Public License
can be found in /usr/share/common-licenses/GPL-2 file.
License: SIL-OFL-1.1
---------------------------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
---------------------------------------------------------------------------
.
PREAMBLE
.
The goals of the Open Font License (OFL) are to stimulate worldwide development
of collaborative font projects, to support the font creation efforts of academic
and linguistic communities, and to provide a free and open framework in which
fonts may be shared and improved in partnership with others.
.
The OFL allows the licensed fonts to be used, studied, modified and redistributed
freely as long as they are not sold by themselves. The fonts, including any
derivative works, can be bundled, embedded, redistributed and/or sold with any
software provided that any reserved names are not used by derivative works. The
fonts and derivatives, however, cannot be released under any other type of license.
The requirement for fonts to remain under this license does not apply to any
document created using the fonts or their derivatives.
.
DEFINITIONS
.
"Font Software" refers to the set of files released by the Copyright Holder(s) under
this license and clearly marked as such. This may include source files, build
scripts and documentation.
.
"Reserved Font Name" refers to any names specified as such after the copyright
statement(s).
.
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
.
"Modified Version" refers to any derivative made by adding to, deleting, or
substituting -- in part or in whole -- any of the components of the Original Version,
by changing formats or by porting the Font Software to a new environment.
.
"Author" refers to any designer, engineer, programmer, technical writer or other
person who contributed to the Font Software.
.
PERMISSION & CONDITIONS
.
Permission is hereby granted, free of charge, to any person obtaining a copy of the
Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell
modified and unmodified copies of the Font Software, subject to the following
conditions:
.
1) Neither the Font Software nor any of its individual components, in Original or
Modified Versions, may be sold by itself.
.
2) Original or Modified Versions of the Font Software may be bundled, redistributed
and/or sold with any software, provided that each copy contains the above copyright
notice and this license. These can be included either as stand-alone text files,
human-readable headers or in the appropriate machine-readable metadata fields within
text or binary files as long as those fields can be easily viewed by the user.
.
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless
explicit written permission is granted by the corresponding Copyright Holder. This
restriction only applies to the primary font name as presented to the users.
.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall
not be used to promote, endorse or advertise any Modified Version, except to
acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with
their explicit written permission.
.
5) The Font Software, modified or unmodified, in part or in whole, must be distributed
entirely under this license, and must not be distributed under any other license. The
requirement for fonts to remain under this license does not apply to any document
created using the Font Software.
.
TERMINATION
.
This license becomes null and void if any of the above conditions are not met.
.
DISCLAIMER
.
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER
RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.

52
Vagrantfile vendored
View File

@@ -2,6 +2,11 @@
VAGRANTFILE_API_VERSION = "2"
def command?(name)
`which #{name}`
$?.success?
end
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# For LXC. VirtualBox hosts use a different box, described below.
@@ -13,6 +18,49 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder ".", "/srv/zulip"
proxy_config_file = ENV['HOME'] + "/.zulip-vagrant-config"
if File.file?(proxy_config_file)
http_proxy = https_proxy = no_proxy = ""
IO.foreach(proxy_config_file) do |line|
line.chomp!
key, value = line.split(nil, 2)
case key
when /^([#;]|$)/; # ignore comments
when "HTTP_PROXY"; http_proxy = value
when "HTTPS_PROXY"; https_proxy = value
when "NO_PROXY"; no_proxy = value
end
end
if Vagrant.has_plugin?("vagrant-proxyconf")
if http_proxy != ""
config.proxy.http = http_proxy
end
if https_proxy != ""
config.proxy.https = https_proxy
end
if https_proxy != ""
config.proxy.no_proxy = no_proxy
end
end
end
# Specify LXC provider before VirtualBox provider so it's preferred.
config.vm.provider "lxc" do |lxc|
if command? "lxc-ls"
LXC_VERSION = `lxc-ls --version`.strip unless defined? LXC_VERSION
if LXC_VERSION >= "1.1.0"
# Allow start without AppArmor, otherwise Box will not Start on Ubuntu 14.10
# see https://github.com/fgrehm/vagrant-lxc/issues/333
lxc.customize 'aa_allow_incomplete', 1
end
if LXC_VERSION >= "2.0.0"
lxc.backingstore = 'dir'
end
end
end
config.vm.provider "virtualbox" do |vb, override|
override.vm.box = "ubuntu/trusty64"
# 2GiB seemed reasonable here. The VM OOMs with only 1024MiB.
@@ -22,9 +70,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
$provision_script = <<SCRIPT
set -x
set -e
sudo apt-get update
sudo apt-get install -y python-pbs
python /srv/zulip/provision.py
/usr/bin/python /srv/zulip/provision.py
SCRIPT
config.vm.provision "shell",

View File

@@ -1,4 +1,5 @@
from __future__ import absolute_import
from __future__ import print_function
from django.core.management.base import BaseCommand
@@ -21,7 +22,7 @@ class Command(BaseCommand):
# Calculate 10min, 2hrs, 12hrs, 1day, 2 business days (TODO business days), 1 week bucket of stats
hour_buckets = [0.16, 2, 12, 24, 48, 168]
user_info = defaultdict(dict)
user_info = defaultdict(dict) # type: Dict[str, Dict[float, List[str]]]
for last_presence in users:
if last_presence.status == UserPresence.IDLE:
@@ -36,13 +37,13 @@ class Command(BaseCommand):
user_info[last_presence.user_profile.realm.domain][bucket].append(last_presence.user_profile.email)
for realm, buckets in user_info.items():
print("Realm %s" % realm)
print("Realm %s" % (realm,))
for hr, users in sorted(buckets.items()):
print("\tUsers for %s: %s" % (hr, len(users)))
statsd.gauge("users.active.%s.%shr" % (statsd_key(realm, True), statsd_key(hr, True)), len(users))
# Also do stats for how many users have been reading the app.
users_reading = UserActivity.objects.select_related().filter(query="/json/update_message_flags")
users_reading = UserActivity.objects.select_related().filter(query="/json/messages/flags")
user_info = defaultdict(dict)
for activity in users_reading:
for bucket in hour_buckets:
@@ -51,7 +52,7 @@ class Command(BaseCommand):
if datetime.now(activity.last_visit.tzinfo) - activity.last_visit < timedelta(hours=bucket):
user_info[activity.user_profile.realm.domain][bucket].append(activity.user_profile.email)
for realm, buckets in user_info.items():
print("Realm %s" % realm)
print("Realm %s" % (realm,))
for hr, users in sorted(buckets.items()):
print("\tUsers reading for %s: %s" % (hr, len(users)))
statsd.gauge("users.reading.%s.%shr" % (statsd_key(realm, True), statsd_key(hr, True)), len(users))

View File

@@ -1,4 +1,5 @@
from __future__ import absolute_import
from __future__ import print_function
import datetime
import pytz
@@ -19,6 +20,6 @@ class Command(BaseCommand):
date = datetime.datetime.now() - datetime.timedelta(days=1)
else:
date = datetime.datetime.strptime(options["date"], "%Y-%m-%d")
print "Activity data for", date
print activity_averages_during_day(date)
print "Please note that the total registered user count is a total for today"
print("Activity data for", date)
print(activity_averages_during_day(date))
print("Please note that the total registered user count is a total for today")

View File

@@ -1,4 +1,5 @@
from __future__ import absolute_import
from __future__ import print_function
from optparse import make_option
from django.core.management.base import BaseCommand
@@ -26,15 +27,15 @@ def compute_stats(log_level):
"bitcoin@mit.edu", "lp@mit.edu", "clocks@mit.edu",
"root@mit.edu", "nagios@mit.edu",
"www-data|local-realm@mit.edu"])
user_counts = {}
user_counts = {} # type: Dict[str, Dict[str, int]]
for m in mit_query.select_related("sending_client", "sender"):
email = m.sender.email
user_counts.setdefault(email, {})
user_counts[email].setdefault(m.sending_client.name, 0)
user_counts[email][m.sending_client.name] += 1
total_counts = {}
total_user_counts = {}
total_counts = {} # type: Dict[str, int]
total_user_counts = {} # type: Dict[str, int]
for email, counts in user_counts.items():
total_user_counts.setdefault(email, 0)
for client_name, count in counts.items():
@@ -43,9 +44,9 @@ def compute_stats(log_level):
total_user_counts[email] += count
logging.debug("%40s | %10s | %s" % ("User", "Messages", "Percentage Zulip"))
top_percents = {}
top_percents = {} # type: Dict[int, float]
for size in [10, 25, 50, 100, 200, len(total_user_counts.keys())]:
top_percents[size] = 0
top_percents[size] = 0.0
for i, email in enumerate(sorted(total_user_counts.keys(),
key=lambda x: -total_user_counts[x])):
percent_zulip = round(100 - (user_counts[email].get("zephyr_mirror", 0)) * 100. /
@@ -63,7 +64,7 @@ def compute_stats(log_level):
logging.info("Top %6s | %s%%" % (size, round(top_percents[size], 1)))
grand_total = sum(total_counts.values())
print grand_total
print(grand_total)
logging.info("%15s | %s" % ("Client", "Percentage"))
for client in total_counts.keys():
logging.info("%15s | %s%%" % (client, round(100. * total_counts[client] / grand_total, 1)))

View File

@@ -1,4 +1,6 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from zerver.lib.statistics import seconds_usage_between
@@ -16,7 +18,7 @@ def analyze_activity(options):
if options["realm"]:
user_profile_query = user_profile_query.filter(realm__domain=options["realm"])
print "Per-user online duration:\n"
print("Per-user online duration:\n")
total_duration = datetime.timedelta(0)
for user_profile in user_profile_query:
duration = seconds_usage_between(user_profile, day_start, day_end)
@@ -25,11 +27,11 @@ def analyze_activity(options):
continue
total_duration += duration
print "%-*s%s" % (37, user_profile.email, duration, )
print("%-*s%s" % (37, user_profile.email, duration, ))
print "\nTotal Duration: %s" % (total_duration,)
print "\nTotal Duration in minutes: %s" % (total_duration.total_seconds() / 60.,)
print "Total Duration amortized to a month: %s" % (total_duration.total_seconds() * 30. / 60.,)
print("\nTotal Duration: %s" % (total_duration,))
print("\nTotal Duration in minutes: %s" % (total_duration.total_seconds() / 60.,))
print("Total Duration amortized to a month: %s" % (total_duration.total_seconds() * 30. / 60.,))
class Command(BaseCommand):
help = """Report analytics of user activity on a per-user and realm basis.
@@ -42,7 +44,7 @@ It will correctly not count server-initiated reloads in the activity statistics.
The duration flag can be used to control how many days to show usage duration for
Usage: python manage.py analyze_user_activity [--realm=zulip.com] [--date=2013-09-10] [--duration=1]
Usage: python2.7 manage.py analyze_user_activity [--realm=zulip.com] [--date=2013-09-10] [--duration=1]
By default, if no date is selected 2013-09-10 is used. If no realm is provided, information
is shown for all realms"""

View File

@@ -1,4 +1,5 @@
from __future__ import absolute_import
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.db.models import Count
@@ -13,9 +14,9 @@ class Command(BaseCommand):
Usage examples:
python manage.py client_activity
python manage.py client_activity zulip.com
python manage.py client_activity jesstess@zulip.com"""
python2.7 manage.py client_activity
python2.7 manage.py client_activity zulip.com
python2.7 manage.py client_activity jesstess@zulip.com"""
def add_arguments(self, parser):
parser.add_argument('arg', metavar='<arg>', type=str, nargs='?', default=None,
@@ -48,8 +49,8 @@ python manage.py client_activity jesstess@zulip.com"""
counts.sort()
for count in counts:
print "%25s %15d" % (count[1], count[0])
print "Total:", total
print("%25s %15d" % (count[1], count[0]))
print("Total:", total)
def handle(self, *args, **options):
@@ -70,5 +71,5 @@ python manage.py client_activity jesstess@zulip.com"""
self.compute_activity(UserActivity.objects.filter(
user_profile__realm=realm))
except Realm.DoesNotExist:
print "Unknown user or domain %s" % (arg,)
print("Unknown user or domain %s" % (arg,))
exit(1)

View File

@@ -1,4 +1,6 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import datetime
import pytz
@@ -6,7 +8,7 @@ import pytz
from django.core.management.base import BaseCommand
from django.db.models import Count
from zerver.models import UserProfile, Realm, Stream, Message, Recipient, UserActivity, \
Subscription, UserMessage
Subscription, UserMessage, get_realm
MOBILE_CLIENT_LIST = ["Android", "ios"]
HUMAN_CLIENT_LIST = MOBILE_CLIENT_LIST + ["website"]
@@ -27,7 +29,7 @@ class Command(BaseCommand):
UserActivity.objects.filter(user_profile__realm=realm,
user_profile__is_active=True,
last_visit__gt=activity_cutoff,
query="/json/update_pointer",
query="/json/users/me/pointer",
client__name="website")]
def messages_sent_by(self, user, days_ago):
@@ -65,52 +67,51 @@ class Command(BaseCommand):
fraction = 0.0
else:
fraction = numerator / float(denominator)
print "%.2f%% of" % (fraction * 100,), text
print("%.2f%% of" % (fraction * 100,), text)
def handle(self, *args, **options):
if options['realms']:
try:
realms = [Realm.objects.get(domain=domain) for domain in options['realms']]
except Realm.DoesNotExist, e:
print e
realms = [get_realm(domain) for domain in options['realms']]
except Realm.DoesNotExist as e:
print(e)
exit(1)
else:
realms = Realm.objects.all()
for realm in realms:
print realm.domain
print(realm.domain)
user_profiles = UserProfile.objects.filter(realm=realm, is_active=True)
active_users = self.active_users(realm)
num_active = len(active_users)
print "%d active users (%d total)" % (num_active, len(user_profiles))
print("%d active users (%d total)" % (num_active, len(user_profiles)))
streams = Stream.objects.filter(realm=realm).extra(
tables=['zerver_subscription', 'zerver_recipient'],
where=['zerver_subscription.recipient_id = zerver_recipient.id',
'zerver_recipient.type = 2',
'zerver_recipient.type_id = zerver_stream.id',
'zerver_subscription.active = true']).annotate(count=Count("name"))
print "%d streams" % (streams.count(),)
print("%d streams" % (streams.count(),))
for days_ago in (1, 7, 30):
print "In last %d days, users sent:" % (days_ago,)
print("In last %d days, users sent:" % (days_ago,))
sender_quantities = [self.messages_sent_by(user, days_ago) for user in user_profiles]
for quantity in sorted(sender_quantities, reverse=True):
print quantity,
print ""
print(quantity, end=' ')
print("")
print "%d stream messages" % (self.stream_messages(realm, days_ago),)
print "%d one-on-one private messages" % (self.private_messages(realm, days_ago),)
print "%d messages sent via the API" % (self.api_messages(realm, days_ago),)
print "%d group private messages" % (self.group_private_messages(realm, days_ago),)
print("%d stream messages" % (self.stream_messages(realm, days_ago),))
print("%d one-on-one private messages" % (self.private_messages(realm, days_ago),))
print("%d messages sent via the API" % (self.api_messages(realm, days_ago),))
print("%d group private messages" % (self.group_private_messages(realm, days_ago),))
num_notifications_enabled = len(filter(lambda x: x.enable_desktop_notifications == True,
active_users))
num_notifications_enabled = len([x for x in active_users if x.enable_desktop_notifications == True])
self.report_percentage(num_notifications_enabled, num_active,
"active users have desktop notifications enabled")
num_enter_sends = len(filter(lambda x: x.enter_sends, active_users))
num_enter_sends = len([x for x in active_users if x.enter_sends])
self.report_percentage(num_enter_sends, num_active,
"active users have enter-sends")
@@ -124,8 +125,8 @@ class Command(BaseCommand):
starrers = UserMessage.objects.filter(user_profile__in=user_profiles,
flags=UserMessage.flags.starred).values(
"user_profile").annotate(count=Count("user_profile"))
print "%d users have starred %d messages" % (
len(starrers), sum([elt["count"] for elt in starrers]))
print("%d users have starred %d messages" % (
len(starrers), sum([elt["count"] for elt in starrers])))
active_user_subs = Subscription.objects.filter(
user_profile__in=user_profiles, active=True)
@@ -133,20 +134,20 @@ class Command(BaseCommand):
# Streams not in home view
non_home_view = active_user_subs.filter(in_home_view=False).values(
"user_profile").annotate(count=Count("user_profile"))
print "%d users have %d streams not in home view" % (
len(non_home_view), sum([elt["count"] for elt in non_home_view]))
print("%d users have %d streams not in home view" % (
len(non_home_view), sum([elt["count"] for elt in non_home_view])))
# Code block markup
markup_messages = human_messages.filter(
sender__realm=realm, content__contains="~~~").values(
"sender").annotate(count=Count("sender"))
print "%d users have used code block markup on %s messages" % (
len(markup_messages), sum([elt["count"] for elt in markup_messages]))
print("%d users have used code block markup on %s messages" % (
len(markup_messages), sum([elt["count"] for elt in markup_messages])))
# Notifications for stream messages
notifications = active_user_subs.filter(notifications=True).values(
"user_profile").annotate(count=Count("user_profile"))
print "%d users receive desktop notifications for %d streams" % (
len(notifications), sum([elt["count"] for elt in notifications]))
print("%d users receive desktop notifications for %d streams" % (
len(notifications), sum([elt["count"] for elt in notifications])))
print ""
print("")

View File

@@ -1,8 +1,9 @@
from __future__ import absolute_import
from __future__ import print_function
from django.core.management.base import BaseCommand
from django.db.models import Q
from zerver.models import Realm, Stream, Message, Subscription, Recipient
from zerver.models import Realm, Stream, Message, Subscription, Recipient, get_realm
class Command(BaseCommand):
help = "Generate statistics on the streams for a realm."
@@ -14,27 +15,27 @@ class Command(BaseCommand):
def handle(self, *args, **options):
if options['realms']:
try:
realms = [Realm.objects.get(domain=domain) for domain in options['realms']]
except Realm.DoesNotExist, e:
print e
realms = [get_realm(domain) for domain in options['realms']]
except Realm.DoesNotExist as e:
print(e)
exit(1)
else:
realms = Realm.objects.all()
for realm in realms:
print realm.domain
print "------------"
print "%25s %15s %10s" % ("stream", "subscribers", "messages")
print(realm.domain)
print("------------")
print("%25s %15s %10s" % ("stream", "subscribers", "messages"))
streams = Stream.objects.filter(realm=realm).exclude(Q(name__istartswith="tutorial-"))
invite_only_count = 0
for stream in streams:
if stream.invite_only:
invite_only_count += 1
continue
print "%25s" % (stream.name,),
print("%25s" % (stream.name,), end=' ')
recipient = Recipient.objects.filter(type=Recipient.STREAM, type_id=stream.id)
print "%10d" % (len(Subscription.objects.filter(recipient=recipient, active=True)),),
print("%10d" % (len(Subscription.objects.filter(recipient=recipient, active=True)),), end=' ')
num_messages = len(Message.objects.filter(recipient=recipient))
print "%12d" % (num_messages,)
print "%d invite-only streams" % (invite_only_count,)
print ""
print("%12d" % (num_messages,))
print("%d invite-only streams" % (invite_only_count,))
print("")

View File

@@ -1,10 +1,12 @@
from __future__ import absolute_import
from __future__ import print_function
import datetime
import pytz
from django.core.management.base import BaseCommand
from zerver.models import UserProfile, Realm, Stream, Message
from zerver.models import UserProfile, Realm, Stream, Message, get_realm
from six.moves import range
class Command(BaseCommand):
help = "Generate statistics on user activity."
@@ -21,21 +23,21 @@ class Command(BaseCommand):
def handle(self, *args, **options):
if options['realms']:
try:
realms = [Realm.objects.get(domain=domain) for domain in options['realms']]
except Realm.DoesNotExist, e:
print e
realms = [get_realm(domain) for domain in options['realms']]
except Realm.DoesNotExist as e:
print(e)
exit(1)
else:
realms = Realm.objects.all()
for realm in realms:
print realm.domain
print(realm.domain)
user_profiles = UserProfile.objects.filter(realm=realm, is_active=True)
print "%d users" % (len(user_profiles),)
print "%d streams" % (len(Stream.objects.filter(realm=realm)),)
print("%d users" % (len(user_profiles),))
print("%d streams" % (len(Stream.objects.filter(realm=realm)),))
for user_profile in user_profiles:
print "%35s" % (user_profile.email,),
print("%35s" % (user_profile.email,), end=' ')
for week in range(10):
print "%5d" % (self.messages_sent_by(user_profile, week)),
print ""
print("%5d" % (self.messages_sent_by(user_profile, week)), end=' ')
print("")

View File

@@ -1,3 +1,7 @@
from __future__ import absolute_import
from __future__ import division
from typing import Any, Dict, List, Tuple
from django.db import connection
from django.template import RequestContext, loader
from django.utils.html import mark_safe
@@ -15,6 +19,10 @@ import itertools
import time
import re
import pytz
from six.moves import filter
from six.moves import map
from six.moves import range
from six.moves import zip
eastern_tz = pytz.timezone('US/Eastern')
def make_table(title, cols, rows, has_row_class=False):
@@ -22,7 +30,7 @@ def make_table(title, cols, rows, has_row_class=False):
if not has_row_class:
def fix_row(row):
return dict(cells=row, row_class=None)
rows = map(fix_row, rows)
rows = list(map(fix_row, rows))
data = dict(title=title, cols=cols, rows=rows)
@@ -37,7 +45,7 @@ def dictfetchall(cursor):
"Returns all rows from a cursor as a dict"
desc = cursor.description
return [
dict(zip([col[0] for col in desc], row))
dict(list(zip([col[0] for col in desc], row)))
for row in cursor.fetchall()
]
@@ -70,7 +78,7 @@ def get_realm_day_counts():
rows = dictfetchall(cursor)
cursor.close()
counts = defaultdict(dict)
counts = defaultdict(dict) # type: Dict[str, Dict[int, int]]
for row in rows:
counts[row['domain']][row['age']] = row['cnt']
@@ -132,7 +140,8 @@ def realm_summary_table(realm_minutes):
'/json/send_message',
'send_message_backend',
'/api/v1/send_message',
'/json/update_pointer'
'/json/update_pointer',
'/json/users/me/pointer'
)
AND
last_visit > now() - interval '1 day'
@@ -161,8 +170,9 @@ def realm_summary_table(realm_minutes):
ua.query in (
'/json/send_message',
'send_message_backend',
'/api/v1/send_message',
'/json/update_pointer'
'/api/v1/send_message',
'/json/update_pointer',
'/json/users/me/pointer'
)
GROUP by realm.id, up.email
HAVING max(last_visit) between
@@ -182,7 +192,8 @@ def realm_summary_table(realm_minutes):
'/json/send_message',
'/api/v1/send_message',
'send_message_backend',
'/json/update_pointer'
'/json/update_pointer',
'/json/users/me/pointer'
)
AND
up.realm_id = realm.id
@@ -226,7 +237,7 @@ def realm_summary_table(realm_minutes):
def meets_goal(row):
return row['active_user_count'] >= 5
num_active_sites = len(filter(meets_goal, rows))
num_active_sites = len(list(filter(meets_goal, rows)))
# create totals
total_active_user_count = 0
@@ -375,7 +386,7 @@ def ad_hoc_queries():
cursor = connection.cursor()
cursor.execute(query)
rows = cursor.fetchall()
rows = map(list, rows)
rows = list(map(list, rows))
cursor.close()
def fix_rows(i, fixup_func):
@@ -609,12 +620,13 @@ def raw_user_activity_table(records):
format_date_for_activity_reports(record.last_visit)
]
rows = map(row, records)
rows = list(map(row, records))
title = 'Raw Data'
return make_table(title, cols, rows)
def get_user_activity_summary(records):
summary = {}
# type: (Any) -> Any
summary = {} # type: Dict[str, Dict[str, Any]]
def update(action, record):
if action not in summary:
summary[action] = dict(
@@ -649,7 +661,7 @@ def get_user_activity_summary(records):
update('website', record)
if ('send_message' in query) or re.search('/api/.*/external/.*', query):
update('send', record)
if query in ['/json/update_pointer', '/api/v1/update_pointer']:
if query in ['/json/update_pointer', '/json/users/me/pointer', '/api/v1/update_pointer']:
update('pointer', record)
update(client, record)
@@ -811,20 +823,19 @@ def realm_user_summary_table(all_records, admin_emails):
@zulip_internal
def get_realm_activity(request, realm):
data = []
all_records = {}
all_user_records = {}
# type: (Any, Any) -> Any
data = [] # type: List[Tuple[str, str]]
all_user_records = {} # type: Dict[str, Any]
try:
admins = Realm.objects.get(domain=realm).get_admin_users()
admins = get_realm(realm).get_admin_users()
except Realm.DoesNotExist:
return HttpResponseNotFound("Realm %s does not exist" % (realm,))
admin_emails = {admin.email for admin in admins}
for is_bot, page_title in [(False, 'Humans'), (True, 'Bots')]:
all_records = get_user_activity_records_for_realm(realm, is_bot)
all_records = list(all_records)
all_records = list(get_user_activity_records_for_realm(realm, is_bot))
user_records, content = realm_user_summary_table(all_records, admin_emails)
all_user_records.update(user_records)
@@ -856,7 +867,7 @@ def get_realm_activity(request, realm):
def get_user_activity(request, email):
records = get_user_activity_records_for_email(email)
data = []
data = [] # type: List[Tuple[str, str]]
user_summary = get_user_activity_summary(records)
content = user_activity_summary_table(user_summary)

View File

@@ -8,3 +8,4 @@ include examples/unsubscribe
include examples/list-members
include examples/list-subscriptions
include examples/print-messages
include examples/recent-messages

View File

@@ -31,11 +31,24 @@ file is as follows:
key=<api key from the web interface>
email=<your email address>
site=<your Zulip server's URI>
insecure=<true or false, true means do not verify the server certificate>
cert_bundle=<path to a file containing CA or server certificates to trust>
If omitted, these settings have the following defaults:
site=https://api.zulip.com
insecure=false
cert_bundle=<the default CA bundle trusted by Python>
Alternatively, you may explicitly use "--user" and "--api-key" in our
examples, which is especially useful if you are running several bots
which share a home directory. There is also a "--site" option for
setting the Zulip server on the command line.
which share a home directory.
The command line equivalents for other configuration options are:
--site=<your Zulip server's URI>
--insecure
--cert-bundle=<file>
You can obtain your Zulip API key, create bots, and manage bots all
from your Zulip [settings page](https://zulip.com/#settings).
@@ -101,3 +114,46 @@ Alternatively, if you don't want to use your ~/.zuliprc file:
--api-key a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 \
hamlet@example.com cordelia@example.com -m \
"Conscience doth make cowards of us all."
#### Working with an untrusted server certificate
If your server has either a self-signed certificate, or a certificate signed
by a CA that you don't wish to globally trust then by default the API will
fail with an SSL verification error.
You can add `insecure=true` to your .zuliprc file.
[api]
site=https://zulip.example.com
insecure=true
This disables verification of the server certificate, so connections are
encrypted but unauthenticated. This is not secure, but may be good enough
for a development environment.
You can explicitly trust the server certificate using `cert_bundle=<filename>`
in your .zuliprc file.
[api]
site=https://zulip.example.com
cert_bundle=/home/bots/certs/zulip.example.com.crt
You can also explicitly trust a different set of Certificate Authorities from
the default bundle that is trusted by Python. For example to trust a company
internal CA.
[api]
site=https://zulip.example.com
cert_bundle=/home/bots/certs/example.com.ca-bundle
Save the server certificate (or the CA certificate) in its own file,
converting to PEM format first if necessary.
Verify that the certificate you have saved is the same as the one on the
server.
The `cert_bundle` option trusts the server / CA certificate only for
interaction with the zulip site, and is relatively secure.
Note that a certificate bundle is merely one or more certificates combined
into a single file.

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# zulip-send -- Sends a message to the specified recipients.

View File

@@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# Copyright © 2012-2014 Zulip, Inc.
@@ -21,6 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import sys
from os import path
import optparse
@@ -46,9 +47,9 @@ parser.add_option('--new-short-name')
client = zulip.init_from_options(options)
print client.create_user({
print(client.create_user({
'email': options.new_email,
'password': options.new_password,
'full_name': options.new_full_name,
'short_name': options.new_short_name
})
}))

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# Copyright © 2012 Zulip, Inc.
@@ -21,6 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import sys
import os
import optparse
@@ -53,4 +54,4 @@ if options.subject != "":
message_data["subject"] = options.subject
if options.content != "":
message_data["content"] = options.content
print client.update_message(message_data)
print(client.update_message(message_data))

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# Copyright © 2012 Zulip, Inc.
@@ -21,6 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import sys
import os
import optparse
@@ -43,4 +44,4 @@ parser.add_option_group(zulip.generate_option_group(parser))
client = zulip.init_from_options(options)
print client.get_streams(include_public=True, include_subscribed=False)
print(client.get_streams(include_public=True, include_subscribed=False))

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# Copyright © 2014 Zulip, Inc.
@@ -21,6 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import sys
import os
import optparse
@@ -42,4 +43,4 @@ parser.add_option_group(zulip.generate_option_group(parser))
client = zulip.init_from_options(options)
for user in client.get_members()["members"]:
print user["full_name"], user["email"]
print(user["full_name"], user["email"])

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# Copyright © 2012 Zulip, Inc.
@@ -21,6 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import sys
import os
import optparse
@@ -42,4 +43,4 @@ parser.add_option_group(zulip.generate_option_group(parser))
client = zulip.init_from_options(options)
print client.list_subscriptions()
print(client.list_subscriptions())

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# Copyright © 2012 Zulip, Inc.
@@ -21,6 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import sys
import os
import optparse
@@ -43,7 +44,7 @@ parser.add_option_group(zulip.generate_option_group(parser))
client = zulip.init_from_options(options)
def print_event(event):
print event
print(event)
# This is a blocking call, and will continuously poll for new events
# Note also the filter here is messages to the stream Denmark; if you

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# Copyright © 2012 Zulip, Inc.
@@ -21,6 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import sys
import os
import optparse
@@ -43,7 +44,7 @@ parser.add_option_group(zulip.generate_option_group(parser))
client = zulip.init_from_options(options)
def print_message(message):
print message
print(message)
# This is a blocking call, and will continuously poll for new messages
client.call_on_each_message(print_message)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# Copyright © 2012 Zulip, Inc.
@@ -21,6 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import sys
import os
import optparse
@@ -42,4 +43,4 @@ parser.add_option_group(zulip.generate_option_group(parser))
client = zulip.init_from_options(options)
print client.get_messages({})
print(client.get_messages({}))

61
api/examples/recent-messages Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# Copyright © 2012 Zulip, Inc.
#
# 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.
from __future__ import print_function
import sys
import os
import json
import optparse
usage = """recent-messages [options] --count=<no. of previous messages> --user=<sender's email address> --api-key=<sender's api key>
Prints out last count messages recieved by the indicated bot or user
Example: recent-messages --count=101 --user=username@example.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
"""
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import zulip
parser = optparse.OptionParser(usage=usage)
parser.add_option('--count', default=100)
parser.add_option_group(zulip.generate_option_group(parser))
(options, args) = parser.parse_args()
client = zulip.init_from_options(options)
req = {
'narrow': [["stream", "Denmark"]],
'num_before': options.count,
'num_after': 0,
'anchor': 1000000000,
'apply_markdown': False
}
old_messages = client.do_api_query(req, zulip.API_VERSTRING + 'messages', method='GET')
if 'messages' in old_messages:
for message in old_messages['messages']:
print(json.dumps(message, indent=4))
else:
print([])

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# Copyright © 2012 Zulip, Inc.
@@ -21,6 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import sys
import os
import optparse
@@ -54,4 +55,4 @@ message_data = {
"subject": options.subject,
"to": args,
}
print client.send_message(message_data)
print(client.send_message(message_data))

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# Copyright © 2012 Zulip, Inc.
@@ -21,6 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import sys
import os
import optparse
@@ -45,8 +46,8 @@ parser.add_option('--streams', default='')
client = zulip.init_from_options(options)
if options.streams == "":
print >>sys.stderr, "Usage:", parser.usage
print("Usage:", parser.usage, file=sys.stderr)
sys.exit(1)
print client.add_subscriptions([{"name": stream_name} for stream_name in
options.streams.split()])
print(client.add_subscriptions([{"name": stream_name} for stream_name in
options.streams.split()]))

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
# Copyright © 2012 Zulip, Inc.
@@ -21,6 +21,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import sys
import os
import optparse
@@ -45,7 +46,7 @@ parser.add_option('--streams', default='')
client = zulip.init_from_options(options)
if options.streams == "":
print >>sys.stderr, "Usage:", parser.usage
print("Usage:", parser.usage, file=sys.stderr)
sys.exit(1)
print client.remove_subscriptions(options.streams.split())
print(client.remove_subscriptions(options.streams.split()))

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Copyright © 2014 Zulip, Inc.

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Asana integration for Zulip
@@ -30,6 +30,7 @@
#
# python-dateutil is a dependency for this script.
from __future__ import print_function
import base64
from datetime import datetime, timedelta
@@ -37,16 +38,16 @@ import json
import logging
import os
import time
import urllib2
from six.moves import urllib
import sys
try:
import dateutil.parser
import dateutil.tz
except ImportError, e:
print >>sys.stderr, e
print >>sys.stderr, "Please install the python-dateutil package."
except ImportError as e:
print(e, file=sys.stderr)
print("Please install the python-dateutil package.", file=sys.stderr)
exit(1)
sys.path.insert(0, os.path.dirname(__file__))
@@ -74,8 +75,8 @@ def fetch_from_asana(path):
headers = {"Authorization": "Basic %s" % auth}
url = "https://app.asana.com/api/1.0" + path
request = urllib2.Request(url, None, headers)
result = urllib2.urlopen(request)
request = urllib.request.Request(url, None, headers)
result = urllib.request.urlopen(request)
return json.load(result)
@@ -189,7 +190,7 @@ def since():
timestamp = float(datestring)
max_timestamp_processed = datetime.fromtimestamp(timestamp)
logging.info("Reading from resume file: " + datestring)
except (ValueError,IOError) as e:
except (ValueError, IOError) as e:
logging.warn("Could not open resume file: %s" % (
e.message or e.strerror,))
max_timestamp_processed = default_since()

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Copyright © 2014 Zulip, Inc.

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Zulip mirror of Basecamp activity
@@ -26,6 +26,7 @@
# or preferably on a server.
# You may need to install the python-requests library.
from __future__ import absolute_import
import requests
import logging
import time
@@ -33,7 +34,8 @@ import re
import sys
import os
from datetime import datetime, timedelta
from HTMLParser import HTMLParser
from six.moves.html_parser import HTMLParser
import six
sys.path.insert(0, os.path.dirname(__file__))
import zulip_basecamp_config as config
@@ -49,7 +51,7 @@ client = zulip.Client(
site=config.ZULIP_SITE,
api_key=config.ZULIP_API_KEY,
client="ZulipBasecamp/" + VERSION)
user_agent = "Basecamp To Zulip Mirroring script (support@zulip.com)"
user_agent = "Basecamp To Zulip Mirroring script (zulip-devel@googlegroups.com)"
htmlParser = HTMLParser()
# find some form of JSON loader/dumper, with a preference order for speed.
@@ -80,7 +82,7 @@ def check_permissions():
# builds the message dict for sending a message with the Zulip API
def build_message(event):
if not (event.has_key('bucket') and event.has_key('creator') and event.has_key('html_url')):
if not ('bucket' in event and 'creator' in event and 'html_url' in event):
logging.error("Perhaps the Basecamp API changed behavior? "
"This event doesn't have the expected format:\n%s" %(event,))
return None
@@ -92,7 +94,7 @@ def build_message(event):
action = htmlParser.unescape(re.sub(r"<[^<>]+>", "", event.get('action', '')))
target = htmlParser.unescape(event.get('target', ''))
# Some events have "excerpts", which we blockquote
excerpt = htmlParser.unescape(event.get('excerpt',''))
excerpt = htmlParser.unescape(event.get('excerpt', ''))
if excerpt.strip() == "":
message = '**%s** %s [%s](%s).' % (event['creator']['name'], action, target, event['html_url'])
else:
@@ -116,13 +118,13 @@ def run_mirror():
since = re.search(r"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}-\d{2}:\d{2}", since)
assert since, "resume file does not meet expected format"
since = since.string
except (AssertionError,IOError) as e:
except (AssertionError, IOError) as e:
logging.warn("Could not open resume file: %s" % (e.message or e.strerror,))
since = (datetime.utcnow() - timedelta(hours=config.BASECAMP_INITIAL_HISTORY_HOURS)).isoformat() + "-00:00"
try:
# we use an exponential backoff approach when we get 429 (Too Many Requests).
sleepInterval = 1
while 1:
while True:
time.sleep(sleepInterval)
response = requests.get("https://basecamp.com/%s/api/v1/events.json" % (config.BASECAMP_ACCOUNT_ID),
params={'since': since},
@@ -170,7 +172,7 @@ def run_mirror():
if __name__ == "__main__":
if not isinstance(config.RESUME_FILE, basestring):
if not isinstance(config.RESUME_FILE, six.string_types):
sys.stderr("RESUME_FILE path not given; refusing to continue")
check_permissions()
if config.LOG_FILE:

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Copyright © 2014 Zulip, Inc.

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Zulip mirror of Codebase HQ activity
@@ -29,6 +29,8 @@
#
# python-dateutil is a dependency for this script.
from __future__ import print_function
from __future__ import absolute_import
import requests
import logging
import time
@@ -36,13 +38,14 @@ import sys
import os
from datetime import datetime, timedelta
import six
try:
import dateutil.parser
except ImportError, e:
print >>sys.stderr, e
print >>sys.stderr, "Please install the python-dateutil package."
except ImportError as e:
print(e, file=sys.stderr)
print("Please install the python-dateutil package.", file=sys.stderr)
exit(1)
sys.path.insert(0, os.path.dirname(__file__))
@@ -58,7 +61,7 @@ client = zulip.Client(
site=config.ZULIP_SITE,
api_key=config.ZULIP_API_KEY,
client="ZulipCodebase/" + VERSION)
user_agent = "Codebase To Zulip Mirroring script (support@zulip.com)"
user_agent = "Codebase To Zulip Mirroring script (zulip-devel@googlegroups.com)"
# find some form of JSON loader/dumper, with a preference order for speed.
json_implementations = ['ujson', 'cjson', 'simplejson', 'json']
@@ -110,7 +113,7 @@ def handle_event(event):
project_name = raw_props.get('name')
project_repo_type = raw_props.get('scm_type')
url = make_url("projects/%s" % project_link)
url = make_url("projects/%s" % (project_link,))
scm = "of type %s" % (project_repo_type,) if project_repo_type else ""
@@ -271,13 +274,13 @@ def run_mirror():
else:
timestamp = int(timestamp, 10)
since = datetime.fromtimestamp(timestamp)
except (ValueError,IOError) as e:
except (ValueError, IOError) as e:
logging.warn("Could not open resume file: %s" % (e.message or e.strerror,))
since = default_since()
try:
sleepInterval = 1
while 1:
while True:
events = make_api_call("activity")[::-1]
if events is not None:
sleepInterval = 1
@@ -314,7 +317,7 @@ def check_permissions():
sys.stderr(e)
if __name__ == "__main__":
if not isinstance(config.RESUME_FILE, basestring):
if not isinstance(config.RESUME_FILE, six.string_types):
sys.stderr("RESUME_FILE path not given; refusing to continue")
check_permissions()
if config.LOG_FILE:

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Zulip notification post-receive hook.
@@ -29,13 +29,14 @@
# For example:
# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
from __future__ import absolute_import
import os
import sys
import subprocess
import os.path
sys.path.insert(0, os.path.dirname(__file__))
import zulip_git_config as config
from . import zulip_git_config as config
VERSION = "0.9"
if config.ZULIP_API_PATH is not None:

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Copyright © 2014 Zulip, Inc.

View File

@@ -1,8 +1,8 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Zulip hook for Mercurial changeset pushes.
# Copyright © 2012-2014 Zulip, Inc.
# Copyright © 2012-2014 Zulip, Inc.
#
# 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,8 +25,10 @@
#
# This hook is called when changesets are pushed to the master repository (ie
# `hg push`). See https://zulip.com/integrations for installation instructions.
from __future__ import absolute_import
import zulip
from six.moves import range
VERSION = "0.9"

View File

@@ -67,7 +67,7 @@ class ZulipListener extends AbstractIssueEventListener {
author, issueUrlMd, comment)
break
case ISSUE_CREATED_ID:
content = String.format("%s **created** %s priority %s, assigned to **%s**: \n\n> %s",
content = String.format("%s **created** %s priority %s, assigned to @**%s**: \n\n> %s",
author, issueUrlMd, event.issue.priorityObject.name,
assignee, title)
break

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
import optparse
import zulip

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Copyright © 2012-2014 Zulip, Inc.
@@ -33,6 +33,7 @@ For example:
1234 //depot/security/src/
'''
from __future__ import print_function
import os
import sys
@@ -59,12 +60,12 @@ try:
changelist = int(sys.argv[1])
changeroot = sys.argv[2]
except IndexError:
print >> sys.stderr, "Wrong number of arguments.\n\n",
print >> sys.stderr, __doc__
print("Wrong number of arguments.\n\n", end=' ', file=sys.stderr)
print(__doc__, file=sys.stderr)
sys.exit(-1)
except ValueError:
print >> sys.stderr, "First argument must be an integer.\n\n",
print >> sys.stderr, __doc__
print("First argument must be an integer.\n\n", end=' ', file=sys.stderr)
print(__doc__, file=sys.stderr)
sys.exit(-1)
metadata = git_p4.p4_describe(changelist)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Copyright © 2014 Zulip, Inc.

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# RSS integration for Zulip
@@ -23,16 +23,17 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import calendar
import errno
import hashlib
from HTMLParser import HTMLParser
from six.moves.html_parser import HTMLParser
import logging
import optparse
import os
import sys
import time
import urlparse
from six.moves import urllib
import feedparser
import zulip
@@ -87,7 +88,7 @@ def mkdir_p(path):
# Python doesn't have an analog to `mkdir -p` < Python 3.2.
try:
os.makedirs(path)
except OSError, e:
except OSError as e:
if e.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
@@ -97,7 +98,7 @@ try:
mkdir_p(opts.data_dir)
except OSError:
# We can't write to the logfile, so just print and give up.
print >>sys.stderr, "Unable to store RSS data at %s." % (opts.data_dir,)
print("Unable to store RSS data at %s." % (opts.data_dir,), file=sys.stderr)
exit(1)
log_file = os.path.join(opts.data_dir, "rss-bot.log")
@@ -169,7 +170,7 @@ client = zulip.Client(email=opts.email, api_key=opts.api_key,
first_message = True
for feed_url in feed_urls:
feed_file = os.path.join(opts.data_dir, urlparse.urlparse(feed_url).netloc)
feed_file = os.path.join(opts.data_dir, urllib.parse.urlparse(feed_url).netloc)
try:
with open(feed_file, "r") as f:

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Zulip notification post-commit hook.

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Copyright © 2014 Zulip, Inc.

View File

@@ -107,8 +107,8 @@ class ZulipPlugin(Component):
field_changes = []
for key in old_values.keys():
if key == "description":
content += '- Changed %s from %s to %s' % (key, markdown_block(old_values.get(key)),
markdown_block(ticket.values.get(key)))
content += '- Changed %s from %s\n\nto %s' % (key, markdown_block(old_values.get(key)),
markdown_block(ticket.values.get(key)))
elif old_values.get(key) == "":
field_changes.append('%s: => **%s**' % (key, ticket.values.get(key)))
elif ticket.values.get(key) == "":

View File

@@ -34,13 +34,13 @@ TRAC_BASE_TICKET_URL = "https://trac.example.com/ticket"
# and annoying. We solve this issue by only sending a notification
# for changes to the fields listed below.
#
# Total list of possible fields is:
# TRAC_NOTIFY_FIELDS lets you specify which fields will trigger a
# Zulip notification in response to a trac update; you should change
# this list to match your team's workflow. The complete list of
# possible fields is:
#
# (priority, milestone, cc, owner, keywords, component, severity,
# type, versions, description, resolution, summary, comment)
#
# The following is the list of fields which can be changed without
# triggering a Zulip notification; change these to match your team's
# workflow.
TRAC_NOTIFY_FIELDS = ["description", "summary", "resolution", "comment", "owner"]
## If properly installed, the Zulip API should be in your import

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Twitter integration for Zulip
@@ -23,10 +23,11 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import os
import sys
import optparse
import ConfigParser
import six.moves.configparser
import zulip
VERSION = "0.9"
@@ -85,14 +86,14 @@ if not options.twitter_id:
parser.error('You must specify --twitter-id')
try:
config = ConfigParser.ConfigParser()
config = six.moves.configparser.ConfigParser()
config.read(CONFIGFILE)
consumer_key = config.get('twitter', 'consumer_key')
consumer_secret = config.get('twitter', 'consumer_secret')
access_token_key = config.get('twitter', 'access_token_key')
access_token_secret = config.get('twitter', 'access_token_secret')
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
except (six.moves.configparser.NoSectionError, six.moves.configparser.NoOptionError):
parser.error("Please provide a ~/.zulip_twitterrc")
if not consumer_key or not consumer_secret or not access_token_key or not access_token_secret:
@@ -112,17 +113,17 @@ api = twitter.Api(consumer_key=consumer_key,
user = api.VerifyCredentials()
if not user.GetId():
print "Unable to log in to twitter with supplied credentials. Please double-check and try again"
print("Unable to log in to twitter with supplied credentials. Please double-check and try again")
sys.exit()
try:
since_id = config.getint('twitter', 'since_id')
except ConfigParser.NoOptionError:
except six.moves.configparser.NoOptionError:
since_id = -1
try:
user_id = config.get('twitter', 'user_id')
except ConfigParser.NoOptionError:
except six.moves.configparser.NoOptionError:
user_id = options.twitter_id
client = zulip.Client(
@@ -154,7 +155,7 @@ for status in statuses[::-1][:options.limit_tweets]:
if ret['result'] == 'error':
# If sending failed (e.g. no such stream), abort and retry next time
print "Error sending message to zulip: %s" % ret['msg']
print("Error sending message to zulip: %s" % ret['msg'])
break
else:
since_id = status.GetId()

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
#
# Twitter search integration for Zulip
@@ -23,10 +23,11 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
import os
import sys
import optparse
import ConfigParser
import six.moves.configparser
import zulip
VERSION = "0.9"
@@ -107,14 +108,14 @@ if not opts.search_terms:
parser.error('You must specify a search term.')
try:
config = ConfigParser.ConfigParser()
config = six.moves.configparser.ConfigParser()
config.read(CONFIGFILE)
consumer_key = config.get('twitter', 'consumer_key')
consumer_secret = config.get('twitter', 'consumer_secret')
access_token_key = config.get('twitter', 'access_token_key')
access_token_secret = config.get('twitter', 'access_token_secret')
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
except (six.moves.configparser.NoSectionError, six.moves.configparser.NoOptionError):
parser.error("Please provide a ~/.zulip_twitterrc")
if not (consumer_key and consumer_secret and access_token_key and access_token_secret):
@@ -122,7 +123,7 @@ if not (consumer_key and consumer_secret and access_token_key and access_token_s
try:
since_id = config.getint('search', 'since_id')
except (ConfigParser.NoOptionError, ConfigParser.NoSectionError):
except (six.moves.configparser.NoOptionError, six.moves.configparser.NoSectionError):
since_id = 0
try:
@@ -138,8 +139,8 @@ api = twitter.Api(consumer_key=consumer_key,
user = api.VerifyCredentials()
if not user.GetId():
print "Unable to log in to Twitter with supplied credentials.\
Please double-check and try again."
print("Unable to log in to Twitter with supplied credentials.\
Please double-check and try again.")
sys.exit()
client = zulip.Client(
@@ -182,7 +183,7 @@ for status in statuses[::-1][:opts.limit_tweets]:
if ret['result'] == 'error':
# If sending failed (e.g. no such stream), abort and retry next time
print "Error sending message to zulip: %s" % ret['msg']
print("Error sending message to zulip: %s" % ret['msg'])
break
else:
since_id = status.GetId()

View File

@@ -1,6 +1,9 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
from __future__ import print_function
from typing import Any, Generator, List, Tuple
import os
import sys
@@ -9,12 +12,13 @@ import itertools
def version():
version_py = os.path.join(os.path.dirname(__file__), "zulip", "__init__.py")
with open(version_py) as in_handle:
version_line = itertools.dropwhile(lambda x: not x.startswith("__version__"),
in_handle).next()
version_line = next(itertools.dropwhile(lambda x: not x.startswith("__version__"),
in_handle))
version = version_line.split('=')[-1].strip().replace('"', '')
return version
def recur_expand(target_root, dir):
# type: (Any, Any) -> Generator[Tuple[str, List[str]], None, None]
for root, _, files in os.walk(dir):
paths = [os.path.join(root, f) for f in files]
if len(paths):
@@ -26,7 +30,7 @@ package_info = dict(
version=version(),
description='Bindings for the Zulip message API',
author='Zulip, Inc.',
author_email='support@zulip.com',
author_email='zulip-devel@googlegroups.com',
classifiers=[
'Development Status :: 3 - Alpha',
'Environment :: Web Environment',
@@ -39,7 +43,7 @@ package_info = dict(
data_files=[('share/zulip/examples', ["examples/zuliprc", "examples/send-message", "examples/subscribe",
"examples/get-public-streams", "examples/unsubscribe",
"examples/list-members", "examples/list-subscriptions",
"examples/print-messages"])] + \
"examples/print-messages", "examples/recent-messages"])] + \
list(recur_expand('share/zulip', 'integrations/')),
scripts=["bin/zulip-send"],
)
@@ -47,6 +51,8 @@ package_info = dict(
setuptools_info = dict(
install_requires=['requests>=0.12.1',
'simplejson',
'six',
'typing',
],
)
@@ -60,13 +66,13 @@ except ImportError:
try:
import simplejson
except ImportError:
print >>sys.stderr, "simplejson is not installed"
print("simplejson is not installed", file=sys.stderr)
sys.exit(1)
try:
import requests
assert(LooseVersion(requests.__version__) >= LooseVersion('0.12.1'))
assert(LooseVersion(requests.__version__) >= LooseVersion('0.12.1')) # type: ignore # https://github.com/JukkaL/mypy/issues/1165
except (ImportError, AssertionError):
print >>sys.stderr, "requests >=0.12.1 is not installed"
print("requests >=0.12.1 is not installed", file=sys.stderr)
sys.exit(1)

View File

@@ -20,24 +20,27 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
import simplejson
import requests
import time
import traceback
import urlparse
import sys
import os
import optparse
import platform
import urllib
import random
from distutils.version import LooseVersion
from ConfigParser import SafeConfigParser
from six.moves.configparser import SafeConfigParser
from six.moves import urllib
import logging
import six
__version__ = "0.2.4"
__version__ = "0.2.5"
logger = logging.getLogger(__name__)
@@ -87,7 +90,7 @@ class RandomExponentialBackoff(CountingBackoff):
try:
logger.warning(message)
except NameError:
print message
print(message)
time.sleep(delay)
def _default_client():
@@ -117,6 +120,19 @@ def generate_option_group(parser, prefix=''):
default=None,
dest="zulip_client",
help=optparse.SUPPRESS_HELP)
group.add_option('--insecure',
action='store_true',
dest='insecure',
help='''Do not verify the server certificate.
The https connection will not be secure.''')
group.add_option('--cert-bundle',
action='store',
dest='cert_bundle',
help='''Specify a file containing either the
server certificate, or a set of trusted
CA certificates. This will be used to
verify the server's identity. All
certificates should be PEM encoded.''')
return group
def init_from_options(options, client=None):
@@ -126,7 +142,8 @@ def init_from_options(options, client=None):
client = _default_client()
return Client(email=options.zulip_email, api_key=options.zulip_api_key,
config_file=options.zulip_config_file, verbose=options.verbose,
site=options.zulip_site, client=client)
site=options.zulip_site, client=client,
cert_bundle=options.cert_bundle, insecure=options.insecure)
def get_default_config_filename():
config_file = os.path.join(os.environ["HOME"], ".zuliprc")
@@ -138,17 +155,16 @@ def get_default_config_filename():
class Client(object):
def __init__(self, email=None, api_key=None, config_file=None,
verbose=False, retry_on_errors=True,
site=None, client=None):
site=None, client=None,
cert_bundle=None, insecure=None):
if client is None:
client = _default_client()
if None in (api_key, email):
if config_file is None:
config_file = get_default_config_filename()
if not os.path.exists(config_file):
raise RuntimeError("api_key or email not specified and %s does not exist"
% (config_file,))
if config_file is None:
config_file = get_default_config_filename()
if os.path.exists(config_file):
config = SafeConfigParser()
with file(config_file, 'r') as f:
with open(config_file, 'r') as f:
config.readfp(f, config_file)
if api_key is None:
api_key = config.get("api", "key")
@@ -156,6 +172,22 @@ class Client(object):
email = config.get("api", "email")
if site is None and config.has_option("api", "site"):
site = config.get("api", "site")
if cert_bundle is None and config.has_option("api", "cert_bundle"):
cert_bundle = config.get("api", "cert_bundle")
if insecure is None and config.has_option("api", "insecure"):
# Be quite strict about what is accepted so that users don't
# disable security unintentionally.
insecure_setting = config.get("api", "insecure").lower()
if insecure_setting == "true":
insecure = True
elif insecure_setting == "false":
insecure = False
else:
raise RuntimeError("insecure is set to '%s', it must be 'true' or 'false' if it is used in %s"
% (insecure_setting, config_file))
elif None in (api_key, email):
raise RuntimeError("api_key or email not specified and %s does not exist"
% (config_file,))
self.api_key = api_key
self.email = email
@@ -175,6 +207,17 @@ class Client(object):
self.retry_on_errors = retry_on_errors
self.client_name = client
if insecure:
self.tls_verification=False
elif cert_bundle is not None:
if not os.path.isfile(cert_bundle):
raise RuntimeError("tls bundle '%s' does not exist"
%(cert_bundle,))
self.tls_verification=cert_bundle
else:
# Default behavior: verify against system CA certificates
self.tls_verification=True
def get_user_agent(self):
vendor = ''
vendor_version = ''
@@ -202,8 +245,8 @@ class Client(object):
def do_api_query(self, orig_request, url, method="POST", longpolling = False):
request = {}
for (key, val) in orig_request.iteritems():
if not (isinstance(val, str) or isinstance(val, unicode)):
for (key, val) in six.iteritems(orig_request):
if not (isinstance(val, str) or isinstance(val, six.text_type)):
request[key] = simplejson.dumps(val)
else:
request[key] = val
@@ -233,9 +276,9 @@ class Client(object):
def end_error_retry(succeeded):
if query_state["had_error_retry"] and self.verbose:
if succeeded:
print "Success!"
print("Success!")
else:
print "Failed!"
print("Failed!")
while True:
try:
@@ -246,10 +289,10 @@ class Client(object):
kwargs = {kwarg: query_state["request"]}
res = requests.request(
method,
urlparse.urljoin(self.base_url, url),
urllib.parse.urljoin(self.base_url, url),
auth=requests.auth.HTTPBasicAuth(self.email,
self.api_key),
verify=True, timeout=90,
verify=self.tls_verification, timeout=90,
headers={"User-agent": self.get_user_agent()},
**kwargs)
@@ -311,7 +354,7 @@ class Client(object):
else:
req_url = url
return self.do_api_query(request, API_VERSTRING + req_url, method=method, **query_kwargs)
call.func_name = name
call.__name__ = name
setattr(cls, name, call)
def call_on_each_event(self, callback, event_types=None, narrow=[]):
@@ -324,7 +367,7 @@ class Client(object):
if 'error' in res.get('result'):
if self.verbose:
print "Server returned error:\n%s" % res['msg']
print("Server returned error:\n%s" % res['msg'])
time.sleep(1)
else:
return (res['queue_id'], res['last_event_id'])
@@ -338,13 +381,13 @@ class Client(object):
if 'error' in res.get('result'):
if res["result"] == "http-error":
if self.verbose:
print "HTTP error fetching events -- probably a server restart"
print("HTTP error fetching events -- probably a server restart")
elif res["result"] == "connection-error":
if self.verbose:
print "Connection error fetching events -- probably server is temporarily down?"
print("Connection error fetching events -- probably server is temporarily down?")
else:
if self.verbose:
print "Server returned error:\n%s" % res["msg"]
print("Server returned error:\n%s" % res["msg"])
if res["msg"].startswith("Bad event queue id:"):
# Our event queue went away, probably because
# we were asleep or the server restarted
@@ -425,7 +468,7 @@ Client._register('list_subscriptions', method='GET', url='users/me/subscriptions
Client._register('add_subscriptions', url='users/me/subscriptions', make_request=_mk_subs)
Client._register('remove_subscriptions', method='PATCH', url='users/me/subscriptions', make_request=_mk_rm_subs)
Client._register('get_subscribers', method='GET',
computed_url=lambda request: 'streams/%s/members' % (urllib.quote(request['stream'], safe=''),),
computed_url=lambda request: 'streams/%s/members' % (urllib.parse.quote(request['stream'], safe=''),),
make_request=_kwargs_to_dict)
Client._register('render_message', method='GET', url='messages/render')
Client._register('create_user', method='POST', url='users')

View File

@@ -1,6 +1,8 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
from __future__ import absolute_import
import xml.etree.ElementTree as ET
import subprocess
from six.moves import range
# Generates the favicon images containing unread message counts.
@@ -10,7 +12,7 @@ elems = [tree.getroot().findall(
".//*[@id='%s']/{http://www.w3.org/2000/svg}tspan" % (name,))[0]
for name in ('number_back', 'number_front')]
for i in xrange(1,100):
for i in range(1, 100):
# Prepare a modified SVG
s = '%2d' % (i,)
for e in elems:

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
from __future__ import absolute_import
from __future__ import print_function
import os
import sys
@@ -8,4 +9,4 @@ sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
os.environ['DJANGO_SETTINGS_MODULE'] = 'zproject.settings'
from django.conf import settings
print getattr(settings, sys.argv[1])
print(getattr(settings, sys.argv[1]))

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
import sys
import logging
import os

View File

@@ -1,4 +1,5 @@
#!/bin/bash -e
#!/usr/bin/env bash
set -e
queue=$1
@@ -11,5 +12,5 @@ ZULIP_DIR=/home/zulip/deployments/current
STATE_DIR=/var/lib/nagios_state
STATE_FILE=$STATE_DIR/check-rabbitmq-consumers-$queue
$ZULIP_DIR/bots/check-rabbitmq-consumers --queue=$queue &> ${STATE_FILE}-tmp;
mv ${STATE_FILE}-tmp $STATE_FILE
"$ZULIP_DIR/bots/check-rabbitmq-consumers" "--queue=$queue" &> "${STATE_FILE}-tmp";
mv "${STATE_FILE}-tmp" "$STATE_FILE"

View File

@@ -1,4 +1,6 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
from __future__ import print_function
from __future__ import absolute_import
import sys
import time
import optparse
@@ -7,6 +9,7 @@ import random
import logging
import subprocess
import hashlib
from six.moves import range
parser = optparse.OptionParser()
parser.add_option('--verbose',
@@ -100,7 +103,7 @@ def print_status_and_exit(status):
# e.g. true success and punting due to a SERVNAK, result in a
# non-alert case, so to give us something unambiguous to check in
# Nagios, print the exit status.
print status
print(status)
sys.exit(status)
def send_zulip(message):
@@ -149,7 +152,7 @@ for (stream, test) in test_streams:
zephyr_subs_to_add.append((stream, '*', '*'))
actually_subscribed = False
for tries in xrange(10):
for tries in range(10):
try:
zephyr.init()
zephyr._z.subAll(zephyr_subs_to_add)
@@ -163,7 +166,7 @@ for tries in xrange(10):
if missing == 0:
actually_subscribed = True
break
except IOError, e:
except IOError as e:
if "SERVNAK received" in e:
logger.error("SERVNAK repeatedly received, punting rest of test")
else:
@@ -276,7 +279,7 @@ logger.info("Finished receiving Zulip messages!")
receive_zephyrs()
logger.info("Finished receiving Zephyr messages!")
all_keys = set(zhkeys.keys() + hzkeys.keys())
all_keys = set(list(zhkeys.keys()) + list(hzkeys.keys()))
def process_keys(content_list):
# Start by filtering out any keys that might have come from
# concurrent check-mirroring processes

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
from __future__ import print_function
import sys
import time
import optparse
@@ -15,7 +16,7 @@ states = {
}
if 'USER' in os.environ and not os.environ['USER'] in ['root', 'rabbitmq']:
print "This script must be run as the root or rabbitmq user"
print("This script must be run as the root or rabbitmq user")
usage = """Usage: check-rabbitmq-consumers --queue=[queue-name] --min-threshold=[min-threshold]"""

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
from __future__ import print_function
import sys
import re
import time
@@ -30,7 +31,7 @@ max_count = 0
warn_queues = []
if 'USER' in os.environ and not os.environ['USER'] in ['root', 'rabbitmq']:
print "This script must be run as the root or rabbitmq user"
print("This script must be run as the root or rabbitmq user")
for line in output.split("\n"):
line = line.strip()

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
import time
def nagios_from_file(results_file):
@@ -10,7 +10,7 @@ def nagios_from_file(results_file):
This file is created by various nagios checking cron jobs such as
check-rabbitmq-queues and check-rabbitmq-consumers"""
data = file(results_file).read().strip()
data = open(results_file).read().strip()
pieces = data.split('|')
if not len(pieces) == 4:

View File

@@ -1,9 +1,10 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
from __future__ import print_function
import sys
import time
import datetime
import optparse
import urlparse
from six.moves import urllib
import itertools
import traceback
import os
@@ -56,13 +57,13 @@ except ImportError:
parser.error('Install python-gdata')
def get_calendar_url():
parts = urlparse.urlparse(options.calendar)
parts = urllib.parse.urlparse(options.calendar)
pat = os.path.split(parts.path)
if pat[1] != 'basic':
parser.error('The --calendar URL should be the XML "Private Address" ' +
'from your calendar settings')
return urlparse.urlunparse((parts.scheme, parts.netloc, pat[0] + '/full',
'', 'futureevents=true&orderby=startdate', ''))
return urllib.parse.urlunparse((parts.scheme, parts.netloc, pat[0] + '/full',
'', 'futureevents=true&orderby=startdate', ''))
calendar_url = get_calendar_url()
@@ -99,7 +100,7 @@ def send_reminders():
key = (uid, start)
if key not in sent:
line = '%s starts at %s' % (title, start.strftime('%H:%M'))
print 'Sending reminder:', line
print('Sending reminder:', line)
messages.append(line)
keys.add(key)

View File

@@ -1,4 +1,4 @@
#! /usr/bin/env python
#! /usr/bin/env python2.7
#
# EXPERIMENTAL
# IRC <=> Zulip mirroring bot
@@ -6,6 +6,7 @@
# Setup: First, you need to install python-irc version 8.5.3
# (https://bitbucket.org/jaraco/irc)
from __future__ import print_function
import irc.bot
import irc.strings
from irc.client import ip_numstr_to_quad, ip_quad_to_numstr
@@ -53,12 +54,12 @@ class IRCBot(irc.bot.SingleServerIRCBot):
return
# Forward the PM to Zulip
print zulip_client.send_message({
print(zulip_client.send_message({
"sender": sender,
"type": "private",
"to": "username@example.com",
"content": content,
})
}))
def on_pubmsg(self, c, e):
content = e.arguments[0]
@@ -68,14 +69,14 @@ class IRCBot(irc.bot.SingleServerIRCBot):
return
# Forward the stream message to Zulip
print zulip_client.send_message({
print(zulip_client.send_message({
"forged": "yes",
"sender": sender,
"type": "stream",
"to": stream,
"subject": "IRC",
"content": content,
})
}))
def on_dccmsg(self, c, e):
c.privmsg("You said: " + e.arguments[0])
@@ -92,11 +93,11 @@ class IRCBot(irc.bot.SingleServerIRCBot):
return
self.dcc_connect(address, port)
usage = """python irc-mirror.py --server=IRC_SERVER --channel=<CHANNEL> --nick-prefix=<NICK> [optional args]
usage = """python2.7 irc-mirror.py --server=IRC_SERVER --channel=<CHANNEL> --nick-prefix=<NICK> [optional args]
Example:
python irc-mirror.py --irc-server=127.0.0.1 --channel='#test' --nick-prefix=username
python2.7 irc-mirror.py --irc-server=127.0.0.1 --channel='#test' --nick-prefix=username
--site=https://zulip.example.com --user=irc-bot@example.com
--api-key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# Copyright (C) 2014 Zulip, Inc.
#
# Permission is hereby granted, free of charge, to any person
@@ -21,6 +21,7 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from __future__ import print_function
import sys
import subprocess
import os
@@ -39,7 +40,7 @@ args.extend(sys.argv[1:])
backoff = RandomExponentialBackoff(timeout_success_equivalent=300)
while backoff.keep_going():
print "Starting Jabber mirroring bot"
print("Starting Jabber mirroring bot")
try:
ret = subprocess.call(args)
except:
@@ -51,9 +52,9 @@ while backoff.keep_going():
backoff.fail()
print ""
print ""
print "ERROR: The Jabber mirroring bot is unable to continue mirroring Jabber."
print "Please contact support@zulip.com if you need assistence."
print ""
print("")
print("")
print("ERROR: The Jabber mirroring bot is unable to continue mirroring Jabber.")
print("Please contact zulip-devel@googlegroups.com if you need assistance.")
print("")
sys.exit(1)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python2.7
#
# Copyright (C) 2013 Permabit, Inc.
# Copyright (C) 2013--2014 Zulip, Inc.
@@ -37,6 +37,7 @@
# | other sender| x | | |
# public mode +-------------+-----+----+--------+----
# | self sender | | | |
from typing import Set
import logging
import threading
@@ -44,7 +45,7 @@ import optparse
from sleekxmpp import ClientXMPP, InvalidJID, JID
from sleekxmpp.exceptions import IqError, IqTimeout
from ConfigParser import SafeConfigParser
from six.moves.configparser import SafeConfigParser
import os, sys, zulip, getpass
import re
@@ -78,11 +79,11 @@ class JabberToZulipBot(ClientXMPP):
self.nick = jid.username
jid.resource = "zulip"
ClientXMPP.__init__(self, jid, password)
self.rooms = set()
self.rooms = set() # type: Set[str]
self.rooms_to_join = rooms
self.add_event_handler("session_start", self.session_start)
self.add_event_handler("message", self.message)
self.zulip = None
self.zulip = None # type: zulip.Client
self.use_ipv6 = False
self.register_plugin('xep_0045') # Jabber chatrooms
@@ -195,7 +196,7 @@ class JabberToZulipBot(ClientXMPP):
class ZulipToJabberBot(object):
def __init__(self, zulip_client):
self.client = zulip_client
self.jabber = None
self.jabber = None # type: JabberToZulipBot
def set_jabber_client(self, client):
self.jabber = client
@@ -376,7 +377,7 @@ option does not affect login credentials.'''.replace("\n", " "))
config = SafeConfigParser()
try:
with file(config_file, 'r') as f:
with open(config_file, 'r') as f:
config.readfp(f, config_file)
except IOError:
pass

View File

@@ -1,4 +1,5 @@
#!/usr/bin/python
#!/usr/bin/env python2.7
from __future__ import print_function
import subprocess
import os
import sys
@@ -20,7 +21,7 @@ def mkdir_p(path):
# Python doesn't have an analog to `mkdir -p` < Python 3.2.
try:
os.makedirs(path)
except OSError, e:
except OSError as e:
if e.errno == errno.EEXIST and os.path.isdir(path):
pass
else:
@@ -55,14 +56,14 @@ def process_logs():
data_file_path = "/var/tmp/log2zulip.state"
mkdir_p(os.path.dirname(data_file_path))
if not os.path.exists(data_file_path):
file(data_file_path, "w").write("{}")
last_data = ujson.loads(file(data_file_path).read())
open(data_file_path, "w").write("{}")
last_data = ujson.loads(open(data_file_path).read())
new_data = {}
for log_file in log_files:
file_data = last_data.get(log_file, {})
if not os.path.exists(log_file):
# If the file doesn't exist, log an error and then move on to the next file
print "Log file %s does not exist!" % (log_file,)
print("Log file does not exist or could not stat log file: %s" % (log_file,))
continue
length = int(subprocess.check_output(["wc", "-l", log_file]).split()[0])
if file_data.get("last") is None:
@@ -78,26 +79,26 @@ def process_logs():
process_lines(new_lines, filename)
file_data["last"] += len(new_lines)
new_data[log_file] = file_data
file(data_file_path, "w").write(ujson.dumps(new_data))
open(data_file_path, "w").write(ujson.dumps(new_data))
if __name__ == "__main__":
if os.path.exists(lock_path):
print "Log2zulip lock held; not doing anything"
print("Log2zulip lock held; not doing anything")
sys.exit(0)
try:
file(lock_path, "w").write("1")
open(lock_path, "w").write("1")
zulip_client = zulip.Client(config_file="/etc/log2zulip.zuliprc")
try:
log_files = ujson.loads(file(control_path, "r").read())
log_files = ujson.loads(open(control_path, "r").read())
except Exception:
print "Could not load control data from %s" % (control_path,)
print("Could not load control data from %s" % (control_path,))
traceback.print_exc()
sys.exit(1)
process_logs()
finally:
try:
os.remove(lock_path)
except OSError, IOError:
except OSError as IOError:
pass

View File

@@ -1,4 +1,4 @@
#!/usr/bin/python
#!/usr/bin/env python2.7
import sys
import subprocess
import base64
@@ -9,27 +9,27 @@ ccache_data_encoded = sys.argv[3]
# Update the Kerberos ticket cache file
program_name = "zmirror-%s" % (short_user,)
with file("/home/zulip/ccache/%s" % (program_name,), "w") as f:
with open("/home/zulip/ccache/%s" % (program_name,), "w") as f:
f.write(base64.b64decode(ccache_data_encoded))
# Setup API key
api_key_path = "/home/zulip/api-keys/%s" % (program_name,)
file(api_key_path, "w").write(api_key + "\n")
open(api_key_path, "w").write(api_key + "\n")
# Setup supervisord configuration
supervisor_path = "/etc/supervisor/conf.d/%s.conf" % (program_name,)
template = "/home/zulip/zulip/bots/zmirror_private.conf.template"
template_data = file(template).read()
template_data = open(template).read()
session_path = "/home/zulip/zephyr_sessions/%s" % (program_name,)
# Preserve mail zephyrs forwarding setting across rewriting the config file
try:
if "--forward-mail-zephyrs" in file(supervisor_path, "r").read():
if "--forward-mail-zephyrs" in open(supervisor_path, "r").read():
template_data = template_data.replace("--use-sessions", "--use-sessions --forward-mail-zephyrs")
except Exception:
pass
file(supervisor_path, "w").write(template_data.replace("USERNAME", short_user))
open(supervisor_path, "w").write(template_data.replace("USERNAME", short_user))
# Delete your session
subprocess.check_call(["rm", "-f", session_path])

View File

@@ -1,3 +1,5 @@
from __future__ import print_function
from typing import Any, Dict, List
# This is hacky code to analyze data on our support stream. The main
# reusable bits are get_recent_messages and get_words.
@@ -31,7 +33,7 @@ def analyze_messages(msgs, word_count, email_count):
if False:
if ' ack' in msg['content']:
name = msg['sender_full_name'].split()[0]
print 'ACK', name
print('ACK', name)
m = re.search('ticket (Z....).*email: (\S+).*~~~(.*)', msg['content'], re.M | re.S)
if m:
ticket, email, req = m.groups()
@@ -40,22 +42,22 @@ def analyze_messages(msgs, word_count, email_count):
word_count[word] += 1
email_count[email] += 1
if False:
print
print()
for k, v in msg.items():
print '%-20s: %s' % (k, v)
print('%-20s: %s' % (k, v))
def generate_support_stats():
client = zulip.Client()
narrow = 'stream:support'
count = 2000
msgs = get_recent_messages(client, narrow, count)
msgs_by_topic = collections.defaultdict(list)
msgs_by_topic = collections.defaultdict(list) # type: Dict[str, List[Dict[str, Any]]]
for msg in msgs:
topic = msg['subject']
msgs_by_topic[topic].append(msg)
word_count = collections.defaultdict(int)
email_count = collections.defaultdict(int)
word_count = collections.defaultdict(int) # type: Dict[str, int]
email_count = collections.defaultdict(int) # type: Dict[str, int]
if False:
for topic in msgs_by_topic:
@@ -63,17 +65,15 @@ def generate_support_stats():
analyze_messages(msgs, word_count, email_count)
if True:
words = word_count.keys()
words = filter(lambda w: word_count[w] >= 10, words)
words = filter(lambda w: len(w) >= 5, words)
words = [w for w in word_count.keys() if word_count[w] >= 10 and len(w) >= 5]
words = sorted(words, key=lambda w: word_count[w], reverse=True)
for word in words:
print word, word_count[word]
print(word, word_count[word])
if False:
emails = email_count.keys()
emails = sorted(emails, key=lambda w: email_count[w], reverse=True)
emails = sorted(list(email_count.keys()),
key=lambda w: email_count[w], reverse=True)
for email in emails:
print email, email_count[email]
print(email, email_count[email])
generate_support_stats()

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
import sys
import os
import logging
@@ -59,7 +59,7 @@ if __name__ == "__main__":
if public_streams is None:
continue
f = file("/home/zulip/public_streams.tmp", "w")
f = open("/home/zulip/public_streams.tmp", "w")
f.write(simplejson.dumps(list(public_streams)) + "\n")
f.close()

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# Copyright (C) 2012 Zulip, Inc.
#
# Permission is hereby granted, free of charge, to any person

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# Copyright (C) 2012 Zulip, Inc.
#
# Permission is hereby granted, free of charge, to any person
@@ -21,13 +21,15 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from __future__ import absolute_import
from __future__ import print_function
import sys
import subprocess
import os
import traceback
import signal
from zephyr_mirror_backend import parse_args
from .zephyr_mirror_backend import parse_args
def die(signal, frame):
# We actually want to exit, so run os._exit (so as not to be caught and restarted)
@@ -52,30 +54,30 @@ if options.forward_class_messages and not options.noshard:
if options.on_startup_command is not None:
subprocess.call([options.on_startup_command])
from zerver.lib.parallel import run_parallel
print "Starting parallel zephyr class mirroring bot"
print("Starting parallel zephyr class mirroring bot")
jobs = list("0123456789abcdef")
def run_job(shard):
subprocess.call(args + ["--shard=%s" % (shard,)])
return 0
for (status, job) in run_parallel(run_job, jobs, threads=16):
print "A mirroring shard died!"
print("A mirroring shard died!")
pass
sys.exit(0)
backoff = RandomExponentialBackoff(timeout_success_equivalent=300)
while backoff.keep_going():
print "Starting zephyr mirroring bot"
print("Starting zephyr mirroring bot")
try:
subprocess.call(args)
except:
traceback.print_exc()
backoff.fail()
print ""
print ""
print "ERROR: The Zephyr mirroring bot is unable to continue mirroring Zephyrs."
print "This is often caused by failing to maintain unexpired Kerberos tickets"
print "or AFS tokens. See https://zulip.com/zephyr for documentation on how to"
print "maintain unexpired Kerberos tickets and AFS tokens."
print ""
print("")
print("")
print("ERROR: The Zephyr mirroring bot is unable to continue mirroring Zephyrs.")
print("This is often caused by failing to maintain unexpired Kerberos tickets")
print("or AFS tokens. See https://zulip.com/zephyr for documentation on how to")
print("maintain unexpired Kerberos tickets and AFS tokens.")
print("")
sys.exit(1)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python2.7
# Copyright (C) 2012 Zulip, Inc.
#
# Permission is hereby granted, free of charge, to any person
@@ -20,12 +20,16 @@
# 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.
from __future__ import absolute_import
from typing import Any, List
import sys
from six.moves import map
from six.moves import range
try:
import simplejson
except ImportError:
import json as simplejson
import json as simplejson # type: ignore
import re
import time
import subprocess
@@ -41,10 +45,12 @@ import select
DEFAULT_SITE = "https://api.zulip.com"
class States:
Startup, ZulipToZephyr, ZephyrToZulip, ChildSending = range(4)
class States(object):
Startup, ZulipToZephyr, ZephyrToZulip, ChildSending = list(range(4))
CURRENT_STATE = States.Startup
logger = None # type: logging.Logger
def to_zulip_username(zephyr_username):
if "@" in zephyr_username:
(user, realm) = zephyr_username.split("@")
@@ -188,7 +194,7 @@ def zephyr_bulk_subscribe(subs):
def update_subscriptions():
try:
f = file(options.stream_file_path, "r")
f = open(options.stream_file_path, "r")
public_streams = simplejson.loads(f.read())
f.close()
except:
@@ -284,7 +290,7 @@ def parse_zephyr_body(zephyr_data):
def parse_crypt_table(zephyr_class, instance):
try:
crypt_table = file(os.path.join(os.environ["HOME"], ".crypt-table"))
crypt_table = open(os.path.join(os.environ["HOME"], ".crypt-table"))
except IOError:
return None
@@ -346,7 +352,7 @@ def process_notice(notice, log):
if zephyr_class == options.nagios_class:
# Mark that we got the message and proceed
with file(options.nagios_path, "w") as f:
with open(options.nagios_path, "w") as f:
f.write("0\n")
return
@@ -465,7 +471,7 @@ def zephyr_load_session_autoretry(session_path):
backoff = zulip.RandomExponentialBackoff()
while backoff.keep_going():
try:
session = file(session_path, "r").read()
session = open(session_path, "r").read()
zephyr._z.initialize()
zephyr._z.load_session(session)
zephyr.__inited = True
@@ -507,7 +513,7 @@ def zephyr_to_zulip(options):
if options.nagios_class:
zephyr_subscribe_autoretry((options.nagios_class, "*", "*"))
if options.use_sessions:
file(options.session_path, "w").write(zephyr._z.dump_session())
open(options.session_path, "w").write(zephyr._z.dump_session())
if options.logs_to_resend is not None:
with open(options.logs_to_resend, 'r') as log:
@@ -801,9 +807,9 @@ def add_zulip_subscriptions(verbose):
unauthorized = res.get("unauthorized")
if verbose:
if already is not None and len(already) > 0:
logger.info("\nAlready subscribed to: %s" % (", ".join(already.values()[0]),))
logger.info("\nAlready subscribed to: %s" % (", ".join(list(already.values())[0]),))
if new is not None and len(new) > 0:
logger.info("\nSuccessfully subscribed to: %s" % (", ".join(new.values()[0]),))
logger.info("\nSuccessfully subscribed to: %s" % (", ".join(list(new.values())[0]),))
if unauthorized is not None and len(unauthorized) > 0:
logger.info("\n" + "\n".join(textwrap.wrap("""\
The following streams you have NOT been subscribed to,
@@ -854,7 +860,7 @@ def parse_zephyr_subs(verbose=False):
logger.error("Couldn't find ~/.zephyr.subs!")
return []
for line in file(subs_file, "r").readlines():
for line in open(subs_file, "r").readlines():
line = line.strip()
if len(line) == 0:
continue
@@ -875,6 +881,7 @@ def parse_zephyr_subs(verbose=False):
return zephyr_subscriptions
def open_logger():
# type: () -> logging.Logger
if options.log_path is not None:
log_file = options.log_path
elif options.forward_class_messages:
@@ -1022,7 +1029,7 @@ if __name__ == "__main__":
signal.signal(signal.SIGINT, die_gracefully)
(options, args) = parse_args()
(options, args) = parse_args() # type: Any, List[str]
logger = open_logger()
configure_logger(logger, "parent")
@@ -1047,7 +1054,7 @@ Could not find API key file.
You need to either place your api key file at %s,
or specify the --api-key-file option.""" % (options.api_key_file,))))
sys.exit(1)
api_key = file(options.api_key_file).read().strip()
api_key = open(options.api_key_file).read().strip()
# Store the API key in the environment so that our children
# don't need to read it in
os.environ["HUMBUG_API_KEY"] = api_key
@@ -1110,7 +1117,7 @@ or specify the --api-key-file option.""" % (options.api_key_file,))))
options.session_path = "/var/tmp/%s" % (options.user,)
if options.forward_from_zulip:
child_pid = os.fork()
child_pid = os.fork() # type: int
if child_pid == 0:
CURRENT_STATE = States.ZulipToZephyr
# Run the zulip => zephyr mirror in the child

88
changelog.md Normal file
View File

@@ -0,0 +1,88 @@
# Change Log
All notable changes to this project will be documented in this file.
[Unreleased]
[1.3.12]
- CVE-2016-4426: Bot API keys were accessible to other users in the same realm.
- CVE-2016-4427: Deactivated users could access messages if SSO was enabled.
- Fixed a RabbitMQ configuration bug that resulted in reordered messages.
- Added expansive test suite for authentication backends and decorators.
- Added an option to logout_all_users to delete only sessions for deactivated users.
[1.3.11]
- Moved email digest support into the default Zulip production configuration.
- Added options for configuring Postgres, RabbitMQ, Redis, and memcached
in settings.py.
- Added documentation on using Hubot to integrate with useful services
not yet integrated with Zulip directly (e.g. Google Hangouts).
- Added new management command to test sending email from Zulip.
- Added Codeship, Pingdom, Taiga, Teamcity, and Yo integrations.
- Added Nagios plugins to the main distribution.
- Added ability for realm administrators to manage custom emoji.
- Added guide to writing new integrations.
- Enabled camo image proxy to fix mixed-content warnings for http images.
- Refactored the Zulip puppet modules to be more modular.
- Refactored the Tornado event system, fixing old memory leaks.
- Removed many old-style /json API endpoints
- Implemented running queue processors multithreaded in development,
decreasing RAM requirements for a Zulip development environment from
~1GB to ~300MB.
- Fixed rerendering the complete buddy list whenever a user came back from
idle, which was a significant performance issue in larger realms.
- Fixed the disabling of desktop notifications from 1.3.7 for new users.
- Fixed the (admin) create_user API enforcing restricted_to_domain, even
if that setting was disabled for the realm.
- Fixed bugs changing certain settings in administration pages.
- Fixed collapsing messages in narrowed views.
- Fixed 500 errors when uploading a non-image file as an avatar.
- Fixed Jira integration incorrectly not @-mentioning assignee.
[1.3.10]
- Added new integration for Travis CI.
- Added settings option to control maximum file upload size.
- Added support for running Zulip development environment in Docker.
- Added easy configuration support for a remote postgres database.
- Added extensive documentation on scalability, backups, and security.
- Recent private message threads are now displayed expanded similar to
the pre-existing recent topics feature.
- Made it possible to set LDAP and EMAIL_HOST passwords in
/etc/zulip/secrets.conf.
- Improved the styling for the Administration page and added tabs.
- Substantially improved loading performance on slow networks by enabling
GZIP compression on more assets.
- Changed the page title in narrowed views to include the current narrow.
- Fixed several backend performance issues affecting very large realms.
- Fixed bugs where draft compose content might be lost when reloading site.
- Fixed support for disabling the "zulip" notifications stream.
- Fixed missing step in postfix_localmail installation instructions.
- Fixed several bugs/inconveniences in the production upgrade process.
- Fixed realm restrictions for servers with a unique, open realm.
- Substantially cleaned up console logging from run-dev.py.
[1.3.9] - 2015-11-16
- Fixed buggy #! lines in upgrade scripts.
[1.3.8] - 2015-11-15
- Added options to the Python api for working with untrusted server certificates.
- Added a lot of documentation on the development environment and testing.
- Added partial support for translating the Zulip UI.
- Migrated installing Node dependencies to use npm.
- Fixed LDAP integration breaking autocomplete of @-mentions.
- Fixed admin panel reactivation/deactivation of bots.
- Fixed inaccurate documentation for downloading the desktop apps.
- Fixed various minor bugs in production installation process.
- Fixed security issue where recent history on private streams might
be visible to new users (to the Zulip team) who were invited with that
private stream as one of their initial streams
(https://github.com/zulip/zulip/issues/230).
- Major preliminary progress towards supporting Python 3.
[1.3.7] - 2015-10-19
- Turn off desktop and audible notifications for streams by default.
- Added support for the LDAP authentication integration creating new users.
- Added new endpoint to support Google auth on mobile.
- Fixed desktop notifications in modern Firefox.
- Fixed several installation issues for both production and development environments.
- Improved documentation for outgoing SMTP and the email mirror integration.

View File

@@ -105,7 +105,7 @@ class Confirmation(models.Model):
objects = ConfirmationManager()
class Meta:
class Meta(object):
verbose_name = _('confirmation email')
verbose_name_plural = _('confirmation emails')

View File

@@ -2,9 +2,10 @@
# Copyright: (c) 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
from typing import Any, Dict
__revision__ = '$Id: settings.py 12 2008-11-23 19:38:52Z jarek.zgoda $'
STATUS_ACTIVE = 1
STATUS_FIELDS = {
}
STATUS_FIELDS = {} # type: Dict[Any, Any]

View File

@@ -6,4 +6,10 @@ urlpatterns = patterns('',
url(r'^zephyr/$', TemplateView.as_view(template_name='corporate/zephyr.html')),
url(r'^mit/$', TemplateView.as_view(template_name='corporate/mit.html')),
url(r'^zephyr-mirror/$', TemplateView.as_view(template_name='corporate/zephyr-mirror.html')),
# Terms of service and privacy policy
url(r'^terms/$', TemplateView.as_view(template_name='corporate/terms.html')),
url(r'^terms-enterprise/$', TemplateView.as_view(template_name='corporate/terms-enterprise.html')),
url(r'^privacy/$', TemplateView.as_view(template_name='corporate/privacy.html')),
)

View File

@@ -79,13 +79,13 @@ In our Django code, never do direct
use ``get_user_profile_by_{email,id}``. There are 3 reasons for this:
#. It's guaranteed to correctly do a case-inexact lookup
#. It fetches the user object from memcached, which is faster
#. It fetches the user object from remote cache, which is faster
#. It always fetches a UserProfile object which has been queried using
.selected\_related(), and thus will perform well when one later
accesses related models like the Realm.
Similarly we have ``get_client`` and ``get_stream`` functions to fetch
those commonly accessed objects via memcached.
those commonly accessed objects via remote cache.
Using Django model objects as keys in sets/dicts
------------------------------------------------
@@ -352,8 +352,8 @@ styles (separate lines for each selector)::
Python
------
- Scripts should start with ``#!/usr/bin/env python`` and not
``#!/usr/bin/python``. See commit ``437d4aee`` for an explanation of
- Scripts should start with ``#!/usr/bin/env python2.7`` and not
``#!/usr/bin/env python2.7``. See commit ``437d4aee`` for an explanation of
why. Don't put such a line on a Python file unless it's meaningful to
run it as a script. (Some libraries can also be run as scripts, e.g.
to run a test suite.)
@@ -391,7 +391,11 @@ Commit Discipline
-----------------
We follow the Git project's own commit discipline practice of "Each
commit is a minimal coherent idea".
commit is a minimal coherent idea". This discipline takes a bit of
work, but it makes it much easier for code reviewers to spot bugs, and
makesthe commit history a much more useful resource for developers
trying to understand why the code works the way it does, which also
helps a lot in preventing bugs.
Coherency requirements for any commit:
@@ -436,12 +440,28 @@ Other considerations:
- Overly fine commits are easily squashed, but not vice versa, so err
toward small commits, and the code reviewer can advise on squashing.
- If a commit you write doesn't pass tests, you should usually fix
that by amending the commit to fix the bug, not writing a new "fix
tests" commit on top of it.
- When you fix a GitHub issue, `mark that you've fixed the issue in
your commit message
<https://help.github.com/articles/closing-issues-via-commit-messages/>`__
so that the issue is automatically closed when your code is merged.
Zulip's preferred style for this is to have the final paragraph
of the commit message read e.g. "Fixes: #123."
It can take some practice to get used to writing your commits this
way. For example, often you'll start adding a feature, and discover
you need to a refactoring partway through writing the feature. When
that happens, we recommend stashing your partial feature, do the
refactoring, commit it, and then finish implementing your feature.
Zulip expects you to structure the commits in your pull requests to
form a clean history before we will merge them; it's best to write
your commits following these guidelines in the first place, but if you
don't, you can always fix your history using `git rebase -i`.
It can take some practice to get used to writing your commits with a
clean history so that you don't spend much time doing interactive
rebases. For example, often you'll start adding a feature, and
discover you need to a refactoring partway through writing the
feature. When that happens, we recommend stashing your partial
feature, do the refactoring, commit it, and then finish implementing
your feature.
Commit Messages
---------------
@@ -454,18 +474,35 @@ Bad::
bugfix
gather_subscriptions was broken
fix bug #234.
Good::
Prevent gather_subscriptions from throwing an exception when given bad input.
Fix gather_subscriptions throwing an exception when given bad input.
- Please use a complete sentence, ending with a period.
- Use present-tense action verbs in your commit messages.
Bad::
Fixing gather_subscriptions throwing an exception when given bad input.
Fixed gather_subscriptions throwing an exception when given bad input.
Good::
Fix gather_subscriptions throwing an exception when given bad input.
- Please use a complete sentence in the summary, ending with a
period.
- The rest of the commit message should be written in full prose and
explain why and how the change was made. If the commit makes
performance improvements, you should generally include some rough
benchmarks showing that it actually improves the performance.
- Any paragraph content in the commit message should be line-wrapped
to less than 76 characters per line, so that your commit message
will be reasonably readable in `git log` in a normal terminal.
- In your commit message, you should describe any manual testing you
did in addition to running the automated tests, and any aspects of
the commit that you think are questionable and you'd like special

View File

@@ -293,3 +293,11 @@ texinfo_documents = [
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
from recommonmark.parser import CommonMarkParser
source_parsers = {
'.md': CommonMarkParser,
}
source_suffix = ['.rst', '.md']

View File

@@ -75,13 +75,13 @@ Templates
Tests
=====
+------------------------+-----------------------------------+
| ``zerver/test*.py`` | Backend tests | |
+------------------------+-----------------------------------+
| ``zerver/tests/frontend/node`` | Node Frontend unit tests |
+------------------------+-----------------------------------+
| ``zerver/tests/frontend/tests`` | Casper frontend tests |
+------------------------+-----------------------------------+
+-------------------------+-----------------------------------+
| ``zerver/tests/`` | Backend tests |
+-------------------------+-----------------------------------+
| ``frontend_tests/node`` | Node Frontend unit tests |
+-------------------------+-----------------------------------+
| ``frontend_tests/tests``| Casper frontend tests |
+-------------------------+-----------------------------------+
Documentation
=============

View File

@@ -0,0 +1,71 @@
=======================
Front End Build Process
=======================
This page documents additional information that may be useful when developing new features for Zulip that require front-end changes. For a more general overview, see the new feature tutorial. The code style documentation also has relevant information about how Zulip's code is structured.
Primary build process
=====================
Most of the existing JS in Zulip is written in IIFE-wrapped modules,
one per file in the `static/js` directory. When running Zulip in
development mode, each file is loaded seperately. In production mode
(and when creating a release tarball using
`tools/build-release-tarball`), JavaScript files are concatenated and
minified.
If you add a new JavaScript file, it needs to be specified in the
`JS_SPECS` dictionary defined in `zproject/settings.py` to be included
in the concatenated file.
Webpack/CommonJS modules
========================
New JS written for Zulip can be written as CommonJS modules (bundled
using `webpack <https://webpack.github.io/>`_, though this will taken
care of automatically whenever ``run-dev.py`` is running). (CommonJS
is the same module format that Node uses, so see `the Node
documentation <https://nodejs.org/docs/latest/api/modules.html>` for
more information on the syntax.)
Benefits of using CommonJS modules over the `IIFE
<http://benalman.com/news/2010/11/immediately-invoked-function-expression/>`_
module approach:
* namespacing/module boilerplate will be added automatically in the bundling process
* dependencies between modules are more explicit and easier to trace
* no separate list of JS files needs to be maintained for concatenation and minification
* third-party libraries can be more easily installed/versioned using npm
* running the same code in the browser and in Node for testing is
simplified (as both environments use the same module syntax)
The entry point file for the bundle generated by webpack is
``static/js/src/main.js``. Any modules you add will need to be
required from this file (or one of its dependencies) in order to be
included in the script bundle.
Adding static files
===================
To add a static file to the app (JavaScript, CSS, images, etc), first
add it to the appropriate place under ``static/``.
* Third-party files should all go in ``static/third/``. Tag the commit
with "[third]" when adding or modifying a third-party package.
* Our own JS lives under ``static/js``; CSS lives under ``static/styles``.
* JavaScript and CSS files are combined and minified in production. In
this case all you need to do is add the filename to PIPELINE_CSS or
JS_SPECS in ``zproject/settings.py``. (If you plan to only use the
JS/CSS within the app proper, and not on the login page or other
standalone pages, put it in the 'app' category.)
If you want to test minified files in development, look for the
``PIPELINE =`` line in ``zproject/settings.py`` and set it to ``True`` -- or
just set ``DEBUG = False``.
Note that ``static/html/{400,5xx}.html`` will only render properly if
minification is enabled, since they hardcode the path
``static/min/portico.css``.

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env python3
#!/usr/bin/env python2.7
from __future__ import print_function
# Remove HTML entity escaping left over from MediaWiki->rST conversion.

View File

@@ -11,10 +11,18 @@ Contents:
.. toctree::
:maxdepth: 2
integration-guide
new-feature-tutorial
code-style
directory-structure
code-style
testing
markdown
queuing
schema-migrations
front-end-build-process
mypy
translating
roadmap
Indices and tables
==================

178
docs/integration-guide.md Normal file
View File

@@ -0,0 +1,178 @@
# Integration Writing Guide
Integrations are one of the most important parts of a group chat tool
like Zulip, and we are committed to making integrating with Zulip and
getting you integration merged upstream so everyone else can benefit
from it as easy as possible while maintaining the high quality of the
Zulip integrations library.
Contributions to this guide are very welcome, so if you run into any
issues following these instructions or come up with any tips or tools
that help writing integration, please email
zulip-devel@googlegroups.com, open an issue, or submit a pull request
to share your ideas!
## Types of integrations
We have several different ways that we integrate with 3rd part
products, ordered here by which types we prefer to write:
1. Webhook integrations (examples: Freshdesk, GitHub), where the
third-party service supports posting content to a particular URI on
our site with data about the event. For these, you usually just need
to add a new handler in `zerver/views/webhooks.py` (plus
test/document/etc.). An example commit implementing a new webhook.
https://github.com/zulip/zulip/pull/324.
2. Python script integrations (examples: SVN, Git), where we can get
the service to call our integration (by shelling out or otherwise),
passing in the required data. Our preferred model for these is to
ship these integrations in our API release tarballs (by writing the
integration in `api/integrations`).
3. Plugin integrations (examples: Jenkins, Hubot, Trac) where the user
needs to install a plugin into their existing software. These are
often more work, but for some products are the only way to integrate
with the product at all.
## General advice for writing integrations
* Consider using our Zulip markup to make the output from your
integration especially attractive or useful (e.g. emoji, markdown
emphasis, @-mentions, or `!avatar(email)`).
* Use topics effectively to ensure sequential messages about the same
thing are threaded together; this makes for much better consumption
by users. E.g. for a bug tracker integration, put the bug number in
the topic for all messages; for an integration like Nagios, put the
service in the topic.
* Integrations that don't match a team's workflow can often be
uselessly spammy. Give careful thought to providing options for
triggering Zulip messages only for certain message types, certain
projects, or sending different messages to different streams/topics,
to make it easy for teams to configure the integration to support
their workflow.
* Sometimes it can be helpful to contact the vendor if it appears they
don't have an API or webhook we can use -- sometimes the right API
is just not properly documented.
## Writing Webhook integrations
New Zulip webhook integrations can take just a few hours to write,
including tests and documentation, if you use the right process.
Here's how we recommend doing it:
* First, use http://requestb.in/ or a similar site to capture an
example webhook payload from the service you're integrating. You
can use these captured payloads to create a set of test fixtures for
your integration under `zerver/fixtures`.
* Then write a draft webhook handler under `zerver/views/webhooks/`;
there are a lot of examples in that directory. We recommend
templating off a short one (like `stash.py` or `zendesk.py`), since
the longer ones usually just have more complex parsing which can
obscure what's common to all webhook integrations. In addition to
writing the integration itself, you'll need to add an entry in
`zproject/urls.py` for your webhook; search for `webhook` in that
file to find the existing ones (and please add yours in the
alphabetically correct place).
* Then write a test for your fixture in `zerver/tests/test_hooks.py`, and
you can iterate on the tests and webhooks handler until they work,
all without ever needing to post directly from the server you're
integrating to your Zulip development machine. To run just the
tests from the test class you wrote, you can use e.g.
```
test-backend zerver.tests.test_hooks.PagerDutyHookTests
```
See
https://github.com/zulip/zulip/blob/master/README.dev.md#running-the-test-suite
for more details on the Zulip test runner.
* Once you've gotten your webhook working and passing a test, capture
payloads for the other common types of posts the service's webhook
will make, and add tests for them; usually this part of the process
is pretty fast. Webhook integration tests should all use fixtures
(as opposed to contacting the service), since otherwise the tests
can't run without Internet access and some sort of credentials for
the service.
* Finally, write documentation for the integration (see below)!
## Writing Python script and plugin integrations integrations
For plugin integrations, usually you will need to consult the
documentation for the third party software in order to learn how to
write the integration. But we have a few notes on how to do these:
* You should always send messages by POSTing to URLs of the form
`https://zulip.example.com/v1/messages/`, not the legacy
`/api/v1/send_message` message sending API.
* We usually build Python script integration with (at least) 2 files:
`zulip_foo_config.py`` containing the configuration for the
integration including the bots' API keys, plus a script that reads
from this configuration to actually do the work (that way, it's
possible to update the script without breaking users' configurations).
* Be sure to test your integration carefully and document how to
install it (see notes on documentation below).
* You should specify a clear HTTP User-Agent for your integration. The
user agent should at a minimum identify the integration and version
number, separated by a slash. If possible, you should collect platform
information and include that in `()`s after the version number. Some
examples of ideal UAs are:
```
ZulipDesktop/0.7.0 (Ubuntu; 14.04)
ZulipJenkins/0.1.0 (Windows; 7.2)
ZulipMobile/0.5.4 (Android; 4.2; maguro)
```
## Documenting your integration
Every Zulip integration must be documented in
`templates/zerver/integrations.html`. Usually, this involves a few
steps:
* Add an `integration-lozenge` class block in the alphabetically
correct place in the main integration list, using the logo for the
integrated software.
* Add an `integration-instructions` class block also in the
alphabetically correct place, explaining all the steps required to
setup the integration, including what URLs to use, etc. If there
are any screens in the product involved, take a few screenshots with
the input fields filled out with sample values in order to make the
instructions really easy to follow. For the screenshots, use
something like `github-bot@example.com` for the email addresses and
an obviously fake API key like `abcdef123456790`.
* Finally, generate a message sent by the integration and take a
screenshot of the message to provide an example message in the
documentation. If your new integration is a webhook integration,
you can generate such a message from your test fixtures
using `send_webhook_fixture_message`:
```
./manage.py send_webhook_fixture_message \
--fixture=zerver/fixtures/pingdom/pingdom_imap_down_to_up.json \
'--url=/api/v1/external/pingdom?stream=stream_name&api_key=api_key'
```
When generating the screenshot of a sample message, give your test
bot a nice name like "GitHub Bot", use the project's logo as the
bot's avatar, and take the screenshots showing the stream/topic bar
for the message, not just the message body.
When writing documentation for your integration, be sure to use the
`{{ external_api_uri }}` template variable, so that your integration
documentation will provide the correct URL for whatever server it is
deployed on. If special configuration is required to set the SITE
variable, you should document that too, inside an `{% if
api_site_required %}` check.

135
docs/markdown.md Normal file
View File

@@ -0,0 +1,135 @@
# Zulip's markdown implementation
Zulip has a special flavor of Markdown, currently called 'bugdown'
after Zulip's original name of "humbug".
Zulip has two implementations of Bugdown. The first is based on
Python-Markdown (`zerver/lib/bugdown/`) and is used to authoritatively
render messages on the backend (and implements expensive features like
querying the Twitter API to render tweets nicely). The other is in
javascript, based on marked (`static/js/echo.js`), and is used to
preview and locally echo messages the moment the sender hits enter,
without waiting for round trip from the server. The two
implementations are tested for compatibility via
`zerver/tests/test_bugdown.py` and the fixtures under
`zerver/fixtures/bugdown-data.json`.
The javascript implementation knows which types of messages it can
render correctly, and thus while there is code to rerender messages
based on the authoritative backend rendering (which would clause a
change in the rendering visible only to the sender shortly after a
message is sent), this should never happen and whenever it does it is
considered a bug. Instead, if the frontend doesn't know how to
correctly render a message, we simply won't echo the message for the
sender until it's rendered by the backend. So for example, a message
containing a link to Twitter will not be rendered by the javascript
implementation because it doesn't support doing the 3rd party API
queries required to render tweets nicely.
I should note that the below documentation is based on a comparison
with original Markdown, not newer Markdown variants like CommonMark.
## Zulip's Markdown philosophy
Markdown is great for group chat for the same reason it's been
successful in products ranging from blogs to wikis to bug trackers:
it's close enough to how people try to express themselves when writing
plain text (e.g. emails) that is helps more than getting in the way.
The main issue for using Markdown in instant messaging is that the
Markdown standard syntax used in a lot of wikis/blogs has nontrivial
error rates, where the author needs to go back and edit the post to
fix the formatting after typing it the first time. While that's
basically fine when writing a blog, it gets annoying very fast in a
chat product; even though you can edit messages to fix formatting
mistakes, you don't want to be doing that often. There are basically
2 types of error rates that are important for a product like Zulip:
* What fraction of the time, if you pasted a short technical email
that you wrote to your team and passed it through your Markdown
implementation, would you need to change the text of your email for it
to render in a reasonable way? This is the "accidental Markdown
syntax" problem, common with Markdown syntax like the italics syntax
interacting with talking about `char *`s.
* What fraction of the time do users attempting to use a particular
Markdown syntax actually succeed at doing so correctly? Syntax like
required a blank line between text and the start of a bulleted list
raise this figure substantially.
Both of these are minor issues for most products using Markdown, but
they are major problems in the instant messaging context, because one
can't edit a message that has already been sent and users are
generally writing quickly. Zulip's Markdown strategy is based on the
principles of giving users the power they need to express complicated
ideas in a chat context while minimizing those two error rates.
## Zulip's Changes to Markdown
Below, we document the changes that Zulip has against stock
Python-Markdown; some of the features we modify / disable may already
be non-standard.
### Basic syntax
* Enable `nl2br</tt> extension: this means one newline creates a line
break (not paragraph break).
* Disable italics entirely. This resolves an issue where people were
using `*` and `_` and hitting it by mistake too often. E.g. with
stock Markdown `You should use char * instead of void * there` would
trigger italics.
* Allow only `**` syntax for bold, not `__` (easy to hit by mistake if
discussing Python `__init__` or something)
* Disable special use of `\` to escape other syntax. Rendering `\\` as
`\` was hugely controversial, but having no escape syntax is also
controversial. We may revisit this. For now you can always put
things in code blocks.
### Lists
* Allow tacking a bulleted list or block quote onto the end of a
paragraph, i.e. without a blank line before it
* Allow only `*` for bulleted lists, not `+` or `-` (previoulsy
created confusion with diff-style text sloppily not included in a
code block)
* Disable ordered list syntax: it automatically renumbers, which can
be really confusing when sending a numbered list across multiple
messages.
### Links
* Enable auto-linkification, both for `http://...` and guessing at
things like `t.co/foo`.
* Force links to be absolute. `[foo](google.com)` will go to
`http://google.com`, and not `http://zulip.com/google.com` which
is the default behavior.
* Set `target="_blank"` and `title=`(the url) on every link tag so
clicking always opens a new window
* Disable link-by-reference syntax, `[foo][bar]` ... `[bar]: http://google.com`
### Code
* Enable fenced code block extension, with syntax highlighting
* Disable line-numbering within fenced code blocks -- the `<table>`
output confused our web client code.
### Other
* Disable headings, both `# foo` and `== foo ==` syntax: they don't
make much sense for chat messages.
* Disabled images.
* Allow embedding any avatar as a tiny (list bullet size) image. This
is used primarily by version control integrations.
* We added the `~~~ quote` block quote syntax.

78
docs/mypy.md Normal file
View File

@@ -0,0 +1,78 @@
# mypy Python static type checker
[mypy](http://mypy-lang.org/) is a compile-time static type checker
for Python, allowing optional, gradual typing of Python code. Zulip
is using mypy's Python 2 compatible syntax for type annotations, which
means that type annotations are written inside comments that start
with `# type: `. Here's a brief example of the mypy syntax we're
using in Zulip:
```
user_dict = {} # type: Dict[str, UserProfile]
def get_user_profile_by_email(email):
# type: (str) -> UserProfile
... # Actual code of the function here
```
You can learn more about it at:
* [Python 2 type annotation syntax in PEP 484](https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code)
* [Using mypy with Python 2 code](http://mypy.readthedocs.io/en/latest/python2.html)
The mypy type checker is run automatically as part of Zulip's Travis
CI testing process.
## Installing mypy
If you installed Zulip's development environment correctly, mypy
should already be installed inside the Python 3 virtualenv at
`zulip-py3-venv` (mypy only supports Python 3). If it isn't installed
(e.g. because you haven't reprovisioned recently), you can run
`tools/install-mypy` to install it.
## Running mypy on Zulip's code locally
To run mypy on Zulip's python code, run the command:
tools/run-mypy
It will output errors in the same style of a compiler. For example,
if your code has a type error like this:
```
foo = 1
foo = '1'
```
you'll get an error like this:
```
test.py: note: In function "test":
test.py:200: error: Incompatible types in assignment (expression has type "str", variable has type "int")
```
If you need help interpreting or debugging mypy errors, please feel
free to mention @sharmaeklavya2 or @timabbott on your pull request (or
email zulip-devel@googlegroups.com) to get help; we'd love to both
build a great troubleshooting guide in this doc and also help
contribute improvements to error messages upstream.
Since mypy is a new tool under rapid development and occasionally
makes breaking changes, Zulip is using a pinned version of mypy from
its [git repository](https://github.com/python/mypy) rather than
tracking the (older) latest mypy release on pypi.
## Excluded files
Since several python files in Zulip's code don't pass mypy's checks
(even for unannotated code) right now, a list of files to be excluded
from the check for CI is present in tools/run-mypy.
To run mypy on all python files, ignoring the exclude list, you can
pass the `--all` option to tools/run-mypy.
tools/run-mypy --all
If you type annotate some of those files, please remove them from the
exclude list.

View File

@@ -2,84 +2,215 @@
New Feature Tutorial
====================
.. attention::
This tutorial is an unfinished work -- contributions welcome!
The changes needed to add a new feature will vary, of course, but this document
provides a general outline of what you may need to do, as well as an example of
the specific steps needed to add a new feature: adding a new option to the
application that is dynamically synced through the data system in real-time to
all browsers the user may have open.
The changes needed to add a new feature will vary, of course. We give an
example here that illustrates some of the common steps needed. We describe
the process of adding a new setting for admins that restricts inviting new
users to admins only.
Backend Changes
General Process
===============
Adding a field to the database
------------------------------
The server accesses the underlying database in `zerver/models.py`. Add
a new field in the appropriate class, `realm_invite_by_admins_only`
in the `Realm` class in this case.
**Update the model:** The server accesses the underlying database in `zerver/
models.py`. Add a new field in the appropriate class.
Once you do so, you need to create the migration and run it; the
process is documented at:
https://docs.djangoproject.com/en/1.8/topics/migrations/
**Create and run the migration:** To create and apply a migration, run: ::
Once you've run the migration, to test your changes, you'll want to
restart memcached on your development server (``/etc/init.d/memcached restart``) and
then restart ``run-dev.py`` to avoid interacting with cached objects.
./manage.py makemigrations
./manage.py migrate
**Test your changes:** Once you've run the migration, restart memcached on your
development server (``/etc/init.d/memcached restart``) and then restart
``run-dev.py`` to avoid interacting with cached objects.
Backend changes
---------------
You should add code in `zerver/lib/actions.py` to interact with the database,
that actually updates the relevant field. In this case, `do_set_realm_invite_by_admins_only`
is a function that actually updates the field in the database, and sends
an event announcing that this change has been made.
**Database interaction:** Add any necessary code for updating and interacting
with the database in ``zerver/lib/actions.py``. It should update the database and
send an event announcing the change.
You then need update the `fetch_initial_state_data` and `apply_events` functions
in `zerver/lib/actions.py` to update the state based on the event you just created.
In this case, we add a line
**Application state:** Modify the ``fetch_initial_state_data`` and ``apply_events``
functions in ``zerver/lib/actions.py`` to update the state based on the event you
just created.
::
**Backend implementation:** Make any other modifications to the backend required for
your change.
state['realm_invite_by_admins_only'] = user_profile.realm.invite_by_admins_only`
to the `fetch_initial_state_data` function. The `apply_events` function
doesn't need to be updated since
::
elif event['type'] == 'realm':
field = 'realm_' + event['property']
state[field] = event['value']
already took care of our event.
Then update `zerver/views/__init__.py` to actually call your function.
In the dictionary which sets the javascript `page_params` dictionary,
add a value for your feature.
::
realm_invite_by_admins_only = register_ret['realm_invite_by_admins_only']
Perhaps your new option controls some other backend rendering: in our case
we test for this option in the `home` method for adding a variable to the response.
The functions in this file control the generation of various pages served
(along with the Django templates).
Our new feature also shows up in the administration tab (as a checkbox),
so we need to update the `update_realm` function.
Finally, add tests for your backend changes; at the very least you
should add a test of your event data flowing through the system in
``test_events.py``.
**Testing:** At the very least, add a test of your event data flowing through
the system in ``test_events.py``.
Frontend changes
----------------
You need to change various things on the front end. In this case, the relevant files
are `static/js/server_events.js`, `static/js/admin.js`, `static/styles/zulip.css
and `static/templates/admin_tab.handlebars`.
**JavaScript:** Zulip's JavaScript is located in the directory ``static/js/``.
The exact files you may need to change depend on your feature. If you've added a
new event that is sent to clients, be sure to add a handler for it to
``static/js/server_events.js``.
**CSS:** The primary CSS file is ``static/styles/zulip.css``. If your new
feature requires UI changes, you may need to add additional CSS to this file.
**Templates:** The initial page structure is rendered via Django templates
located in ``template/server``. For JavaScript, Zulip uses Handlebars templates located in
``static/templates``. Templates are precompiled as part of the build/deploy
process.
**Testing:** There are two types of frontend tests: node-based unit tests and
blackbox end-to-end tests. The blackbox tests are run in a headless browser
using Casper.js and are located in ``frontend_tests/casper_tests/``. The unit
tests use Node's ``assert`` module are located in ``frontend_tests/node_tests/``.
For more information on writing and running tests see the :doc:`testing
documentation <testing>`.
Example Feature
===============
This example describes the process of adding a new setting to Zulip:
a flag that restricts inviting new users to admins only (the default behavior
is that any user can invite other users). It is based on an actual Zulip feature,
and you can review `the original commit in the Zulip git repo <https://github.com/zulip/zulip/commit/5b7f3466baee565b8e5099bcbd3e1ccdbdb0a408>`_.
(Note that Zulip has since been upgraded from Django 1.6 to 1.8, so the migration
format has changed.)
First, update the database and model to store the new setting. Add a
new boolean field, ``realm_invite_by_admins_only``, to the Realm model in
``zerver/models.py``.
Then create a Django migration that adds a new field, ``invite_by_admins_only``,
to the ``zerver_realm`` table.
In ``zerver/lib/actions.py``, create a new function named
``do_set_realm_invite_by_admins_only``. This function will update the database
and trigger an event to notify clients when this setting changes. In this case
there was an exisiting ``realm|update`` event type which was used for setting
similar flags on the Realm model, so it was possible to add a new property to
that event rather than creating a new one. The property name matches the
database field to make it easy to understand what it indicates.
The second argument to ``send_event`` is the list of users whose browser
sessions should be notified. Depending on the setting, this can be a single user
(if the setting is a personal one, like time display format), only members in a
particular stream or all active users in a realm. ::
# zerver/lib/actions.py
def do_set_realm_invite_by_admins_only(realm, invite_by_admins_only):
realm.invite_by_admins_only = invite_by_admins_only
realm.save(update_fields=['invite_by_admins_only'])
event = dict(
type="realm",
op="update",
property='invite_by_admins_only',
value=invite_by_admins_only,
)
send_event(event, active_user_ids(realm))
return {}
You then need to add code that will handle the event and update the application
state. In ``zerver/lib/actions.py`` update the ``fetch_initial_state`` and
``apply_events`` functions. ::
def fetch_initial_state_data(user_profile, event_types, queue_id):
# ...
state['realm_invite_by_admins_only'] = user_profile.realm.invite_by_admins_only`
In this case you don't need to change ``apply_events`` because there is already
code that will correctly handle the realm update event type: ::
def apply_events(state, events, user_profile):
for event in events:
# ...
elif event['type'] == 'realm':
field = 'realm_' + event['property']
state[field] = event['value']
You then need to add a view for clients to access that will call the newly-added
``actions.py`` code to update the database. This example feature adds a new
parameter that should be sent to clients when the application loads and be
accessible via JavaScript, and there is already a view that does this for
related flags: ``update_realm``. So in this case, we can add out code to the
exisiting view instead of creating a new one. ::
# zerver/views/__init__.py
def home(request):
# ...
page_params = dict(
# ...
realm_invite_by_admins_only = register_ret['realm_invite_by_admins_only'],
# ...
)
Since this feature also adds a checkbox to the admin page, and adds a new
property the Realm model that can be modified from there, you also need to make
changes to the ``update_realm`` function in the same file: ::
# zerver/views/__init__.py
def update_realm(request, user_profile,
name=REQ(validator=check_string, default=None),
restricted_to_domain=REQ(validator=check_bool, default=None),
invite_by_admins_only=REQ(validator=check_bool,default=None)):
# ...
if invite_by_admins_only is not None and
realm.invite_by_admins_only != invite_by_admins_only:
do_set_realm_invite_by_admins_only(realm, invite_by_admins_only)
data['invite_by_admins_only'] = invite_by_admins_only
Then make the required front end changes: in this case a checkbox needs to be
added to the admin page (and its value added to the data sent back to server
when a realm is updated) and the change event needs to be handled on the client.
To add the checkbox to the admin page, modify the relevant template,
``static/templates/admin_tab.handlebars`` (omitted here since it is relatively
straightforward). Then add code to handle changes to the new form control in
``static/js/admin.js``. ::
var url = "/json/realm";
var new_invite_by_admins_only =
$("#id_realm_invite_by_admins_only").prop("checked");
data[invite_by_admins_only] = JSON.stringify(new_invite_by_admins_only);
channel.patch({
url: url,
data: data,
success: function (data) {
# ...
if (data.invite_by_admins_only) {
ui.report_success("New users must be invited by an admin!", invite_by_admins_only_status);
} else {
ui.report_success("Any user may now invite new users!", invite_by_admins_only_status);
}
# ...
}
});
Finally, update ``server_events.js`` to handle related events coming from the
server. ::
# static/js/server_events.js
function get_events_success(events) {
# ...
var dispatch_event = function dispatch_event(event) {
switch (event.type) {
# ...
case 'realm':
if (event.op === 'update' && event.property === 'invite_by_admins_only') {
page_params.realm_invite_by_admins_only = event.value;
}
}
}
Any code needed to update the UI should be placed in ``dispatch_event`` callback
(rather than the ``channel.patch``) function. This ensures the appropriate code
will run even if the changes are made in another browser window. In this example
most of the changes are on the backend, so no UI updates are required.

81
docs/queuing.md Normal file
View File

@@ -0,0 +1,81 @@
# RabbitMQ queues
Zulip uses RabbitMQ to manage a system of internal queues. These are
used for a variety of purposes:
* Asynchronously doing expensive operations like sending email
notifications which can take seconds per email and thus would
otherwise timeout when 100s are triggered at once (E.g. inviting a
lot of new users to a realm).
* Asynchronously doing non-time-critical somewhat expensive operations
like updating analytics tables (e.g. UserActivityInternal) which
don't have any immediate runtime effect.
* Communicating events to push to clients (browsers, etc.) from the
main Zulip Django application process to the Tornado-based events
system. Example events might be that a new message was sent, a user
has changed their subscriptions, etc.
* Processing mobile push notifications and email mirroring system
messages.
* Processing various errors, frontend tracebacks, and slow database
queries in a batched fashion.
* Doing markdown rendering for messages delivered to the Tornado via
websockets.
Needless to say, the RabbitMQ-based queuing system is an important
part of the overall Zulip architecture, since it's in critical code
paths for everything from signing up for account, to rendering
messages, to delivering updates to clients.
We use the `pika` library to interface with RabbitMQ, using a simple
custom integration defined in `zerver/lib/queue.py`.
### Adding a new queue processor
To add a new queue processor:
* Define the processor in `zerver/worker/queue_processors.py` using
the `@assign_queue` decorator; it's pretty easy to get the template
for an existing similar queue processor. This suffices to test your
queue worker in the Zulip development environment, though you'll
need to restart `tools/run-dev.py` in order to run your new queue
processor. You can also run a single queue processor manually using
e.g. `./manage.py process_queue --queue=user_activity`.
* So that supervisord will known to run the queue processor in
production, you will need to define a program entry for it in
`servers/puppet/modules/zulip/files/supervisor/conf.d/zulip.conf`
and add it to the `zulip-workers` group further down in the file.
* For monitoring, you need to add a check that your worker is running
to puppet/zulip/files/cron.d/rabbitmq-numconsumers if it's a
one-at-a-time consumer like `user_activity_internal` or a custom
nagios check if it is a bulk processor like `slow_queries`.
### Publishing events into a queue
You can publish events to a RabbitMQ queue using the
`queue_json_publish` function defined in `zerver/lib/queue.py`.
### Clearing a RabbitMQ queue
If you need to clear a queue (delete all the events in it), run
`./manage.py purge_queue <queue_name>`, for example:
```
./manage.py purge_queue user_activity
```
You can also use the amqp tools directly. Install `amqp-tools` from
apt and then run:
```
amqp-delete-queue --username=zulip --password='...' --server=localhost \
--queue=user_presence
```
with the RabbitMQ password from `/etc/zulip/zulip-secrets.conf`.

262
docs/roadmap.md Normal file
View File

@@ -0,0 +1,262 @@
Zulip 2016 Roadmap
==================
## Introduction
Zulip has received a great deal of interest and attention since it was
released as free and open source software by Dropbox. That attention
has come with a lot of active development work from members of the
Zulip community. From when Zulip was released as open source in late
September 2015 through today (mid-April, 2016), over 300 pull requests
have been submitted to the various Zulip repositories (and over 250
have been merged!), the vast majority of which are submitted by
Zulip's users around the world (as opposed to the small core team who
review and merge the pull requests).
In any project, there can be a lot of value in periodically putting
together a roadmap detailing the major areas where the project is
hoping to improve. This can be especially important in an open source
project like Zulip where development is distributed across many people
around the world. This roadmap is intended to organize a list of the
most important improvements that should to be made to Zulip in the
relatively near future. Our aim is to complete most of these
improvements in 2016.
This document is not meant to constrain in any way what contributions
to Zulip will be accepted; instead, it will be used by the Zulip core
team to prioritize our efforts, measure progress on improving the
Zulip product, hold ourselves accountable for making Zulip improve
rapidly, and celebrate members of the community who contribute to
projects on the roadmap.
If you're someone interested in making a larger contribution to Zulip
and looking for somewhere to start, this roadmap is the best place to
look for substantial projects that will definitely be of value to the
community (if you're looking for a starter project, see the [guide to
getting involved with
Zulip](https://github.com/zulip/zulip#how-to-get-involved-with-contributing-to-zulip)).
Without further ado, below is the Zulip 2016 roadmap.
## Burning problems
The top problem for the Zulip project is the state of the mobile apps.
The Android app has started seeing rapid progress thanks to a series
of contributions by Lisa Neigut of Recurse Center, and we believe to
be on a good path. The iOS app has fewer features than Android and
has more bugs, but more importantly is in need of an experienced iOS
developer who has time to drive the project.
## Core User Experience
This category includes important improvements to the core user
experience that will benefit all users.
* [Improve missed message notifications to make "reply" work nicely](https://github.com/zulip/zulip/issues/612)
* [Add support for showing "user is typing" notifications](https://github.com/zulip/zulip/issues/150)
* [Add pretty bubbles for recipients in the compose box](https://github.com/zulip/zulip/issues/595)
* [Finish and merge support for pinning a few important streams](https://github.com/zulip/zulip/issues/285)
* [Display stream descriptions more prominently](https://github.com/zulip/zulip/issues/164)
* [Integration inline URL previews](https://github.com/zulip/zulip/issues/406)
* [Add support for managing uploaded files](https://github.com/zulip/zulip/issues/454)
* [Make Zulip onboarding experience smoother for teams not used to topics](https://github.com/zulip/zulip/issues/647). That specific proposal might not be right but the issue is worth investing time in.
## Ease of setup and onboarding issues
This category focuses on issues users experience when installing a new
Zulip server or setting up a new Zulip realm.
* [Create a web flow for setting up a new realm / the first realm on a new server (currently, it's a command-line process)](https://github.com/zulip/zulip/issues/260)
* [Document or better script solution to rabbitmq startup issues](https://github.com/zulip/zulip/issues/465)
* [Add a mechanism for deleting early test messages](https://github.com/zulip/zulip/issues/135)
* [Merge a supported way to use Zulip in Docker in production
implementation](https://github.com/zulip/zulip/pull/450).
## Internationalization
The core Zulip UI has been mostly translated into 5 languages;
however, more work is required to make those translations actually
displayed in the Zulip UI for the users who would benefit from them.
* [Merge support for using translations in Django templates](https://github.com/zulip/zulip/pull/607)
* [Add text in handlebars templates to translatable string database](https://github.com/zulip/zulip/issues/726)
* [Merge support for translating text in handlebars](https://github.com/zulip/zulip/issues/726)
* [Add text in error messages to translatable strings](https://github.com/zulip/zulip/issues/727)
## User Experience at scale
There are a few parts of the Zulip UI which could benefit from
overhauls designed around making the user experience nice for large
teams.
* [Make the buddy list work better for large teams](https://github.com/zulip/zulip/issues/236)
* [Improve @-mentioning syntax based on stronger unique identifiers](https://github.com/zulip/zulip/issues/374)
* [Show subscriber counts on streams](https://github.com/zulip/zulip/pull/525)
* [Make the streams page easier to navigate with 100s of streams](https://github.com/zulip/zulip/issues/563)
* [Add support for filtering long lists of streams](https://github.com/zulip/zulip/issues/565)
## Administration and management
Currently, Zulip has a number of administration features that can be
controlled only via the command line.
* [Make default streams web-configurable](https://github.com/zulip/zulip/issues/665)
* [Make realm emoji web-configurable](https://github.com/zulip/zulip/pull/543)
* [Make realm filters web-configurable](https://github.com/zulip/zulip/pull/544)
* [Make realm aliases web-configurable](https://github.com/zulip/zulip/pull/651)
* [Enhance the LDAP integration and make it web-configurable](https://github.com/zulip/zulip/issues/715)
* [Add a SAML integration for Zulip](https://github.com/zulip/zulip/issues/716)
* [Improve administrative controls for managing streams](https://github.com/zulip/zulip/issues/425)
## Scalability
Zulip should support 10000 users in a realm and also support smaller
realms in more resource-constrained environments (probably a good
initial goal is working well with only 2GB of RAM).
* [Make the Zulip Tornado service support horizontal scaling](https://github.com/zulip/zulip/issues/445)
* [Make presence system scale well to 10000 users in a realm.](https://github.com/zulip/zulip/issues/728)
* [Support running queue workers multithreaded in production to
decrease minimum memory footprint](https://github.com/zulip/zulip/issues/34)
## Performance
Performance is essential for a communication tool. While some things
are already quite good (E.g. narrowing and message sending is speedy),
this is an area where one can always improve. There are a few known
performance opportunities:
* [Migrate to faster jinja2 templating engine](https://github.com/zulip/zulip/issues/620)
* [Don't load zxcvbn when it isn't needed](https://github.com/zulip/zulip/issues/263)
* [Optimize the frontend performance of loading the Zulip webapp using profiling](https://github.com/zulip/zulip/issues/714)
## Technology improvements
Zulip should be making use of the best Python/Django tools available.
* [Add support for Zulip running on Python 3](https://github.com/zulip/zulip/issues/256)
* [Add support for changing users' email addresses](https://github.com/zulip/zulip/issues/734)
* [Automatic thumbnailing of uploaded images](https://github.com/zulip/zulip/issues/432)
* [Upgrade Zulip to use Django 1.10 once it is released. The patches
needed to run Zulip were merged into mainline Django in Django 1.10,
so this will mean we don't need to use a fork of Django anymore.](https://github.com/zulip/zulip/issues/3)
## Technical Debt
While the Zulip server has a great codebase compared to most projects
of its size, it takes work to keep it that way.
* [Migrate most web routes to REST API](https://github.com/zulip/zulip/issues/611)
* [Finish purging global variables from the Zulip javascript](https://github.com/zulip/zulip/issues/610)
* [Finish deprecating and remove the pre-REST Zulip /send_message API](https://github.com/zulip/zulip/issues/730)
* [Split Tornado subsystem into a separate Django app](https://github.com/zulip/zulip/issues/729)
* [Clean up clutter in the root of the zulip.git repository](https://github.com/zulip/zulip/issues/707)
* [Refactor zulip.css to be broken into components](https://github.com/zulip/zulip/issues/731)
## Deployment and upgrade process
* [Support backwards-incompatible upgrades to Python libraries](https://github.com/zulip/zulip/issues/717)
* [Minimize the downtime required in Zulip upgrade process](https://github.com/zulip/zulip/issues/646)
## Security
* [Add support for 2-factor authentication on all platforms](https://github.com/zulip/zulip/pull/451)
* [Add a retention policy feature that automatically deletes old messages](https://github.com/zulip/zulip/issues/106)
* [Upgrade every Zulip dependency to a modern version](https://github.com/zulip/zulip/issues/717)
* [The LOCAL_UPLOADS_DIR file uploads backend only supports world-readable uploads](https://github.com/zulip/zulip/issues/320)
* [Add support for stronger security controls for uploaded files](https://github.com/zulip/zulip/issues/320)
## Testing
* [Extend Zulip's automated test coverage to include all API endpoints](https://github.com/zulip/zulip/issues/732)
* [Build automated tests for the client API bindings](https://github.com/zulip/zulip/issues/713)
* [Add Python static type-checking to Zulip using mypy](https://github.com/zulip/zulip/issues/733)
* [Improve the runtime of Zulip's backend test suite](https://github.com/zulip/zulip/issues/441)
* [Use caching to make Travis CI runtimes faster](https://github.com/zulip/zulip/issues/712)
* [Add automated tests for the production upgrade process](https://github.com/zulip/zulip/issues/306)
* [Improve Travis CI "production" test suite to catch more regressions](https://github.com/zulip/zulip/issues/598)
## Development environment
* [Migrate from jslint to eslint](https://github.com/zulip/zulip/issues/535)
* [Figure out a nice upgrade process for Zulip Vagrant VMs](https://github.com/zulip/zulip/issues/264)
* [Overhaul new contributor documentation](https://github.com/zulip/zulip/issues/677)
* [Replace closure-compiler with a faster minifier toolchain](https://github.com/zulip/zulip/issues/693)
* [Add support for building frontend features in React](https://github.com/zulip/zulip/issues/694)
* [Use a javascript bundler like webpack](https://github.com/zulip/zulip/issues/695)
## Documentation
* [Significantly expand documentation of the Zulip API and integrating
with Zulip.](https://github.com/zulip/zulip/issues/672)
* [Expand library of documentation on Zulip's feature set. Currently
most documentation is for either developers or system administrators.](https://github.com/zulip/zulip/issues/675)
* [Expand developer documentation with more tutorials explaining how to do
various types of projects.](https://github.com/zulip/zulip/issues/676)
* [Overhaul new contributor documentation, especially on coding style,
to better highlight and teach the important pieces.](https://github.com/zulip/zulip/issues/677)
* [Update all screenshots to show the current Zulip UI](https://github.com/zulip/zulip/issues/599)
## Integrations
Integrations are essential to Zulip. While we currently have a
reasonably good framework for writing new webhook integrations for
getting notifications into Zulip, it'd be great to streamline that
process and make bots that receive messages just as easy to build.
* [Make it super easy to take screenshots for new webhook integrations](https://github.com/zulip/zulip/issues/658)
* [Add an outgoing webhook integration system](https://github.com/zulip/zulip/issues/735)
* [Build a framework to cut duplicated code in new webhook integrations](https://github.com/zulip/zulip/issues/660)
* [Make setting up a new integration a smooth flow](https://github.com/zulip/zulip/issues/692)
* [Optimize the integration writing documentation to make writing new
ones really easy.](https://github.com/zulip/zulip/issues/70)
## Android app
The Zulip Android app is ahead of the iOS app in terms of feature set,
so this section serves to document the goals for Zulip on mobile.
* [Support using a non-zulip.com server](https://github.com/zulip/zulip-android/issues/1)
* [Support Google authentication with a non-Zulip.com server](https://github.com/zulip/zulip-android/issues/49)
* [Add support for narrowing to @-mentions](https://github.com/zulip/zulip-android/issues/39)
* [Support having multiple Zulip realms open simultaneously](https://github.com/zulip/zulip-android/issues/47)
* [Build a slick development login page to simplify testing (similar to
the development homepage on web)](https://github.com/zulip/zulip-android/issues/48)
* [Improve the compose box to let you see what you're replying to](https://github.com/zulip/zulip-android/issues/8)
* [Make it easy to compose messages with mentions, emoji, etc.](https://github.com/zulip/zulip-android/issues/11)
* [Display unread counts and improve navigation](https://github.com/zulip/zulip-android/issues/57)
* [Hide messages sent to muted topics](https://github.com/zulip/zulip-android/issues/9)
* [Fill out documentation to make it easy to get started](https://github.com/zulip/zulip-android/issues/58)
## iOS app
Most of the projects listed under Android apply here as well, but it's
worth highlighting some areas where iOS is substantially behind
Android. The top priority here is recruiting a lead developer for the
iOS app. Once we have that resolved, we'll expand our ambitions for
the app with more specific improvements.
* [iOS app needs maintainer](https://github.com/zulip/zulip-ios/issues/12)
* [APNS notifications are broken](https://github.com/zulip/zulip/issues/538)
## Desktop apps
The top goal for the desktop apps is to rebuild it in modern toolchain
(probably Electron) so that it's easy for a wide range of developers
to contribute to the apps.
* Migrate platform from QT/webkit to Electron
* Desktop app doesn't recover well from entering the wrong Zulip server
* Support having multiple Zulip realms open simultaneously
* Build an efficient process for testing and releasing new versions of
the desktop apps
## Community
These don't get GitHub issues since they're not technical projects,
but they are important goals for the project.
* Setup a Zulip server for the Zulip development community
* Expand the number of core developers able to do code reviews
* Expand the number of contributors regularly adding features to Zulip
* Have a successful summer with Zulip's 3 GSOC students

23
docs/schema-migrations.md Normal file
View File

@@ -0,0 +1,23 @@
# Schema Migrations
Zulip uses the [standard Django system for doing schema
migrations](https://docs.djangoproject.com/en/1.8/topics/migrations/).
There is some example usage in the Zulip new feature tutorial on
readthedocs.
This page documents some important issues related to writing schema
migrations.
* **Large tables**: For large tables like Message and UserMessage, you
want to take precautions when adding columns to the table,
performing data backfills, or building indexes. We have a
`zerver/lib/migrate.py` library to help with adding columns and
backfilling data. For building indexes on these tables, we should do
this using SQL with postgres's CONCURRENTLY keyword.
* **Numbering conflicts across branches**: If you've done your schema
change in a branch, and meanwhile another schema change has taken
place, Django will now have two migrations with the same number. To
fix this, you can just rename the file, as long as no other
migrations depend on it (in which case you also need to update the
dependencies).

View File

@@ -15,7 +15,7 @@ Schema and initial data changes
-------------------------------
If you change the database schema or change the initial test data, you
have have to regenerate the pristine test database by running
have to regenerate the pristine test database by running
``tools/do-destroy-rebuild-test-database``.
Wiping the test databases
@@ -53,13 +53,13 @@ it. On Ubuntu:
Backend Django tests
--------------------
These live in ``zerver/tests.py`` and ``zerver/test_*.py``. Run them
with ``tools/test-backend``.
These live in ``zerver/tests/tests.py`` and
``zerver/tests/test_*.py``. Run them with ``tools/test-backend``.
Web frontend black-box tests
----------------------------
Web frontend black-box casperjs tests
-------------------------------------
These live in ``zerver/tests/frontend/tests/``. This is a "black box"
These live in ``frontend_tests/casper_tests/``. This is a "black box"
test; we load the frontend in a real (headless) browser, from a real dev
server, and simulate UI interactions like sending messages, narrowing,
etc.
@@ -67,8 +67,63 @@ etc.
Since this is interacting with a real dev server, it can catch backend
bugs as well.
You can run this with ``./zerver/tests/frontend/run``. You will need
`PhantomJS <http://phantomjs.org/>`__ 1.7.0 or later.
You can run this with ``./tools/test-js-with-casper`` or as
``./tools/test-js-with-casper 05-settings.js`` to run a single test
file from ``frontend_tests/casper_tests/``.
Writing Casper tests
~~~~~~~~~~~~~~~~~~~~
Probably the easiest way to learn how to write Casper tests is to
study some of the existing test files. There are a few tips that can
be useful for writing Casper tests in addition to the debugging notes
below:
- Run just the file containing your new tests as described above to
have a fast debugging cycle.
- With frontend tests in general, it's very important to write your
code to wait for the right events. Before essentially every action
you take on the page, you'll want to use ``waitForSelector``,
``waitUntilVisible``, or a similar function to make sure the page or
elemant is ready before you interact with it. For instance, if you
want to click a button that you can select via ``#btn-submit``, and
then check that it causes ``success-elt`` to appear, you'll want to
write something like:
::
casper.waitForSelector("#btn-submit", function () {
casper.click('#btn-submit')
casper.test.assertExists("#success-elt");
});
This will ensure that the element is present before the interaction
is attempted. The various wait functions supported in Casper are
documented in the Casper here:
http://docs.casperjs.org/en/latest/modules/casper.html#waitforselector
and the various assert statements available are documented here:
http://docs.casperjs.org/en/latest/modules/tester.html#the-tester-prototype
- Casper uses CSS3 selectors; you can often save time by testing and
debugigng your selectors on the relevant page of the Zulip
development app in the Chrome javascript console by using
e.g. ``$$("#settings-dropdown")``.
- The test suite uses a smaller set of default user accounts and other
data initialized in the database than the development environment;
to see what differs check out the section related to
``options["test_suite"]`` in
``zilencer/management/commands/populate_db.py``.
- Casper effectively runs your test file in two phases -- first it
runs the code in the test file, which for most test files will just
collect a series of steps (each being a ``casper.then`` or
``casper.wait...`` call). Then, usually at the end of the test
file, you'll have a ``casper.run`` call which actually runs that
series of steps. This means that if you write code in your
test file outside a ``casper.then`` or ``casper.wait...`` method, it
will actually run before all the Casper test steps that are declared
in the file, which can lead to confusing failures where the new code
you write in between two ``casper.then`` blocks actually runs before
either of them. See this for more details about how Casper works:
http://docs.casperjs.org/en/latest/faq.html#how-does-then-and-the-step-stack-work
Debugging Casper.JS
~~~~~~~~~~~~~~~~~~~
@@ -78,7 +133,7 @@ is not perfect. Here are some steps for using it and gotchas you might
want to know.
To turn on remote debugging, pass ``--remote-debug`` to the
``./zerver/frontend/tests/run`` script. This will run the tests with
``./frontend_tests/tests/run`` script. This will run the tests with
port ``7777`` open for remote debugging. You can now connect to
``localhost:7777`` in a Webkit browser. Somewhat recent versions of
Chrome or Safari might be required.
@@ -97,6 +152,23 @@ you set a breakpoint and it is hit, the inspector will pause and you can
do your normal JS debugging. You can also put breakpoints in the Zulip
webpage itself if you wish to inspect the state of the Zulip frontend.
If you need to use print debugging in casper, you can do using
``casper.log``; see http://docs.casperjs.org/en/latest/logging.html
for details.
An additional debugging technique is to enable verbose mode in the
Casper tests; you can do this by adding to the top of the relevant
test file the following:
::
var casper = require('casper').create({
verbose: true,
logLevel: "debug"
});
This can sometimes give insight into exactly what's happening.
Web frontend unit tests
-----------------------
@@ -114,7 +186,7 @@ bottom of ``foobar.js``:
This makes ``foobar.js`` follow the CommonJS module pattern, so it can
be required in Node.js, which runs our tests.
Now create ``zerver/tests/frontend/node/foobar.js``. At the top, require
Now create ``frontend_tests/node_tests/foobar.js``. At the top, require
the `Node.js assert module <http://nodejs.org/api/assert.html>`__, and
the module you're testing, like so:
@@ -140,12 +212,12 @@ asserts, the *actual* value comes first, the *expected* value second.
}());
The test runner (index.js) automatically runs all .js files in the
zerver/tests/frontend/node directory.
frontend_tests/node directory.
.. _handling-dependencies:
Handling dependencies in tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Handling dependencies in unit tests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following scheme helps avoid tests leaking globals between each
other.
@@ -249,3 +321,47 @@ Setting up the manual testing database
Will populate your local database with all the usual accounts plus some
test messages involving Shakespeare characters.
(This is run automatically as part of the development environment setup
process.)
Javascript manual testing
-------------------------
`debug.js` has some tools for profiling Javascript code, including:
- `print_elapsed_time`: Wrap a function with it to print the time that
function takes to the javascript console.
- `IterationProfiler`: Profile part of looping constructs (like a for
loop or $.each). You mark sections of the iteration body and the
IterationProfiler will sum the costs of those sections over all
iterations.
Chrome has a very good debugger and inspector in its developer tools.
Firebug for Firefox is also pretty good. They both have profilers, but
Chrome's is a sampling profiler while Firebug's is an instrumenting
profiler. Using them both can be helpful because they provide
different information.
Python 3 Compatibility
======================
Zulip is working on supporting Python 3, and all new code in Zulip
should be Python 2+3 compatible. We have converted most of the
codebase to be compatible with Python 3 using a suite of 2to3
conversion tools and some manual work. In order to avoid regressions
in that compatibility as we continue to develop new features in zulip,
we have a special tool, `tools/check-py3`, which checks all code for
Python 3 syntactic compatibility by running a subset of the automated
migration tools and checking if they trigger any changes.
`tools/check-py3` is run automatically in Zulip's Travis CI tests to
avoid any regressions, but is not included in `test-all` since it is
quite slow.
To run `tooks/check-py3`, you need to install the `modernize` and
`future` python packages (which are in the development environment's
`requirements.txt` file).
To run `check-py3` on just the python files in a particular directory,
you can change the current working directory (e.g. `cd zerver/`) and
run `check-py3` from there.

19
docs/translating.md Normal file
View File

@@ -0,0 +1,19 @@
# Translating Zulip
Zulip has full support for unicode, so you can already use your
preferred language everywhere in Zulip.
To make Zulip even better for users around the world, the Zulip UI is
being translated into a number of major languages, including Spanish,
German, French, Chinese, Russian, and Japanese, with varying levels of
progress. If you speak a language other than English, your help with
translating Zulip would be greatly appreciated!
If you're interested in contributing translations to Zulip, join the
[Zulip project on Transifex](https://www.transifex.com/zulip/zulip/)
and ask to join any languages you'd like to contribute to (or add new
ones). Transifex's notification system sometimes fails to notify the
maintainers when you ask to join a project, so please send a quick
email to zulip-core@googlegroups.com when you request to join the
project or add a language so that we can be sure to accept your
request to contribute.

2
frontend_tests/casper_lib/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/server.log
/test_credentials.js

View File

@@ -2,7 +2,7 @@ var common = (function () {
var exports = {};
var test_credentials = require('../test_credentials.js').test_credentials;
var test_credentials = require('../casper_lib/test_credentials.js').test_credentials;
function timestamp() {
return new Date().getTime();
@@ -129,11 +129,11 @@ exports.then_send_message = function (type, params) {
else {
casper.test.assertTrue(false, "send_message got valid message type");
}
casper.fill('form[action^="/json/send_message"]', params);
casper.fill('form[action^="/json/messages"]', params);
casper.click('#compose-send-button');
});
casper.waitFor(function emptyComposeBox() {
return casper.getFormValues('form[action^="/json/send_message"]').content === '';
return casper.getFormValues('form[action^="/json/messages"]').content === '';
}, function () {
last_send_or_update = timestamp();
});

View File

@@ -1,4 +1,4 @@
var common = require('../common.js').common;
var common = require('../casper_lib/common.js').common;
// Start of test script.
casper.start('http://localhost:9981/', common.initialize_casper);

View File

@@ -10,7 +10,7 @@
// For example, utils.dump() prints an Object with nice formatting.
var utils = require('utils');
var common = require('../common.js').common;
var common = require('../casper_lib/common.js').common;
common.start_and_log_in();

View File

@@ -1,4 +1,4 @@
var common = require('../common.js').common;
var common = require('../casper_lib/common.js').common;
common.start_and_log_in();
@@ -20,7 +20,7 @@ common.then_send_many([
{ stream: 'Verona', subject: 'other subject',
content: 'test message C' },
{ stream: 'Venice', subject: 'frontend test',
{ stream: 'Denmark', subject: 'frontend test',
content: 'other message' },
{ recipient: 'cordelia@zulip.com, hamlet@zulip.com',
@@ -83,7 +83,7 @@ function expect_stream_subject() {
function expect_subject() {
common.expected_messages('zfilt', [
'Verona > frontend test',
'Venice > frontend test',
'Denmark > frontend test',
'Verona > frontend test'
], [
'<p>test message A</p>',
@@ -125,12 +125,20 @@ function expect_all_pm() {
]);
}
function check_narrow_title(title) {
return function () {
// need to get title tag from HTML
// test if it's equal to some string passed in to function
casper.test.assertSelectorHasText('title', title, 'Got expected narrow title');
};
}
function un_narrow() {
casper.then(common.un_narrow);
casper.then(expect_home);
casper.then(check_narrow_title('home - Zulip Dev - Zulip'));
}
// Narrow by clicking links.
common.wait_for_receive(function () {
@@ -141,6 +149,7 @@ common.wait_for_receive(function () {
casper.waitUntilVisible('#zfilt', function () {
expect_stream();
});
casper.then(check_narrow_title('Verona - Zulip Dev - Zulip'));
un_narrow();
casper.waitUntilVisible('#zhome', function () {
@@ -148,6 +157,7 @@ casper.waitUntilVisible('#zhome', function () {
casper.test.info('Narrowing by clicking subject');
casper.click('*[title="Narrow to stream \\\"Verona\\\", topic \\\"frontend test\\\""]');
});
casper.then(check_narrow_title('frontend test - Zulip Dev - Zulip'));
casper.waitUntilVisible('#zfilt', function () {
expect_stream_subject();
@@ -163,6 +173,7 @@ casper.waitUntilVisible('#zhome', function () {
casper.click('*[title="Narrow to your private messages with Cordelia Lear, King Hamlet"]');
});
casper.then(check_narrow_title('private - Zulip Dev - Zulip'));
casper.waitUntilVisible('#zfilt', function () {
expect_huddle();
@@ -205,32 +216,39 @@ function do_search(str, item) {
});
}
function search_and_check(str, item, check) {
function search_and_check(str, item, check, narrow_title) {
do_search(str, item);
casper.then(check);
casper.then(check_narrow_title(narrow_title));
un_narrow();
}
casper.waitUntilVisible('#zhome', expect_home);
// Test stream / recipient autocomplete in the search bar
search_and_check('Verona', 'Narrow to stream', expect_stream);
search_and_check('Cordelia', 'Narrow to private', expect_1on1);
search_and_check('Verona', 'Narrow to stream', expect_stream,
'Verona - Zulip Dev - Zulip');
search_and_check('Cordelia', 'Narrow to private', expect_1on1,
'private - Zulip Dev - Zulip');
// Test operators
search_and_check('stream:verona', 'Narrow', expect_stream);
search_and_check('stream:verona subject:frontend+test', 'Narrow', expect_stream_subject);
search_and_check('subject:frontend+test', 'Narrow', expect_subject);
search_and_check('stream:Verona', 'Narrow', expect_stream,
'Verona - Zulip Dev - Zulip');
search_and_check('stream:Verona subject:frontend+test', 'Narrow', expect_stream_subject,
'frontend test - Zulip Dev - Zulip');
search_and_check('subject:frontend+test', 'Narrow', expect_subject,
'home - Zulip Dev - Zulip');
// Narrow by clicking the left sidebar.
casper.then(function () {
casper.test.info('Narrowing with left sidebar');
});
casper.thenClick('#stream_filters [data-name="Verona"] a', expect_stream);
casper.then(check_narrow_title('Verona - Zulip Dev - Zulip'));
casper.thenClick('#global_filters [data-name="home"] a', expect_home);
casper.then(check_narrow_title('home - Zulip Dev - Zulip'));
casper.thenClick('#global_filters [data-name="private"] a', expect_all_pm);
casper.then(check_narrow_title('private - Zulip Dev - Zulip'));
un_narrow();

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