Compare commits

...

2913 Commits
1.4.3 ... 1.5.0

Author SHA1 Message Date
Tim Abbott
e79520c593 Release Zulip Server 1.5.0. 2017-02-06 21:15:17 -08:00
Rishi Gupta
27055bdd49 analytics: Use plotly-basic.js instead of plotly.js.
It's 600kb (minified) instead of 1.8mb.
2017-02-06 21:14:24 -08:00
Rishi Gupta
86b45b57df analytics: Fix rangeselector buttons for messages_sent_over_time.
Previously was using the daily_rangeselector regardless of whether we
started in the daily or weekly view.
2017-02-06 17:48:56 -08:00
Tim Abbott
d71f2e7b9b update-prod-static: Don't ship node_modules.
This saves more than 50MB of unnecessary duplicate content in release
tarballs (the static assets that will actually be served have already
been built at this point by tools/minify-js).
2017-02-06 17:21:34 -08:00
Tim Abbott
babb6aaa47 settings: Stop serving zxcvbn from node_modules/.
Now that we have the minified_source_filenames feature, we don't need
to serve zxcvbn from node_modules/ directly to avoid re-minifying it.

Moving this this allows us to stop shipping the (duplicate)
node_modules directory in release tarballs, which will save many
megabytes of unnecessary increase in our release tarball size.
2017-02-06 17:21:34 -08:00
Tim Abbott
e2ee1951e0 storage: Fix static files storage reuse issues.
Zulip's previous model for managing static asset files via Django
pipeline had some broken behavior around upgrades.  In particular, it
was for some reason storing the information as to which static files
should be used in a memcached cache that was shared between different
deployments of Zulip.  This means that during the upgrade process,
some clients might be served a version of the static assets that does
not correspond to the server they were connected to.

We've replaced that model with using ManifestStaticFilesStorage, which
instead allows each Zulip deployment directory to have its own
complete copy of the mapping of files to static assets, as it should
be.

We have to do a little bit of hackery with the staticfiles.json path
to make this work, basically because Django expects staticfiles.json
to be under STATIC_ROOT (aka the path nginx is serving to users), but
doing that doesn't really make sense for Zulip, since that directory
is shared between different deployments.
2017-02-06 16:10:24 -08:00
Steve Howell
0ab832cc49 bug fix: Clean up blue highlighting in the left corner.
In a96fdd18b1, I introduced a few
regressions related to the blue highlighting that happens
in the top left corner for Home, Private messages, Starred
messages, and @-mentions.  Basically, we weren't clearing
the highlighting when we thought we were, so Home would stay
blue too long and the other filters wouldn't turn blue.

We went a surprising long time before noticing the regression.
This fix adds a function called deselect_top_left_corner_items()
to clear the blue backgrounds, so that will happen more explicitly.

And then I restored a line of code to pm_list.js that puts the
blue in place when you are in an is:private narrow (vs. a
specific PM narrow).
2017-02-06 16:10:24 -08:00
Tim Abbott
70388b17d2 puppet: Add missing dependency on ssl-cert. 2017-02-06 15:51:38 -08:00
Tim Abbott
975ede6c83 README: Fix Zulip docs badge. 2017-02-06 15:50:24 -08:00
Tim Abbott
6c4eaf3d14 analytics: Map client names to user-facing versions.
This makes the pie charts on /stats more readable.
2017-02-05 22:19:10 -08:00
Tim Abbott
28a123f00e webhooks: Fix spelling of GitHub webhook client name.
This will make the Zulip analytics on /stats be consistent with the
old integration.
2017-02-05 16:26:12 -08:00
Cynthia Lin
ac4d551b32 user docs: Conform *Reply to a message* to user docs styling guide. 2017-02-05 15:19:44 -08:00
Cynthia Lin
362001eb9d user docs: Make minor edits to *Add a bot or integration* doc. 2017-02-05 15:19:44 -08:00
Cynthia Lin
1ec5f01e4d user docs: Make minor edits to *Edit or delete a message* doc. 2017-02-05 15:19:44 -08:00
Cynthia Lin
ee7fc103aa user docs: Make minor edits to *Make an announcement* doc. 2017-02-05 15:19:44 -08:00
Cynthia Lin
d634cdbefe user docs: Make minor edits to *Join a Zulip organization* doc. 2017-02-05 15:19:44 -08:00
Cynthia Lin
862f501818 user docs: Make minor edits to *Signing out* doc. 2017-02-05 15:19:44 -08:00
khantaalaman
c3fd0d4e0c subs: Fix incorrect use of RegExp in stream filtering.
When filtering streams, we were incorrectly treating the regexp input
provided by the user as a regular expression, meaning that terms like
`c++` would trigger errors because they are invalid regular expression
syntax.  We fix this by replacing RegExp with a simple IndexOf check.

Node test added by tabbott.

Fixes #3559.
2017-02-05 13:01:43 -08:00
khantaalaman
b82104a769 message-view: Uncollapsing using [More...] made easier.
The [More...] link for un-collapsing messages has been made easier to
click, by giving it a top margin which prevent clicks on the top
portion of it from being masked by the top part of the message body.

Fixes #3313.
2017-02-05 12:48:12 -08:00
Tim Abbott
c1f0ed5637 update-authors-json: Improve error handling. 2017-02-05 12:34:05 -08:00
Rishi Gupta
e5441af2c3 analytics: Add word wrap to pie chart legend text. 2017-02-04 00:24:09 -08:00
Rishi Gupta
12e8373692 analytics: Change pie chart colors to be more differentiated. 2017-02-04 00:22:39 -08:00
Amy Liu
24f0716df3 analytics: Clean up graph styling.
This fixes a number of issues in the prototype /stats graphs, including:

* Adding a Total Users number to the Users graph.
* Changing the Messages sent over time graph so that the bot
trace is hidden by default.
* Fades out the last bars in the weekly view to represent unfinished
ata.
* Sets the default view to weekly only if the realm is > 12 weeks old.
* Gets rid of the tooltips and replaces them with hover text
for the Number of Users graph.
* Fixes a bug in the legend colors for the Messages Over Time
graph.
* It also adds the year to the hover text.
* Sets the pie chart colors and adds spaces between sectors.
* Changes the font to Humbug.
2017-02-03 17:17:23 -08:00
Tim Abbott
12e7be585d i18n: Fix compilemessages processing extra files in production.
In a Zulip production environment, STATIC_ROOT points to the shared
directory that static assets are served from, and so the
compilemessages management command was trying to process every
historical version in there.
2017-02-03 17:17:23 -08:00
Steve Howell
6e2189f134 bugdown: Disable link previews when bots send messages.
We do not use `get_link_embed_data` for messsages sent by
bots, as bots often repeat the same URL over and over again
and are generally either text-focused or have their own
mechanisms to provide preview content.

Fixes #2968.
2017-02-03 17:08:23 -08:00
Steve Howell
709493cd75 Pass in sent_by_bot flag to bugdown parser.
We will use this flag to suppress certain url previews
for bots.
2017-02-03 17:07:38 -08:00
Tim Abbott
4abb6724d0 changelog: Fix a typo in setting name. 2017-02-03 16:34:46 -08:00
Tim Abbott
d6c21c7142 docs: Improve translating guide clarity.
This corrects a few details and increases the billing of writing a
translating style guide.
2017-02-03 14:45:56 -08:00
Yago González
00a9f68eea docs: Improve the translation guide. 2017-02-03 14:38:52 -08:00
Tim Abbott
c4ba971247 casper: Fix test failures in 06-settings due to new translations. 2017-02-03 14:32:05 -08:00
Tim Abbott
a889346c9f Remove zh_CN old Django name for Chinese. 2017-02-03 14:29:03 -08:00
Steve Howell
89b9c5eece blueslip: Avoid blueslip spam for failed email lookups.
If an email lookup fails, we now wait for five seconds before
doing a blueslip.error() call (after re-checking the email).
2017-02-03 13:02:26 -08:00
Tim Abbott
633d4d1882 docs: Update customization docs slightly for Zulip 1.5.
There's more we'll want to do here now that we have /help/, but this
is a good start.
2017-02-03 12:57:50 -08:00
Tim Abbott
21f09dcab7 docs: Make it harder to screw up our manage.py commands. 2017-02-03 12:57:50 -08:00
Tim Abbott
43d343027b Update translations for Zulip 1.5 release. 2017-02-03 12:32:04 -08:00
hackerkid
90f8eb7c52 Add tool for scanning issues without area labels.
Fixes #3495
2017-02-03 09:59:35 -08:00
Tim Abbott
fa02dfdff4 mobile: Add an endpoint for checking compatibility. 2017-02-03 09:55:34 -08:00
K.Kanakhin
cb1d61cae0 run-dev: Add pid file to development server.
- Add pid file of development processes group, which allows to
  manage development processes group with os utils. Also it allows to
  kill subprocesses  when parent process was closed incorrectly.
- Add tool 'stop_dev_server' to stop development server by pid file.

Fixes #1547
2017-02-02 21:07:03 -08:00
Steve Howell
bcfe1bcdbe linters: Handle comments better in template parser.
We now properly parse HTML comments that have HTML
block tags or handlebars/Django blocks within them.
2017-02-02 20:55:43 -08:00
Rishi Gupta
aafb1c70f0 analytics: Fix pie chart sorting computations in stats.js. 2017-02-02 18:19:48 -08:00
Tim Abbott
621e3f68ba docs: Update changelog. 2017-02-02 17:44:17 -08:00
Tim Abbott
70e75508ba settings: Include analytics in default distribution.
This moves the analytics module from being a default-off module that
is somewhat difficult to install to being a default part of the
Zulip distribution (both tarballs and what is enabled by default).
2017-02-02 16:23:24 -08:00
Tim Abbott
161522e04c analytics: Add comment explaining server admin routes. 2017-02-02 16:23:10 -08:00
Tim Abbott
27112b1e08 lint: Pin version of eslint to 3.9.1.
This indirectly works around an issue with acorn version 4.0.5 that
in turn causes eslint to hang forever.
2017-02-02 15:25:44 -08:00
Tomasz Kolek
7bcba19e99 Add handling synchronize PR event to github webhook integration. 2017-02-02 12:33:08 -08:00
Steve Howell
5b8cc03c61 bugdown: Restore data-user-email to user mention spans.
(The commit q7ef4e40258280e202325c9295579c93fb948b replaced
data-user-email with data-user-id, but we still need to
support data-user-email for old clients like non-updated
androids and we still want to start the migration forward
to data-user-id.)
2017-02-02 12:32:18 -08:00
Cynthia Lin
17ad591eb4 docs: Fix bullet formatting and indenting. 2017-02-02 12:25:58 -08:00
Cynthia Lin
0efb806861 portico: Add links to 'Features' and 'User documentation' pages. 2017-02-02 12:25:58 -08:00
Cynthia Lin
944b809fd7 docs: Replace "search help" with "search operators".
For better clarification and to avoid confusion with user documentation tab.
2017-02-02 12:25:58 -08:00
Brock Whittaker
377592802c hashchange: Fix exiting #subscriptions overlay not updating hash.
This applies fixes a bug where if a user used the Esc key, the
subscriptions hash did not get restored to its previous state.
2017-02-02 12:13:08 -08:00
khantaalaman
8c7321abad compose: Show restore-draft option in write mode only.
Fixes #3491.
2017-02-02 11:42:56 -08:00
brockwhittaker
830f3e76b6 Change all '1' (warn) flags to '0' in eslint.
This changes all warn flags to no-warn because warn flags currently
are not tracked nor monitored by the linter but do show up on a
line-by-line basis in text editors using the eslint plugin which
ends up causing a lot of noise.
2017-02-02 11:41:39 -08:00
brockwhittaker
894f0b5bf0 Fix hashchange closing #subscriptions on IE.
This fixes an issue where Array.prototype.split is called on an
undefined instance due to the EventTarget.oldURL property not being
recorded in IE. We fix this by recording it ourselves.
2017-02-02 11:40:26 -08:00
Rishi Gupta
5eb5fa3f31 analytics: Change time_range to not include current day/hour.
Current day/hour will always be 0, since we haven't computed it yet for the
CountStat tables.
2017-02-02 10:59:52 -08:00
Rishi Gupta
2bd214077b analytics: Limit pie charts to 6 segments. 2017-02-02 09:20:53 +00:00
Tim Abbott
e8b0880320 analytics: Log updates to analytics counts. 2017-02-01 17:02:46 -08:00
umkay
76f3d02590 analytics: Add cron job to run analytics jobs.
This adds a cron job to update the Zulip analytics counts, complete
with locking etc.

Substantially tweaked by tabbott.
2017-02-01 17:02:46 -08:00
Rishi Gupta
92e8cad42a dev login page: Add all non-zulip users as community users.
We create a new realm and user when running populate_analytics_db.py, in a
realm that is neither 'zulip' nor 'simple'.
2017-02-01 16:10:11 -08:00
Tim Abbott
b7df84d5a8 analytics: Add indexes to optimize performance of aggregation.
These indexes fix some slow queries used in updating the analytics
tables, resulting in the analytics system consuming far less total
resources.
2017-02-01 15:47:49 -08:00
Steve Howell
5ec4ed0d5c bug fix: Allow renaming streams to different cases.
Before this change, you could not rename a stream
from "denmark" to "Denmark".
2017-02-01 14:20:46 -08:00
brockwhittaker
d38d12db8d Fix for broad ID selector.
This fixes the broad ID selector `*[id]:before` to be a more specific
selection of h{x} tags inside the `.markdown` container.
2017-02-01 11:24:00 -08:00
Steve Howell
2a07b204bf css parser: Show line numbers for errors.
This is a fairly major overhaul of the CSS parser to support
line numbers in error messages.

Basically, instead of passing "slices" of tokens around, we pass
indexes into the token arrays to all of our sub-parsers, which
allows them to have access to previous tokens in certain cases.
This is particularly important for errors where stuff is missing
(vs. being wrong).

In testing this out I found a few more places to catch errors.
2017-02-01 10:02:03 -08:00
Tim Abbott
a03d816983 docs: Update release checklist to mention GitHub. 2017-02-01 09:48:00 -08:00
Amy Liu
0a39e354dc analytics: Add graphs of usage statistics on /stats.
This adds a frontend for the analytics system we've had for a few
months, showing several graphs of the data in Zulip.

There's a ton more that we can do with this tooling, but this initial
version is enough to provide users with a pretty good experience.

Fixes #2052.
2017-01-31 22:18:54 -08:00
Cynthia Lin
2fbe2229a4 portico: Fix portico header covering anchor links.
Fixes issue #3506
2017-01-31 21:54:09 -08:00
Rishi Gupta
783096627c user docs: Change link color to #399993.
Also removes gradient.
2017-01-31 18:17:49 -08:00
Rishi Gupta
d8012c5b7b user docs: Change footer to be less prominent. 2017-01-31 18:17:49 -08:00
Rishi Gupta
89c5ef76b4 user docs: Move Basics and Apps into a Misc category. 2017-01-31 18:17:49 -08:00
Tim Abbott
a64cb1d687 navbar: Add a link to the /help/ site. 2017-01-31 18:15:14 -08:00
Tim Abbott
55e3731707 navbar: Rearrange the icons. 2017-01-31 18:11:54 -08:00
Tim Abbott
daf43c5e4d navbar: Add margin between icons and text. 2017-01-31 18:11:34 -08:00
brockwhittaker
49b150bcb3 navbar: Center icons in gear-menu.
This centers the icons in the gear menu so they are naturally
in line and centered.
2017-01-31 18:11:28 -08:00
Cynthia Lin
056eb8d5c5 docs: Replace all instances of "accessibility" with "privacy" 2017-01-31 18:04:59 -08:00
Cynthia Lin
42487d372e docs: Update *Searching for messages* doc with new UI and features. 2017-01-31 18:04:59 -08:00
brockwhittaker
b37b7de498 Fix the position of the edit message label.
This fixes the position of the "Topic" label to be above
the input and adds a "Content" label to improve consistency.
2017-01-31 17:53:20 -08:00
brockwhittaker
59743a8508 Fix for TravisCI + casper.js race condition.
This changes the markdown preview test to use the
waitForSelectorTextChange method rather than waitWhileVisible
because it was not being generated fast enough in some cases
to show correctly with waitWhileVisible.
2017-01-31 17:53:20 -08:00
Rishi Gupta
7d02a44bc6 user docs: Rename searching-for-messages to search-for-messages. 2017-01-31 17:13:51 -08:00
Rishi Gupta
4be0fd6a6d user docs: Comment out links without articles on index.md. 2017-01-31 17:13:50 -08:00
Rishi Gupta
10810b85ab user docs: Cleanup index in preparation for 1.5. 2017-01-31 17:13:40 -08:00
Tomasz Kolek
3f1b21fe61 Add ping event handling to github webhook integration. 2017-02-01 00:38:16 +01:00
Tomasz Kolek
39bd685dd5 Update How to create jira webhook url in Jira doc. 2017-01-31 15:17:12 -08:00
Tomasz Kolek
11a1f1d72b Add support for old Jira API's version to Jira integration. 2017-01-31 15:17:12 -08:00
Steve Howell
bc20692a91 Prevent tracebacks when admin screens aren't loaded.
Various server events can be passed into admin.js before
the initial widgets have been set up.  This code short
circuits live update code when these events happen.

Note that live updates don't consistently work for the
admin pages before this fix (and after it), since don't
store data changes when the widgets aren't built.
2017-01-31 10:34:06 -08:00
khantaalaman
e72107dec0 left-sidebar: Fix + icon opening stream-search box.
The of stream-search box in left-sidebar was being opened incorrectly
when clicking the + icon to add a new subscription (because that's
what would happen if you clicked the area around the +). Changes were
made in click_handlers.js by adding e.stopPropagation and
e.preventDefault in appropriate click handler.

Fixes #3517.
2017-01-31 10:00:07 -08:00
Brock Whittaker
ebe0aa48a7 Enlargen settings page loading spinner.
Currently the loading spinner on the settings page is too small
and is in the left corner of the parent box. This changes the width
to the same as the main page: 100% fill inside a 38px square container.
2017-01-30 17:51:05 -08:00
Harshit Bansal
59d22e7cb8 realm_emoji: Cleanup an unreachable try/except block.
Fixes: #3515.
2017-01-30 16:43:02 -08:00
Tomasz Kolek
d598fae52e docs: Add missing configuration step to github webhook doc. 2017-01-30 13:02:48 -08:00
Tim Abbott
d7dd158197 test_signup: Fix test failures due to emacs backup files. 2017-01-30 11:55:50 -08:00
Tim Abbott
87337e0d1f test_realm_aliases: Edit new realm alias test for subdomains. 2017-01-30 11:55:50 -08:00
Harshit Bansal
9bbe0efd77 realm_aliases: Add a test for adding an alias which is already claimed.
Fixes: #3514.
2017-01-30 11:55:50 -08:00
Steve Howell
85cee51c68 Extract frontend_tests/node_tests/pm_list.js.
This code used to live in node_tests/stream_list.js.
2017-01-30 11:49:19 -08:00
Steve Howell
373c8a0bb5 Live-update PM list for full-name changes.
We now trigger an event in user_events.js, and we dynamically
build the list of names in pm_list.js by calling out to
people.get_recipients().

We have a few variations of functions that build lists of names
for huddles, which should be cleaned up eventually.  They are
called at different times in the code path, so the different
functions, while doing mostly the same thing, start with different
data sources.
2017-01-30 11:49:19 -08:00
Steve Howell
f836ae0dfb Live-update name changes in the recipient bar.
We now call message_store.get_pm_full_names() when
re-rendering a message list view, rather than reading
msg.display_reply_to, which could be stale.
2017-01-30 11:49:19 -08:00
Steve Howell
2980a9e33d Use user's current full name in recipient bars.
This breaks the function
message_store.get_private_message_recipient into two functions:
get_pm_emails and get_pm_full_names.

The get_pm_emails function behaves the same way as the original
function, but get_pm_full_names now dynamically gets full names
from people.js using the user_id in the message.display_recipient
row.

This makes the recipient bar show the correct new name if you reload
your page.  It doesn't help with live updates.
2017-01-30 11:49:19 -08:00
Steve Howell
a98cbff788 Use user's current full name when rendering messages.
The field message.sender_full_name can be out of date, so
we recompute is using data from people.js in
add_message_metadata().
2017-01-30 11:49:19 -08:00
Steve Howell
97243dcd52 Live update full names for senders in the message pane.
Note that this only works for people who are currently logged in.
Folks that log in after you may pick up the old full name from
the message.  (I'll address this in a separate commit.)
2017-01-30 11:49:19 -08:00
Yago González
a52cd99452 docs: Add book about OSS prod to the reading list. 2017-01-30 11:32:23 -08:00
Steve Howell
00e815e91d Removed duplicates from changelog. 2017-01-30 11:15:28 -08:00
Tim Abbott
b3c9e186f9 help: Clean up change-your-organization-settings. 2017-01-29 23:02:20 -08:00
Cynthia Lin
7766c122b4 docs: Conform *View messages from a stream* to style guide. 2017-01-29 22:57:38 -08:00
Cynthia Lin
c739e6e752 docs: Update *About streams and topics* doc. 2017-01-29 22:56:23 -08:00
synicalsyntax
969b6db7ed docs: Rename documentation URLs and titles to be the same. 2017-01-29 22:56:23 -08:00
Cynthia Lin
41d66f1ddf docs: Conform *Send a group of people a private message* to style guide. 2017-01-29 22:51:54 -08:00
synicalsyntax
26c13a42f8 docs: Conform *Enable or disable Press Enter to send* to style guide.
Also, tabbott made a number of edits to the content.
2017-01-29 22:49:23 -08:00
synicalsyntax
7ea84aa0af docs: Conform *Send a private message* to style guide. 2017-01-29 22:36:48 -08:00
synicalsyntax
8932d46657 docs: Conform *Send a stream message* to style guide. 2017-01-29 22:35:24 -08:00
Tim Abbott
1bbf0f9a98 streams: Consider stream name validation logic. 2017-01-29 22:07:14 -08:00
Tim Abbott
d14037c82e streams: Fix misplaced import. 2017-01-29 22:07:14 -08:00
Tim Abbott
884aa2b184 streams: Eliminate last use of get_stream in views. 2017-01-29 22:07:14 -08:00
Tim Abbott
4d3e97f304 actions: Remove unnecessary do_create_stream function. 2017-01-29 22:07:14 -08:00
Tim Abbott
700089f386 bugdown: Fix need for Internet in test_inline_dropbox_bad. 2017-01-29 22:07:14 -08:00
Tim Abbott
32f778636b streams: Add tests for do_rename_stream error paths. 2017-01-29 20:27:00 -08:00
Tim Abbott
b1c2ff9d05 lint: Ban most use of get_stream from zerver/lib/actions.py. 2017-01-29 20:27:00 -08:00
Tim Abbott
01daa3e91a test_helpers: Move get_subscription out of actions.py.
It's no longer used by anything other than test code.
2017-01-29 20:27:00 -08:00
Tim Abbott
035e442b63 actions: Remove unused set_stream_color method. 2017-01-29 20:27:00 -08:00
Tim Abbott
a3f3f5b7bc remove_default_stream: use access_stream_by_name. 2017-01-29 20:27:00 -08:00
Tim Abbott
19eaa92059 add_default_stream: use access_stream_by_name. 2017-01-29 20:27:00 -08:00
Tim Abbott
de3f539f58 do_change_stream_description: Accept a stream as argument. 2017-01-29 20:27:00 -08:00
Tim Abbott
2dc90e8ebd rename_stream: Pass a stream object to do_rename_stream. 2017-01-29 20:27:00 -08:00
Tim Abbott
7be34357b2 rename_stream: Move stream name taken check to view. 2017-01-29 20:27:00 -08:00
Tim Abbott
ccdf17f47e rename_stream: Move stream already has name check to view. 2017-01-29 20:27:00 -08:00
Tim Abbott
d059a0a90a rename_stream: Move check_stream_name into view. 2017-01-29 20:26:59 -08:00
Tim Abbott
ab1e9f2b97 rename_stream: Move stripping of whitespace to view. 2017-01-29 20:26:59 -08:00
Tim Abbott
4ad1fadab0 streams: Create and use do_change_stream_invite_only. 2017-01-29 20:26:59 -08:00
Tim Abbott
c74ddb74e9 do_make_stream_private: Accept a stream object, not a name. 2017-01-29 20:26:59 -08:00
Tim Abbott
0a75480444 do_make_stream_public: Accept a stream object, not a name. 2017-01-29 20:26:59 -08:00
Tim Abbott
54bcc675f7 subscribe_to_stream: Return the stream object.
This simplifies some code paths a bit.
2017-01-29 20:26:59 -08:00
Tim Abbott
3f83ea3879 lint: Ban use of get_stream in most views files. 2017-01-29 20:26:59 -08:00
Tim Abbott
e137787d1a users: Use access_stream_by_name to access streams.
This simplifies the code somewhat and adds greater consistency of
error messages.
2017-01-29 20:26:59 -08:00
Tim Abbott
ea72b97cd9 home: Cleanup narrow_topic logic. 2017-01-29 20:26:59 -08:00
Tim Abbott
a7cb7dd695 home: Use access_stream_by_name to access streams. 2017-01-29 20:26:59 -08:00
Tim Abbott
6c512bdfd3 json_invite_users: Use access_stream_by_name. 2017-01-29 20:26:59 -08:00
Tim Abbott
bc2f23383e streams: Move list_to_streams to lib. 2017-01-29 20:26:59 -08:00
Tim Abbott
02f5ef1d23 streams: Move filter_stream_authorization to lib. 2017-01-29 20:26:59 -08:00
Tim Abbott
de68dd2860 lint: Ban use of Stream.objects.* in zerver/views. 2017-01-29 20:26:59 -08:00
Tim Abbott
bb86bba20d stream_exists_backend: Use access_stream_by_name. 2017-01-29 20:26:59 -08:00
Tim Abbott
eeeffa8704 urls: Review useless stream_exists_backend endpoints.
The actual function was overcomplicated and was designed to check
whether a stream existed by name, not by ID, so there was no value in
having it be used for checking if a stream existed by ID.
2017-01-29 20:26:59 -08:00
Tim Abbott
46e5b8a9cc streams: Remove unused json_remove_subscriptions. 2017-01-29 20:26:59 -08:00
Tim Abbott
e57e2ee9f1 get_subscribers_backend: Use access_stream_by_id. 2017-01-29 20:26:59 -08:00
Tim Abbott
0d980b7cef json_get_stream_id: Use access_stream_by_name. 2017-01-29 20:26:59 -08:00
Tim Abbott
1ced8d3eb6 get_topics_backend: Use access_stream_by_id. 2017-01-29 20:26:58 -08:00
Tim Abbott
6685885741 deactivate_stream_backend: Use access_stream_by_id. 2017-01-29 20:26:58 -08:00
Tim Abbott
826cc80c9e update_stream_backend: Use access_stream_by_id. 2017-01-29 20:26:58 -08:00
Tim Abbott
de38f3eb94 update_stream_backend: Clean up unnecessary stream_name variable. 2017-01-29 20:26:58 -08:00
Tim Abbott
2cf223470d streams: Eliminate get_subscription_or_die helper function. 2017-01-29 20:26:58 -08:00
Tim Abbott
0af34ee710 streams: Add zerver/lib/streams.py library for security checks.
The goal of this library is to make it a lot easier to prevent bugs
like CVE-2017-0881 by having all of our views logic for fetching a
stream go through a couple carefully tested code paths.
2017-01-29 20:26:58 -08:00
Tim Abbott
de3e96162e middleware: Fix recursive DisallowedHost exceptions. 2017-01-29 20:26:58 -08:00
Tim Abbott
20f3705c00 logging_handlers: Add error handling for invalid hosts. 2017-01-29 19:57:09 -08:00
Tim Abbott
96d3bea6d5 Add changelog from Zulip 1.4.3 release. 2017-01-29 15:32:08 -08:00
Tim Abbott
7ecda1ac8e streams: Fix autosubscribe security bug (CVE-2017-0881).
A bug in Zulip's implementation of the "stream exists" endpoint meant
that any user of a Zulip server could subscribe to an invite-only
stream without needing to be invited by using the "autosubscribe"
argument.

Thanks to Rafid Aslam for discovering this issue.
2017-01-29 15:30:59 -08:00
Tim Abbott
7e0ce22808 errors: Remove build_request_repr logic.
This interface is no longer supported in Django 1.10.
2017-01-29 14:18:22 -08:00
Tim Abbott
dea281557d events: Handle reactions events in apply_events.
Previously, this race condition just threw an exception.
2017-01-29 14:18:16 -08:00
Tim Abbott
70af09539f Fix unnecessary traceback in authenticated_rest_api_view.
Apparently, we weren't returning the `json_error`, resulting in users
encountering this condition receiving a 500, rather than the proper
40x error.

This fixes a regresion introduced in 9ae68ade8b.
2017-01-29 12:48:10 -08:00
Tim Abbott
234eb7a723 emoji: Add a bunch of documentation in comments for emoji rules. 2017-01-29 12:33:44 -08:00
Rishi Gupta
e19f3d5534 emoji: Make minor adjustments to emoji names list. 2017-01-29 12:19:54 -08:00
Tim Abbott
d38b552b02 docs: Add initial documentation on the emoji system. 2017-01-29 12:15:29 -08:00
Tim Abbott
0f75c8d4ed docs: Simplify integration guide discussion of writing docs.
You don't need to know about the div structure of /integrations
anymore, so we shouldn't get into it.
2017-01-29 11:53:09 -08:00
Tomasz Kolek
3b48f21f5a Add improvements to integration-guide.md.
Fix some typos, add a few sentences that might clear it a little.
2017-01-29 11:49:13 -08:00
Jackson
db1d6933de docs: Add user guide for Using Zulip on Windows. 2017-01-29 11:38:12 -08:00
Tim Abbott
e8fd780413 docs: Fix missing wget when downloading tsearch_extra.
Fixes #3509.
2017-01-29 11:23:34 -08:00
Cynthia Lin
522ac3ea4a frontend: Add #search-operators link to search icon; Fixes #1369. 2017-01-29 07:20:15 -08:00
Rishi Gupta
6f307ffd08 emoji: Switch the order of thumbs_up and thumbs_down in autocomplete. 2017-01-28 23:38:03 -08:00
Rishi Gupta
8ef5197d5c emoji: Remove problematic color emoji from autocomplete and picker. 2017-01-28 23:38:03 -08:00
Rishi Gupta
a2890f7d7a emoji: Remove duplicates from autocomplete and emoji picker.
Previously, if you searched for ':offi..' you would see both 🏢 and
:office_building: as possible completions, both of which are shortcodes for
the same unicode codepoint (and hence which have the same image). Also, we
sort the emoji in our emoji pickers alphabetically by shortcode, and so the
images for 🏢 and :office_building: show up next to each other, which
looks like a bug. This removes :office_building: as a shortcode, along with
several hundred other duplicates. It leaves some duplicates in that won't
give autocomplete or alphabetical ordering a problem, like (🚗,
:automobile:).
2017-01-28 23:38:03 -08:00
Cynthia Lin
d8c648ac05 docs: Update *Verify that you message has been successfully sent* doc.
Change wording for better clarification.
2017-01-28 22:56:09 -08:00
synicalsyntax
21534930b1 docs: Update *Searching for messages* doc. 2017-01-28 22:49:11 -08:00
synicalsyntax
f6fc218ba3 docs: Fix *Join Zulip Chat button* doc.
With tweaks from tabbott to clean it up and better explain it.
2017-01-28 22:47:18 -08:00
Tim Abbott
5f4ddb9079 glossary: Add more clarity to private message discussions. 2017-01-28 22:39:35 -08:00
Tim Abbott
2fb51ff876 puppet: Use SIGINT to restart uwsgi.
This results in a brief service interruption (not a graceful restart),
but fixes a bug where on a `supervisorctl restart zulip-django`, we'd
end up leaking a bunch of uwsgi processes.

The mechanism was that sending SIGHUP to uwsgi was a command for it to
gracefully restart, so it'd start doing that (whereas supervisor
expected it to be dying)... and then supervisor would start up the new
uwsgi process group, resulting in 2 uwsgi process groups running.

This, in turn, led to a memory leak that could eventually result in
OOM kills.
2017-01-28 22:26:12 -08:00
synicalsyntax
4504818e5e docs: Add user guide for *Send someone a private message* 2017-01-28 19:16:56 -08:00
Cynthia Lin
30b7eee3ef docs: Add user guide for *Configure email notifications* 2017-01-28 19:09:03 -08:00
Yago González
d0d0e6956a docs: Improve Spanish style guide. 2017-01-28 19:08:14 -08:00
Yago González
87a7691bfc translations: Improve some strings. 2017-01-28 18:58:09 -08:00
Tim Abbott
f96979ae72 templates: Clean references to zulip.com. 2017-01-28 18:38:43 -08:00
Tim Abbott
37dbed7a81 zephyr: Remove Webathena text from translations. 2017-01-28 18:32:57 -08:00
Tim Abbott
d73a19927f zephyr: Remove unnecessary hardcoding of hostname. 2017-01-28 18:26:38 -08:00
Tim Abbott
b3cb9213d1 Fix malformed double-translated string in alert words code. 2017-01-28 18:23:56 -08:00
Tim Abbott
bd6f71580e docs: Remove obsolete terms-enterprise page.
This was documentation for the old zulip.com enterprise service that
no longer exists.
2017-01-28 18:12:19 -08:00
Yago González
7fe090f902 translations: Improve some poorly-worded strings. 2017-01-28 18:04:17 -08:00
Tim Abbott
36d54cf5ff Replace references to zulip.com/dist with zulip.org/dist.
Now that zulip.org has all the files to distribute, there's no reason
to still point to the soon-to-be-decommissioned zulip.com/dist.
2017-01-28 17:56:25 -08:00
Tim Abbott
5d6f42d136 tests: Fix missing type annotation for events list. 2017-01-28 17:51:46 -08:00
Tim Abbott
153418de38 subs: Send create event to new subscribers of invite-only streams.
This fixes a regression introduced by our migration to track
subscribers for all public streams, where now users who are added to
an invite-only stream were receiving a mark_subscribed event
for a stream their browser didn't know existed, causing an exception.

To fix this, we now send a stream create event to the browser just
before the user receives the notification that it was added to the
invite-only stream.
2017-01-28 17:12:16 -08:00
Tim Abbott
f665980079 test_subs: Add some additional asserts. 2017-01-28 17:11:39 -08:00
Rishi Gupta
6b3abce541 build_emoji: Generate emoji names and codepoints from emoji_map.
Replaces the hardcoded list of emoji_names and unicode_emoji_names in
static/js/emoji.js with a list generated from emoji_map.json, both to get
the list out of version control and so we can start modifying it for our
autocomplete. This does not change the contents of emoji_names. It sorts and
removes duplicates from unicode_emoji_names (causes no change in behavior,
since unicode_emoji_names is only used as if it were a set).
2017-01-28 17:05:32 -08:00
avisrivastava254084
762b84710e auth: Redirect users to home from /login if already logged in.
This makes various links in Zulip work a bit more reasonably for
already-logged-in users.

Fixes #3316.
2017-01-28 16:10:19 -08:00
synicalsyntax
7ba62c0e79 docs: Conform *Format your message using Markdown* to style guidelines. 2017-01-28 16:03:00 -08:00
synicalsyntax
3c8c72b816 docs: Update *Add emoji* doc. 2017-01-28 16:02:53 -08:00
synicalsyntax
4c0c7dd3f9 docs: Conform *@-mention a team member* to user documentation styling guidelines. 2017-01-28 15:59:44 -08:00
synicalsyntax
0f2327f9ce docs: Conform *Restore the last unsent message* to user documentation styling guidelines. 2017-01-28 15:59:44 -08:00
synicalsyntax
07d84941de docs: Update *Zulip glossary* doc. 2017-01-28 15:59:44 -08:00
khantaalaman
04591d1ce5 js: Fix pressing escape with modals open.
Previously, if you pressed the escape key with various modals open
(keyboard shortcuts, markdown help, etc.), the modals would close but
also the compose box would close and the user would be unnarrowed.
This changes makes it so all that happens is the modal closes.

Fixes #3472.
2017-01-28 15:54:36 -08:00
sinwar
21083278b5 Fix banners for unknown streams.
Fixes #3443
2017-01-28 13:11:31 -08:00
Tim Abbott
e69c4458c6 errors: Use hostname to report deployment. 2017-01-28 13:07:09 -08:00
Tim Abbott
f6f8168f4d emoji: Build emoji before minifying JS.
Since build_emoji will soon be generated
static/generated/emoji_data.js (containing the emoji data), we need to
generate those JavaScript files before minifying them.
2017-01-28 12:15:34 -08:00
Steve Howell
5251e4981c Prevent traceback in PM recipient matching code. 2017-01-28 04:39:02 -08:00
Tim Abbott
3951e650c9 formatting help: Clean up reference to zulip.com. 2017-01-27 16:55:21 -08:00
Brock Whittaker
22b74a9e01 Fix node test for emojis.
This fixes the node test for emojis that broke when the type for
displaying the emojis in the popover changed to an object from a string.
2017-01-27 16:42:00 -08:00
Yago González
1535739222 contrib_bots: Fix typos and repetitions in the readme. 2017-01-27 16:39:19 -08:00
Brock Whittaker
e44723f79d Fix broken emoji popover styling.
This fixes CSS issues such as removing padding with negative margins
and then re-adding padding back later. It also ensures the width of the
picker is exactly six columns wide and does not shift around when zoom
is enabled in the browser.
2017-01-27 16:12:38 -08:00
Tim Abbott
dff9b31546 help: Clean up discussion of search operators. 2017-01-27 16:00:22 -08:00
Cynthia Lin
de0329b4f9 docs: Modify *Searching for messages* to include directions on viewing the first message in a topic. 2017-01-27 16:00:22 -08:00
Brock Whittaker
1dd8fb7966 Display realm emojis in the emoji picker container.
This displays the realm emojis in the emoji picker container in their
own divs styled similarly to the existing .emoji divs.
2017-01-27 15:39:22 -08:00
Cynthia Lin
c72d51ec45 docs: Add user guide for *Configure email digest notifications* 2017-01-27 15:32:13 -08:00
Raghav Jajodia
c8451097be tests: Replace Stream.objects.get() with get_stream().
This should have a slight perf benefit from using caching, and also in
some cases cleans up the code a bit.

Fixes #3284.
2017-01-27 15:04:13 -08:00
Akash Kothawale
46ffafab7d docs: Use bash to run tools/provision in docker. 2017-01-27 14:54:18 -08:00
Tim Abbott
f33a9fe384 js: Fix linter errors from rebased code. 2017-01-27 14:54:11 -08:00
hackerkid
c42e4000d6 docs: Suggest vagrant provision if up errors.
Fixes #3486.
2017-01-27 14:41:29 -08:00
Steve Howell
f14e2de985 Handle spaces better in compose typeaheads.
We now allow spaces and other special characters to be part
of the token (following "#", "@", or ":") that the typeahead
code will further evaluate as a typeahead candidate.

This is important for folks with short/common first names
on larger realms.
2017-01-27 12:35:46 -08:00
Brock Whittaker
ac710be9ae On enter, submit content editable.
On the enter key, the value of the content editable box should be
submitted.
2017-01-27 12:20:21 -08:00
Brock Whittaker
14b471a29f Stream Name to Content Editable.
This changes the stream name component to be content editable.
2017-01-27 12:05:08 -08:00
Brock Whittaker
eaeb0e32a7 Stream Description Content Editable Piece.
This makes the stream description a content-editable piece.
2017-01-27 12:04:37 -08:00
Tim Abbott
82b3f7f661 help: Workaround weird wrapping bug with CSS. 2017-01-27 11:50:12 -08:00
Brock Whittaker
04dfa2071f Remove unnecessary terms-page-container class.
This removes the terms-page-container class from the markdown div and
thereby removes the necessary 40px padding at the top of the div.
2017-01-27 11:41:35 -08:00
Brock Whittaker
8dfd5d7134 Add ordered list styling for /help/ pages.
This adds a styling that puts the numbers in a Zulip brand green bubble
with white text for the number.
2017-01-27 11:41:29 -08:00
Tim Abbott
ae35bde3a6 errors: Enable error reports without zilencer enabled. 2017-01-27 10:27:41 -08:00
Tim Abbott
04ae2977fa errors: Add logging for consuming processed error reports.
This should make it a big easier to debug issues with this system.
2017-01-27 10:27:41 -08:00
Tim Abbott
0dd5d6cea0 errors: Separate browser error reporting from backend. 2017-01-27 10:27:41 -08:00
Steve Howell
ddf17abf5c Prevent dragging of Click/Unclick-all links.
We have links when to create a stream to "Click all" or
"Unclick all" for checkboxes.

In FF it's easy to accidentally start dragging these links,
which has no real value (since their href is uninteresting)
and is confusing.

Perhaps these should just be buttons.
2017-01-27 10:25:18 -08:00
Steve Howell
80ea7db4d9 Suppress jQuery warning related to settings menu.
If you develop with Firefox, before this commit, you would
get jQuery warnings about empty selectors every time you clicked
in the app, due to a glitch with our old version of bootstrap.js.

This commit makes the error go away by setting
`data-toggle` to 'nada' for the settings-dropdown
element.

This was the error:

    Empty string passed to getElementById().

More details here:

    https://github.com/twbs/bootstrap/issues/5566
2017-01-27 07:55:30 -08:00
Brock Whittaker
4ac12745cd Add capped height to description box.
This adds a capped height of 70px  to the description box (same as the
images) and then uses a gradient to fade out any text that may be near
the bottom.
2017-01-26 22:02:16 -08:00
Brock Whittaker
214b011bb5 Add subscribe button inside subscription settings.
This adds a subscribe/unsubscribe button inside the subscription
settings container for a stream right next to the stream name.
2017-01-26 21:02:57 -08:00
Steve Howell
4be2d6577d Add a new community realm to our test databases.
The realm with string_id of "simple" just has three users
named alice, bob, and cindy for now.  It is useful for testing
scenarios where realms don't have special zulip.com exception
handling.
2017-01-26 19:25:34 -08:00
Brock Whittaker
bcdd326b65 Change data-stream-name referencess to data-stream-id.
This changes all references of the data-stream-name to more
predictable data-stream-id references in the subscriptions overlay.
This prevents unescaped characters from breaking selectors and stream
renames from breaking selectors.
2017-01-26 17:32:35 -08:00
Harshit Bansal
b4186fdfdd views/realm_aliases.py: Use domain instead of id as handle for RealmAlias.
We need to make the change for the API, and the next commit introduces a
unique_together constraint on (realm, domain) anyway.
2017-01-26 17:24:25 -08:00
Harshit Bansal
06cc306d00 Add stricter domain validation and improve error messages. 2017-01-26 17:24:25 -08:00
Harshit Bansal
0ff22f68b3 settings.css: Make long domains list wrap properly in admin settings. 2017-01-26 17:24:25 -08:00
Harshit Bansal
f0e5380ff1 handlebar templates: Rename admin_alias_list to admin-alias-list. 2017-01-26 17:24:25 -08:00
Harshit Bansal
38c50a81ad admin settings: Restyle realm alias modal. 2017-01-26 17:24:25 -08:00
Harshit Bansal
5b01694e00 actions.py: Rename do_get_realm_aliases to get_realm_aliases. 2017-01-26 17:24:25 -08:00
Harshit Bansal
ec02599336 admin.js: Simplify wording around the restricted to domain setting.
Remove stringify_list_with_conjunction, which would have been tough for
i18n, and make it clear that the setting only affects new users.
2017-01-26 17:24:25 -08:00
Brock Whittaker
1a63f15382 Only run popovers.hide_all() once on scroll start.
This function throttles the function and only allows the on scroll
event to fire the popovers.hide_all() function once on scroll start
(determined as > 250ms after the last scroll event fire on .app.

This should resolve some performance issues surrounding constantly
firing queries and potentially changing the document tree.
2017-01-26 13:59:14 -08:00
Tim Abbott
b52f606c3a Revert "deps: Upgrade and move jquery-mousewheel from static/third to npm"
Apparently, the updated version of this has a serious scrolling
performance problem in the left sidebar that basically makes scrolling
in that area unusable.

This reverts commit b683b2d3c3.
2017-01-26 13:42:00 -08:00
Tomasz Kolek
71e6eb68c0 Update integration-guide according to integrations redesign.
With numerous typo and grammar fixed by tabbott.
2017-01-26 12:27:38 -08:00
Tomasz Kolek
6e6cbeb89d Split webhooks doc and move to particular directories. 2017-01-26 11:56:45 -08:00
Steve Howell
f7c3765c77 Make "Copy from Stream" more transparent/flexible.
This change makes it so that when you are creating a stream
and use "Copy from Stream", the UI will immediately
check/uncheck the user checkboxes that correspond to the
stream's subscribers.

In concrete terms this allows Cordelia to create a new
stream call "Paris" that has all the "Verona" subscribers
except for Hamlet.

It also makes it so that when you go to create the stream,
the response is a little quicker, because we don't have to
iterate the streams.

Finally, it removes an odd quirk from the original design,
where if you clicked on Denmark but then collapsed the
streams, we wouldn't actually add the Denmark subscribers
to your new stream.

The current UI will still be slightly intuitive for people, as
I think checkmarks don't really make sense here.  What we
really want are Add/Remove links (or buttons) next to each
of the existing streams.
2017-01-26 10:24:15 -08:00
Steve Howell
8cfb9e427f Simplify the "Copy from Stream" feature.
I moved the UI element for "Copy from Stream" to be above
the list of users, including the filter box and check/uncheck
links, which no longer get applied to the list of streams.

The reason I no longer apply the filter to streams is...

    * It's kind of confusing to have filters apply to both
      streams and users.  There should be separate filters for
      them, and I will try to resuscitate that feature later.
    * The code to filter the streams was doing a sketchy
      regex operation against user-inputted data. (`match()`)
    * We want to use the same stream filtering code as the
      right sidebar uses.
    * It improves performance for the common case that you
      are filtering users.

The reason I no longer apply the check-all/uncheck-all actions
to streams is that it would be crazy to select all your streams
to copy users from, and it would be expensive/slow for large
realms, and it would likely be done by accident if somebody was
trying to manage individual users.

Finally, the check-all/uncheck-all actions have been scoped
to the users filtered by the text box, so I moved the links
under the text box to make that hopefully more clear to users.
2017-01-26 10:24:15 -08:00
Steve Howell
5c091437da Improve empty user filter handling for stream creates.
If we blank out the user filter for users (by hitting backspace,
for example), then we now have short-circuit logic to display all
the user checkboxes.  (The user-facing behavior doesn't change here,
but now we don't have to process all the strings.)
2017-01-26 10:24:15 -08:00
Steve Howell
88870c316f Use Dict[user_id] in people.filter_by_search_terms.
The function people.filter_by_search_terms() used
to return a JS object with emails as keys to represent
a set of users.  Now we return a Zulip Dict() object
with user_ids as keys.
2017-01-26 10:24:15 -08:00
Steve Howell
beb3782e6c Speed up user filtering during stream creation.
The old implementation was O(N squared) for N = number of
users due to its using an O(N) selector inside of a loop.

Now we simply iterate through all the checkboxes and turn them
on or off based on a bunch of O(1) operations.
2017-01-26 10:24:15 -08:00
Tomasz Kolek
7de45951e2 Make webhooks as separate modules with view and tests.
Create python packege for every webhook with view.py and tests.py
2017-01-25 23:14:19 -08:00
Raghav Jajodia
fc965eb5f6 admin: Add No-change-made message.
A 'no changes made' message is displayed whenever save-changes button
is clicked, albeit no changes are made in the admin page.
2017-01-25 23:10:14 -08:00
Tim Abbott
06cd40d461 travis: Run test-api in Travis CI. 2017-01-25 16:42:17 -08:00
Tim Abbott
015ab412bc test-api: Log API tests status. 2017-01-25 16:42:09 -08:00
Steve Howell
9177f17d73 Simplify tools/test-help-documentation.py.
It now uses the test_server_running() context manager to
get a test server running.
2017-01-25 16:33:19 -08:00
Steve Howell
5799183e10 Add use_db flag to test_server_running(). 2017-01-25 16:33:19 -08:00
Steve Howell
38f5f3a76e tests: Move logging into test_server.py for Casper. 2017-01-25 16:33:19 -08:00
Steve Howell
6de1e8be46 Add test-api to tools/test-all. 2017-01-25 16:33:19 -08:00
Steve Howell
eb69791712 Fix update_message() in our API.
This was regressed in b3df1ddeb1.
2017-01-25 16:33:19 -08:00
Harshit Bansal
8c428dc130 Fix ZulipLDAPAuthBackend not to rely on user's email domain.
In case realms have subdomains and the user hasn't been populated
yet in the Django User model, `ZulipLDAPAuthBackend` should not
rely on user's email domain to determine in which realm it should
be created in.

Fixes: #2227.
2017-01-25 15:24:49 -08:00
Feorlen
eea6eb23f5 Note in linters doc that untracked files aren't linted. 2017-01-25 05:54:46 -08:00
hackerkid
1d1dcab2b3 requirements: Add comment explaining why CommonMark can't be upgraded.
Fixes #3398.
2017-01-24 14:22:06 -08:00
Sampriti Panda
4e78ca32de register: Improve styling for frontend errors 2017-01-24 13:39:43 -08:00
Sampriti Panda
8fe612c319 register: Fix bugs in form field auto-fills 2017-01-24 13:39:43 -08:00
Sampriti Panda
3c3902471b register: Improve styling for server-side errors 2017-01-24 13:39:43 -08:00
Tim Abbott
8a8e0ea48b requirements: Upgrade moto and dateutil to latest version. 2017-01-24 13:02:57 -08:00
Tim Abbott
dd9e0b8463 errors: Move do_report_error into zerver/lib/. 2017-01-23 23:18:28 -08:00
Tim Abbott
e6fc4ae27d errors: Move zilencer/error_notify.py to zerver/lib/. 2017-01-23 23:17:09 -08:00
Eitan Adler
0ce29d7ad6 Remove some some duplicate words in copy. 2017-01-23 23:15:04 -08:00
Tim Abbott
126b1c4edc upgrade: Don't require authors updates deploying from Git.
Fixes #3392.
2017-01-23 23:00:09 -08:00
Tim Abbott
4e171ce787 lint: Clean up E126 PEP-8 rule. 2017-01-23 22:06:13 -08:00
Tim Abbott
31e7dcd86b lint: Tag remaining PEP-8 rules with explanations. 2017-01-23 21:43:33 -08:00
Tim Abbott
376aa3e404 lint: Clean up E702 PEP-8 rule. 2017-01-23 21:37:27 -08:00
Tim Abbott
de99f48ce7 lint: Clean up E401 PEP-8 rule. 2017-01-23 21:36:39 -08:00
Tim Abbott
d6e38e2a5c lint: Clean up E123 PEP-8 rule. 2017-01-23 21:34:26 -08:00
Tim Abbott
9cc83f87fc lint: Clean up E241 PEP-8 rule. 2017-01-23 21:21:14 -08:00
Tim Abbott
fe4f7b1170 lint: Clean up E711 PEP-8 rule. 2017-01-23 21:11:49 -08:00
Tim Abbott
9640a9e864 lint: Clean up E712 PEP-8 rule. 2017-01-23 21:11:18 -08:00
Tim Abbott
e385b93448 lint: Clean up E713 PEP-8 rule. 2017-01-23 21:08:52 -08:00
Tim Abbott
a088cdaa04 lint: Clean up E714 PEP-8 rule. 2017-01-23 21:07:45 -08:00
Tim Abbott
d96f392147 lint: Clean up E741 PEP-8 rule. 2017-01-23 21:07:04 -08:00
Tim Abbott
e5daec46ec lint: Clean up E306 PEP-8 rule. 2017-01-23 21:05:08 -08:00
Tim Abbott
e3e92903eb lint: Document why E305 is turned off. 2017-01-23 21:03:46 -08:00
Tim Abbott
e9158dd520 lint: Clean up E121 PEP-8 rule. 2017-01-23 21:02:39 -08:00
Tim Abbott
6f0d2a9445 lint: Clean up E115 PEP-8 rule. 2017-01-23 20:55:37 -08:00
Feorlen
378ac3abf3 Lint yaml files using text file rules.
Fixes #3404
2017-01-23 20:53:20 -08:00
Tim Abbott
df3d6aee5d lint: Clean up E114 PEP-8 lint rule. 2017-01-23 20:52:58 -08:00
Tim Abbott
22d1aa396b lint: Clean up W503 PEP-8 warning. 2017-01-23 20:50:04 -08:00
Tim Abbott
bde2da7dfd lint: clean up PEP-8 W391 rule. 2017-01-23 20:39:02 -08:00
Zev Benjamin
f4d3cc6545 Annotate ignored pep8 rules to explain why they're ignored 2017-01-23 20:19:58 -08:00
Tim Abbott
b3df1ddeb1 edit: Remove duplicate update_message_backend endpoint. 2017-01-23 17:22:42 -08:00
Tim Abbott
46ab7762e7 edit: Eliminate unnecessary json_update_message wrapper. 2017-01-23 17:22:42 -08:00
Tim Abbott
33b02a02dd update_message_backend: Fix memcached queries in loop.
This fixes a bug where update_message_backend would do one memcached
query per user receiving a given message.  Right now we just do a
single bulk database query, but in principle we could use
generic_bulk_cached_fetch to use the cache as well.
2017-01-23 17:22:42 -08:00
Tim Abbott
0f7f9dc0fb update_message_backend: Log number of changed messages.
This will be helpful for debugging potential performance problems.
2017-01-23 17:22:40 -08:00
Steve Howell
929e8a48d7 Add test_message_flags() to echo node tests. 2017-01-23 16:52:12 -08:00
Steve Howell
01aad70910 bug fix: Fix recent regression with at-mentioning.
One of my commits from yesterday erroneously set the
"mentioned" flag on messages that weren't mentioning
the current user, so you would get the pink/salmon
background when you sent at-mentions to other people.

Now we check the user_id before setting the flag.
2017-01-23 16:42:43 -08:00
Rafid Aslam
1e9baf8ee0 deps: Upgrade docutils to 0.13.1.
Fixes #3399.
2017-01-23 15:23:58 -08:00
Adarsh S
ec44edb305 Add avatar_version to UserProfile.
avatar_version is used to keep track of the avatar version of the
user and to update the cache, everytime the user updates their avatar.
2017-01-23 23:29:07 +05:30
Tim Abbott
bbd853e208 puppet: Add redirect to https to zulip.org. 2017-01-22 21:52:50 -08:00
Tim Abbott
44776c43a1 puppet: Add configuration for zulip.org website.
This puppet configuration, plus cloning the zulip.github.io repo and
letsencrypt key setup, is all we need to run a zulip.org server.
2017-01-22 21:48:48 -08:00
Tim Abbott
a3b51bb9d2 Fix JS error syncing starred out-of-view messages.
Previously, if one starred very old messages (or ones in a stream
you're not subscribed to), your other open browsers would likely throw
an exception syncing the message flag.
2017-01-22 20:39:05 -08:00
Tim Abbott
c082564c66 reload: Catch exceptions aborting pending AJAX requests.
It's probably a bug that this throws exceptions sometimes, but it's
not consistently reproducible (or maybe, browser dependent?), and it
isn't really a problem to fail to abort some requests as part of the
page reload process; the abort was just there to make sure as little
as possible is happening so we can garbage-collect effectively.
2017-01-22 20:23:37 -08:00
Tim Abbott
e7c9a5087c auth methods: Fix buggy check for changes.
Apparently, we were comparing the full list of enabled authentication
methods (whether or not supported by the server) against the user's
selections among those supported by the server, which resulted in
authentication methods being always reported as different.
2017-01-22 17:12:58 -08:00
Tim Abbott
e5a3bbab4f docs: Expand explanation for why we use rebase workflow. 2017-01-22 15:42:27 -08:00
Yago González
8ee8118328 docs: Add explanation on the git rebase workflow. 2017-01-22 15:42:27 -08:00
sinwar
f83da697ee requirements: Upgrade parsel to latest version
Fixes #3401
2017-01-22 15:26:11 -08:00
Yago González
495a25ce1b docs: Fix broken URL. 2017-01-22 13:04:37 -08:00
Steve Howell
b37203cc83 Fix lint error w/ClientDummy. 2017-01-22 05:51:33 -08:00
Robert Hönig
af0d985bdf Update the commands in bots-guide.md to fit the new contrib_bots layout. 2017-01-22 05:42:46 -08:00
Robert Hönig
bef93959d3 Restructure converter bot.
Apply the new layout for 'contrib_bots' bots to the converter bot
to make it an exemplary model for new bots.
2017-01-22 05:42:46 -08:00
Robert Hönig
4415d6085f Restructure contrib_bots bots to new layout.
In order to make the layout of all bots consistent, this commit
moves each bot into a folder with its name and modifies 'run.py'
so that only bots with such a structure can be executed. 'lib'
gets renamed to 'bots'.
2017-01-22 05:42:46 -08:00
Raghav Jajodia
dd4ea5e56e Fix bot edit cancel button updating name anyway.
Apparently, the bot cancel button was incorrectly tagged with
"submit", and thus ended up saving the changes anyway!

Fixes #3412.
2017-01-21 22:47:29 -08:00
Rohith Asrk
9088c46e4c templates: Fix filename ending with .html.txt.
Fixes a part of #3136.
2017-01-21 22:44:13 -08:00
Tim Abbott
00d48bff7d Digest: Fix URIs for emoji and friends in email links.
It turns out we were using malformed URLs in the image tags
(containing just a hostname, but no http(s)!) in what we were passing
to the Django templates for our digest/, which resulted in the Django
templates treating these URLs as http.  Gmail recently cracked down on
loading images in HTTP, causing the emoji links to appear broken in
emails Zulip sends.

Fixes #3258.
2017-01-21 22:25:51 -08:00
Tim Abbott
c0c9dfb66d populate_db: Fix crash by removing do_send_message.
This old helper has for years been used only by populate_db, and got
buggy (as of a recent refactoring).  So we just call do_send_messages
directly instead.

Fixes the provisioning error we currently get in Travis CI.
2017-01-21 22:07:36 -08:00
Steve Howell
0fc2f18c1d bug fix: Fix already-rendered messages for avatar updates.
Most of the magic happens in message_live_update.update_avatar().

The prior code was buggy, as it was using person.id instead of
person.user_id, and it was not setting the image resolution.
2017-01-21 21:45:12 -08:00
Steve Howell
f75af94984 bug fix: Prefer person.avatar_url to message.avatar_url.
This change is a partial bug fix for avatar live updates.
It makes it so that we prefer the person.avatar_url to
the message.avatar_url when rendering messages.  Our live
update code was already populating person.avatar_url, but
we were ignoring it until now.

This commit does not affect messages that were already
rendered with the old url.
2017-01-21 21:45:12 -08:00
Steve Howell
e7e2e388c5 Move small_avatar_url() to people.js. 2017-01-21 21:45:12 -08:00
Steve Howell
4eb1a8f07d Extract user_events.js.
This moves people.update() to user_events.person().

We now also use user_id as the key for finding person
objects in people.js (instead of email).
2017-01-21 21:45:12 -08:00
Steve Howell
601bad554e bug fix: Limit updating full names in admin screens.
If we get a realm_user update for a user that is **not**
changing their full name, we no longer call
admin.update_user_full_name().

This was probably a fairly minor bug.
2017-01-21 21:45:12 -08:00
Steve Howell
4ea7e80be1 Change our_person() in apply_events() to use user_id.
This is a pretty minor change, but it makes it clear that we
have user_id in all the relevant states/events, so we might as
well use that for the check, since email is mutable and
slightly more difficult to reason about.
2017-01-21 21:45:12 -08:00
Steve Howell
e2afab142a Add user_id to payload for is_admin updates. 2017-01-21 21:45:12 -08:00
Steve Howell
28164d68b4 Extract people.set_full_name(). 2017-01-21 21:45:12 -08:00
Steve Howell
ee00d848b9 refactor: Eliminate use of page_params.fullname.
We now use people.my_full_name().
2017-01-21 21:45:12 -08:00
Steve Howell
53308b49b2 refactor: Remove last uses of page_params.email in JS code.
Earlier commits removed all uses of page_params.email outside
of people.js, and it turns out we have page_params.user_id, so
we don't even need page_params.email for seeding the data.
2017-01-21 21:45:12 -08:00
Steve Howell
9d16993011 refactor: Use people.my_current_email() in subs.js. 2017-01-21 21:45:12 -08:00
Steve Howell
58fb9e45e4 Fix flaw when subscribing using "Add" button.
When we subscribe ourselves using the "Add" button in the
right pane of "Stream settings", we now call
stream_data.subscribe_myself(), which properly updates our
data structures (more than just sub.subscribed) and prevents
some console errors when you un-subscribe yourself using
the check mark.
2017-01-21 21:45:12 -08:00
Steve Howell
f476f5be7d refactor: Add early return to subs.mark_subscribed().
The code now handles the `sub.subscribed` condition up front to
make the code less nested.
2017-01-21 21:45:12 -08:00
Steve Howell
0ccb2e38f8 refactor: Use people.my_current_email() in settings.js. 2017-01-21 21:45:12 -08:00
Steve Howell
2af0302ed0 refactor: Use people.my_current_email() in search_suggestion.js. 2017-01-21 21:45:12 -08:00
Steve Howell
038164ff04 Remove unneeded data param in pointer.fast_forward_pointer(). 2017-01-21 21:45:12 -08:00
Steve Howell
2c684bf39f refactor: Use people.my_current_email() in filter.js. 2017-01-21 21:45:12 -08:00
Steve Howell
e10c6719d9 refactor: Use people.my_current_email() in echo.js. 2017-01-21 21:45:12 -08:00
Steve Howell
1137ef4e40 Mark up mention buttons with data-user-id on the backend.
We use data-user-id now in the buttons for at-mentions when
we render messages.  A previous commit already made the front
end support this new style.
2017-01-21 21:45:12 -08:00
Steve Howell
8c6dab9750 Use data-user-id for mention buttons in local echo.
The local echo code now marks up mention buttons with user ids
instead of email.  Our code in message_list_view.js deals with
either the old style or the new style of markup now to determine
which mention buttons need to be highlighted.

As part of this commit we extract mention_button_refers_to_me().
2017-01-21 21:45:12 -08:00
Steve Howell
efdcfcaea2 Clean up message flag handling for mentions in echo.js.
After this change, if a user sends a message with at-mentions, the
local echo code will add the `mentioned` flag to 'message.flags`
as part of the callback to build the HTML, rather then doing it
hackily during a post-processing step.
2017-01-21 21:45:12 -08:00
Steve Howell
894282222a refactor: Move echo.userMentionHandler code.
The userMentionHandler callback now closes on `message` inside
of echo.apply_markdown().  This sets the stage for the next commit.
2017-01-21 21:45:12 -08:00
Steve Howell
2539ed0563 refactor: Have echo.apply_markdown take message as param.
The function echo.apply_markdown() actually applies markdown to
a message now, instead of simply computing markdown.  Passing
in the outer `message` object will allow us to avoid some hacky
post-processing of messages after rendering, because we can
have our parser callbacks update message on the spot in a more
atomic fashion.
2017-01-21 21:45:12 -08:00
Steve Howell
ee8502ef0e refactor: Use people.my_current_email() in custom_markdown.js. 2017-01-21 21:45:12 -08:00
Steve Howell
0b9a3251dd refactor: Use people.my_current_user_id() in stream_data.js.
In stream_data.unsubscribe_myself(), we no longer look at
page_params.email.
2017-01-21 21:45:12 -08:00
Steve Howell
5bce806c4e refactor: Introduce people.my_current_email().
This commit doesn't change any behavior yet, but it starts us
down the road of deprecating page_params.email and allowing
people.js to control all access to the current user's email,
which will be important for email changes.
2017-01-21 21:45:12 -08:00
Steve Howell
73125e2718 refactor: Move is_current_user() to people.js.
We no longer have it in util.js, because we will
want to encapsulate this better for upcoming commits
related to email changes.
2017-01-21 21:45:12 -08:00
Tim Abbott
5d52f1ec17 bugdown: Move realm_filters_key logic out of callers.
This gets rid of the confusing duplicate realm_filters_key and
message_realm arguments that previously were passed to bugdown.
2017-01-21 21:37:57 -08:00
Sampriti Panda
34a4a1378d bugdown: Use specified realm, not sender realm, for rendering.
This changes bugdown to use the realm passed in by the caller (if any)
for rendering, fixing a problem where bots such as the notification
bot would have their messages rendering using the admin realm's
settings, not the settings of the realm their messages are being sent
into.

Also adds a test for the notification bot case.

Fixes #3215.
2017-01-21 21:37:57 -08:00
Tim Abbott
01e0acb282 render_incoming_message: Require a realm object. 2017-01-21 21:37:57 -08:00
Tim Abbott
76509a251b do_send_message: Pass the realm object in. 2017-01-21 21:37:57 -08:00
Tim Abbott
bc138f72f4 render_markdown: Refactor realm_filters_key logic.
This moves the realm_filter_key variable, primarily used for clarity,
up from Bugdown into the render_markdown function.

We'll need this for the upcoming commits.
2017-01-21 21:37:57 -08:00
Tim Abbott
99c5563bc6 internal_send_message: Make realm argument mandatory.
A lot of care has been taken to ensure we're using the realm that the
message is being sent into, not the realm of the sender, to correctly
handle the logic for cross-realm bot users such as the notifications
bot.
2017-01-21 21:37:30 -08:00
Tim Abbott
8ba7d2080c internal_prep_message: Make realm argument mandatory.
In order to correctly handle messages sent by cross-realm bots, we
need to specify the realm that the messages are being sent into in the
send message code path.  The commit and its successors convert that
code path to include the realm the message is being sent to explicitly.
2017-01-21 21:16:18 -08:00
sinwar
b0efa58eb4 requirements: Upgrade python-social-auth to latest version
Fixes #3403
2017-01-21 21:22:59 +05:30
Tim Abbott
15c4ae9ea9 Revert "docs: Remove broken docker links for now."
This reverts commit ef953af597.

Docker has fixed their website.

Fixes #3394.
2017-01-20 11:01:12 -08:00
Tim Abbott
aadf621466 test-backend: Only check for unrendered templates if tests passed. 2017-01-20 10:56:03 -08:00
Tomasz Kolek
cc13104780 Add Zapier integration. 2017-01-20 10:43:18 -08:00
Rishi Gupta
29799d93c6 analytics/views.py: Always return time series data for stats.
Makes a number of simplications to the analytics views code. The main one is
that we now return the entire data series, even if the data is eventually
going to go into a pie chart. This was prompted by us wanting several
different pie charts for each stat (one for last 30 days, one for all time,
etc), but I think it is also a more natural API. The total amount of data
being sent for the pie charts now is maybe half of what is being sent for
our single 'hourly' stat, or maybe up to 10,000 ints per year the
organization has been around.

The other big change is that the data being sent back is now always explicit
about whether it is data about the realm (stored in data['realm'], or data
about the user (stored in data['user']).
2017-01-19 17:44:17 -08:00
Rafid Aslam
b683b2d3c3 deps: Upgrade and move jquery-mousewheel from static/third to npm
- Remove `jquery-mousewheel` from `static/third` and fetch it from npm.
- Upgrade `jquery-mousewheel` to 3.1.6.
- Bump up the `PROVISION_VERSION` to 4.5.
- Change some js code to comply with this `jquery-mousewheel` version.

Part of #1709.
2017-01-19 17:24:53 -08:00
Rafid Aslam
10a8c3d2ae deps: Move xdate from static/third to npm
- Remove `xdate` from `static/third` and fetch it from `npm`.
- Bump up the `PROVISION_VERSION` to 4.3.

Part of #1709.
2017-01-19 17:07:55 -08:00
Rafid Aslam
84e802422e deps: Upgrade and move underscore.js from static/third to npm
- Remove `underscore.js` from `static/third` and fetch it from `npm`.
- Upgrade `underscore.js` to 1.8.3.
- Bump up the `PROVISION_VERSION` to 4.2.

Part of #1709
2017-01-19 17:07:45 -08:00
Rafid Aslam
911fcd3831 deps: Upgrade and move codepointat from static/third to npm
- Remove `codepointat` from `static/third` and fetch it from `npm`.
- Upgrade `codepointat` to 0.2.0.
- Bump up the `PROVISION_VERSION` to 4.1.

Part of #1709.
2017-01-19 17:07:32 -08:00
Rafid Aslam
8ac81d2722 deps: Upgrade and move winchan.js from static/third to npm
- Remove `winchan.js` from `static/third` and fetch it from `npm`.
- Upgrade `winchan` to 0.2.0.
- Bump up the `PROVISION_VERSION` to 4.0.

Part of #1709.
2017-01-19 17:07:21 -08:00
Tim Abbott
ef953af597 docs: Remove broken docker links for now. 2017-01-19 16:42:50 -08:00
Tim Abbott
1a536f381c lint: Fix some PEP-8 lint errors. 2017-01-19 16:42:50 -08:00
Tim Abbott
42612161df tornado: Remove unused caching code. 2017-01-19 16:36:31 -08:00
Rohith Asrk
a1b0e35792 Remove use of mailer.send_mail from all files.
This was just copied from some third-party projects.

Fixes #3153.
2017-01-19 16:28:29 -08:00
Rohith Asrk
213b8cef0c Bootstrap.js: Fix null is not an object error. 2017-01-19 16:28:17 -08:00
Rohith Asrk
560db2d482 send_password_reset_email.py: Migrate to send_mail from EmailMultiAlternatives. 2017-01-19 16:26:31 -08:00
Rohith Asrk
92ed9dd930 deliver_email.py: Migrate to send_mail from EmailMultiAlternatives. 2017-01-19 16:26:24 -08:00
Tim Abbott
d091691b3d lint: Require access_message to access Message objects. 2017-01-19 15:59:06 -08:00
Steve Howell
477b4af39d Direct new users to the "new members" stream.
If a new user is auto-subscribed to a stream called "new
members", we will automatically narrow them to that stream
after the tutorial.  Otherwise, we fall back to the code's
previous behavior, which is to direct them to the notifications
stream (often called "announce").

This is somewhat experimental.  If we try this concept out on
the public Zulip realm and it works well, we will create a nice
realm setting for the "new members" stream.
2017-01-19 14:58:31 -08:00
Steve Howell
0ff2c5881e provision: Simplify messaging in tools/provision.
The script now outputs bullet points to the user when
it fails, and there are some basic comments at the top
of the file.  I also fixed the path of the log file.

Fixes #3230
2017-01-19 14:55:22 -08:00
Steve Howell
cd6115c24d Make nicer slugs for "sender" narrows.
Slugs are now like our "pm-with" slugs:

    narrow/sender/3-cordelia
2017-01-19 14:54:50 -08:00
Steve Howell
1ae3feac3e Use blueslip.warn, not error, for unknown emails.
In people.emails_strings_to_user_ids_string, we just warn
for bad emails going forward.

Users can enter bad emails into the search location bar,
for example, and that causes us to compute a browser hash,
which in turn uses this function.

(It's possible that we should adjust the search code not
to compute hashes for narrowing when the narrow doesn't
make sense, but that could be a non-trivial fix.)
2017-01-19 14:54:50 -08:00
Tim Abbott
286f640194 minify: Clean up unnecessary tuple/list complexity. 2017-01-19 14:51:16 -08:00
Tommy Ip
23a7685fa5 deps: Add option to skip minifying Javascript files.
Plotly.js take around 20 seconds to minify with the Closure
compiler so it is taken out.

Fixes #3076.
2017-01-19 14:31:38 -08:00
Brock Whittaker
2ed598c619 Change actually_filter_streams to only run if subs overlay is open.
This change makes it such that the stream filtering operation will only
run if the subscription overlay is visible, preventing any issues with
the lack of existence of elements or processing something that users
won’t be able to see.

Fixes #3388.
2017-01-19 14:26:36 -08:00
Brock Whittaker
eccca8fc61 Unify subs modal closing with subs.close().
The new subs.close() function should unify all closing events of the
subscriptions overlay. The function also now tracks whether the
subscription overlay is in a closed or open state.
2017-01-19 14:23:25 -08:00
hackerkid
f6c8a005b4 Increment provision version for upgradation of python dependencies. 2017-01-19 14:18:39 -08:00
hackerkid
dbf17064c2 requirements: Upgrade pathlib2 to 2.2.1 2017-01-19 14:18:39 -08:00
hackerkid
57e4c925bc requirements: Add scandir package to ipython.txt.
Needed for pathlib2==2.2.1.
2017-01-19 14:18:39 -08:00
hackerkid
071ab7bf70 requirements: Upgrade Typing to 3.5.3.0. 2017-01-19 14:18:39 -08:00
hackerkid
dc5e09f5e1 requirements: Upgrade Jinja2 to 2.9.4. 2017-01-19 14:18:39 -08:00
hackerkid
9f5108ded2 requirements: Upgrade Pillow to 4.0.0. 2017-01-19 14:18:39 -08:00
hackerkid
7a20dc64d7 requirements: Add olefile package to common.txt.
Olefile is needed for running Pillow==4.0.0.
2017-01-19 14:18:39 -08:00
hackerkid
b5de4e06f1 requirements: Upgrade backports-abc to 0.5. 2017-01-19 14:18:39 -08:00
hackerkid
aeb9c4b485 requirements: Upgrade boto to 2.45.0. 2017-01-19 14:18:39 -08:00
hackerkid
11b15d1cc8 requirements: Upgrade sphinx to 1.5.1. 2017-01-19 14:18:39 -08:00
hackerkid
4dd0de33db requirements: Upgrade requests to 2.12.5. 2017-01-19 14:18:39 -08:00
hackerkid
1783e88531 requirements: Upgrade attrs to 16.3.0. 2017-01-19 14:18:39 -08:00
hackerkid
e1da6140eb requirements: Upgrade zope.interface to 4.3.3. 2017-01-19 14:18:39 -08:00
hackerkid
8c323e05ac requirements: Upgrade Twisted to 16.6.0. 2017-01-19 14:18:39 -08:00
hackerkid
a142b9801f requirements: Upgrade w3lib to 1.16.0. 2017-01-19 14:18:39 -08:00
hackerkid
0d000ec13c requirements: Upgrade cryptography to 1.7.1. 2017-01-19 14:18:39 -08:00
hackerkid
7a5d605ae4 requirements: Upgrade Scrapy to 1.3.0. 2017-01-19 14:18:39 -08:00
hackerkid
77e0fe012c requirements: Upgrade python-ldap to 2.4.28. 2017-01-19 14:18:38 -08:00
hackerkid
b4e979a23f requirements: Upgrade Werkzeug to 0.11.15 and click to 6.7. 2017-01-19 14:18:31 -08:00
hackerkid
bec790f4ca requirements: Upgrade Flask to 0.12. 2017-01-19 14:11:07 -08:00
hackerkid
a36b524e61 requirements: Upgrade prompt_toolkit to 1.0.9. 2017-01-19 14:11:07 -08:00
hackerkid
e82180a5c0 requirements: Upgrade urllib3 to 1.20. 2017-01-19 14:11:07 -08:00
hackerkid
94410c920f requirements: Upgrade decorator to 4.0.11. 2017-01-19 14:11:07 -08:00
hackerkid
65f7514a69 requirements: Upgrade regex to 2017.1.17. 2017-01-19 14:11:07 -08:00
hackerkid
3b1f6a4154 requirements: Upgrade lxml to 3.7.2. 2017-01-19 14:11:07 -08:00
hackerkid
76bf3982a6 requirements: Upgrade cssselect to 1.0.1. 2017-01-19 14:11:07 -08:00
hackerkid
5f56b9af97 requirements: Upgrade cchardet to 1.1.2. 2017-01-19 14:11:07 -08:00
hackerkid
4116da22a9 requirements: Upgrade pyflakes to 1.5.0. 2017-01-19 14:11:07 -08:00
hackerkid
8b45f5c8a3 requirements: Upgrade coverage to 4.3.4. 2017-01-19 14:11:07 -08:00
hackerkid
ae1bd2b0bc requirements: Upgrade beautifulsoup4 to 4.5.3. 2017-01-19 14:11:07 -08:00
hackerkid
43c4d7f39e requirements: Upgrade pcodestyle to 2.2.0. 2017-01-19 14:11:07 -08:00
hackerkid
6571d7c568 requirements: Upgrade polib to 1.0.8. 2017-01-19 14:11:07 -08:00
hackerkid
c29cd84ce9 requirements: Upgrade django-pipeline to 1.6.11. 2017-01-19 14:11:07 -08:00
hackerkid
60fbe093c1 requirements: Upgrade sourcemap to 0.2.0. 2017-01-19 14:11:07 -08:00
hackerkid
24426d4684 requirements: Upgrade simplejson to 3.10.0. 2017-01-19 14:11:07 -08:00
hackerkid
22c2c0144c requirements: Upgrade pytz to 2016.10. 2017-01-19 14:11:07 -08:00
hackerkid
f1c2156aae requirements: Upgrade oauthlib to 2.0.1. 2017-01-19 14:11:07 -08:00
hackerkid
82d8ef12cd requirements: Upgrade oauth2client to 4.0.0. 2017-01-19 14:11:07 -08:00
hackerkid
9d999dd524 requirements: Upgrade google-api-python-client to 1.6.1. 2017-01-19 14:11:07 -08:00
hackerkid
33e8be51e2 requirements: Upgrade fonttools to 3.5.0. 2017-01-19 14:11:07 -08:00
hackerkid
2ce60273f9 requirements: Upgrade SQLAlchemy to 1.1.5. 2017-01-19 14:11:07 -08:00
hackerkid
db9d0b74a7 requirements: Upgrade Django to 1.10.5. 2017-01-19 14:11:07 -08:00
Sampriti Panda
6484af6854 tools: Fix regressions in tools/tests/test_html_branches.py 2017-01-19 08:02:34 -08:00
Tim Abbott
bbba6b7725 Update changelog. 2017-01-18 15:43:25 -08:00
Tim Abbott
287b84d113 auth: Improve configuration/documentation for password strength.
Followup to #3190.
2017-01-17 20:52:52 -08:00
Tim Abbott
bbead84afa docs: Extract security-model.md. 2017-01-17 20:52:29 -08:00
Tim Abbott
48109b7bd8 docs: Clean up user guide index a bit. 2017-01-17 17:06:40 -08:00
Yago González
ade5e762fb integrations: Add documentation for OpenShift. 2017-01-17 16:04:55 -08:00
Rishi Gupta
734ca4644c analytics: Add random_seed argument to generate_time_series_data. 2017-01-17 15:54:57 -08:00
Rishi Gupta
37bdc7c010 analytics: Remove COUNT_STATS['messages_sent:hour'].
Having both messages_sent:hour and messages_sent:is_bot:day is confusing,
since a single messages_sent:is_bot:hour would have a superset of the
information and take less total space. This commit and its parent together
replace the two stats with a single messages_sent:is_bot:hour.
2017-01-17 15:54:57 -08:00
Rishi Gupta
b593ac9d7c analytics: Change messages_sent:is_bot to hourly frequency.
In preparation for replacing messages_sent.
2017-01-17 15:54:57 -08:00
Rishi Gupta
68fcb4152f analytics: Remove interval field from *Count tables.
Includes a database migration. The interval field was originally there to
facilitate time aggregation (e.g. aggregate_hour_to_day), but we now do such
aggregations in views code or in the frontend.
2017-01-17 15:54:57 -08:00
Rishi Gupta
a8f2ebb443 analytics: Include interval in COUNT_STATS property names. 2017-01-17 15:54:57 -08:00
Rishi Gupta
c466036c80 analytics: Remove unneeded references to interval from test_counts.py. 2017-01-17 15:54:57 -08:00
Rishi Gupta
12d277d4f4 analytics: Change messages_sent:client stat to daily frequency.
A few reasons:
* Our two other subgroup'd message stats in UserCount are at CountStat.DAY
  frequency (messages_sent:is_bot and messages_sent:message_type).
* Keeping this stat at hourly frequency would likely double the size of our
  analytics table, given the current stats. (Counterpoint: if there are
  roughly as many active streams as active users, and we keep
  messages_sent_to_stream:is_bot at hourly frequency, then maybe this stat
  is only a 30% or 50% increase).
* We're currently only showing this on the frontend as a pie chart anyway.
2017-01-17 15:54:57 -08:00
Rishi Gupta
690002aef8 analytics: Add fixtures for several CountStats. 2017-01-17 15:54:57 -08:00
Rishi Gupta
2710a944e8 analytics: Refactor fixture creation to make it more general.
Also less verbose, in preparation for adding a bunch more fixtures.
2017-01-17 15:54:57 -08:00
Rishi Gupta
1f4a4e5e26 analytics: Force --clear-existing-data option in populate_analytics_db.
Makes more sense for a fixture generating script to just clear the existing
data every time.
2017-01-17 15:54:57 -08:00
Rishi Gupta
680e7f75e1 analytics: Change generate_time_series_data argument from length to days.
Previously, this function seemed ambivalent about whether it was generating
a series of abstract data points or a series of data points that would
correspond to times. Switch firmly to the latter, so e.g. if the frequency
changes, so will the length of the output sequence.
2017-01-17 15:54:57 -08:00
Rishi Gupta
3712fda30d analytics: Ensure fixture data points are non-negative. 2017-01-17 15:54:57 -08:00
Rishi Gupta
ecfc336a15 analytics: Add views for remaining /stats graphs. 2017-01-17 15:54:57 -08:00
Rishi Gupta
73c0c4c52e analytics/views.py: Increase efficiency of get_time_series_by_subgroup.
Not sure if this would actually be a performance problem in practice, but
this was originally making a database query for each subgroup (instead of
just a single query getting data for all the subgroups).

Also removed the filter against the interval column, which will soon not be
needed (interval will be uniquely determined by the property).
2017-01-17 15:54:57 -08:00
Rishi Gupta
d873902755 analytics/views.py: Refactor get_messages_sent_by_humans_and_bots.
Refactor out the reusable parts, since we're about to add several more
views.
2017-01-17 15:54:57 -08:00
Rishi Gupta
3a72b5cda9 analytics: Rename messages_sent_to_realm.
Several additional stats in the pipeline that also relate to messages sent
to the realm.
2017-01-17 15:54:57 -08:00
Rishi Gupta
cdb1c96169 analytics tests: Refactor assertCountEquals calls to be more readable. 2017-01-17 15:54:57 -08:00
Rishi Gupta
59d50c3a47 analytics tests: Make it easy to refer to users in test realm. 2017-01-17 15:54:57 -08:00
Rishi Gupta
54e66e6079 analytics: Add remaining backend tests in TestCountStats. 2017-01-17 15:54:57 -08:00
aakash-cr7
b373f2ef0f analytics: Add backend test for messages_sent_to_stream:is_bot. 2017-01-17 15:54:57 -08:00
Amy Liu
10c0c2b16d analytics: Add backend tests for messages_sent:message_type. 2017-01-17 15:54:57 -08:00
Rishi Gupta
f30b174199 analytics: Set property and interval defaults in assertCountEquals. 2017-01-17 15:54:57 -08:00
Rishi Gupta
a563a15f88 analytics: Make TestCountStats tests more robust.
Adds two things to TestCountStats.setUp():
* A realm with no messages, that generally should not show up in *Count
  tables,
* Users/streams/messages created at 0, 1, 61, and 1441 (just over a day)
  minutes ago (previously was 0, 60), to better test the start_time/end_time
  in the queries, and the frequency/interval setting in the CountStats.
2017-01-17 15:54:57 -08:00
Rishi Gupta
e94bc8f142 analytics tests: Autogenerate names for create* functions. 2017-01-17 15:54:57 -08:00
Amy Liu
f7ce76fb63 analytics: Add create_stream_with_recipient and create_huddle_with_recipient.
This commit replaces AnalyticsTestCase.create_stream with create_stream_with_recipient and adds the method create_huddle_with_recipient.
2017-01-17 15:54:57 -08:00
Umair Khan
378bab6304 Create validate_email function. 2017-01-17 15:49:35 -08:00
Umair Khan
61b2a1c158 Get email activation url through a function.
This allows us to override the activation url function
in the derived class; this can be used to change the
view which handles the confirmation.
2017-01-17 15:49:34 -08:00
Umair Khan
9fecbcecf5 subdomains: Don't show login page on root aliases. 2017-01-17 15:29:24 -08:00
Umair Khan
d8db94bab8 TestLoginPage: Fix a confusingly named test.
Change name from test_login_page_with_subdomains to
test_login_page_wrong_subdomain_error.
2017-01-17 15:29:07 -08:00
Steve Howell
c0281498e6 group PMs: Fix hrefs in right sidebar for groups.
For the "GROUP PMs" part of the right sidebar, we now have
accurate hrefs when you hover over the groups or right-click
to copy links or open links in new tabs.
2017-01-17 15:13:49 -08:00
Steve Howell
c94b8c39d0 Add narrow.huddle_with_uri() convenience method.
This will be used in a subsequent commit.
2017-01-17 15:13:49 -08:00
Steve Howell
d757f840dd Make nicer slugs for "pm-with" narrows.
The slugs for PM-with narrows now have user ids in them, so they
are more resilient to email changes, and they have less escaping
characters and are generally prettier.

Examples:

    narrow/pm-with/3-cordelia
    narrow/pm-with/3,5-group

The part of the URL that is actionable is the comma-delimited
list of one or more userids.

When we decode the slugs, we only use the part before the dash; the
stuff after the dash is just for humans.  If we don't see a number
before the dash, we fall back to the old decoding (which should only
matter during a transition period where folks may have old links).

For group PMS, we always say "group" after the dash. For single PMs,
we use the person's email userid, since it's usually fairly concise
and not noisy for a URL.  We may tinker with this later.

Basically, the heart of this change is these two new methods:

    people.emails_to_slug
    people.slug_to_emails

And then we unify the encode codepath as follows:

    narrow.pm_with_uri ->
    hashchange.operators_to_hash ->
    hashchange.encode_operand ->
    people.emails_to_slug

The decode path didn't really require much modication in this commit,
other than to have hashchange.decode_operand call people.slug_to_emails
for the pm-with case.
2017-01-17 15:13:49 -08:00
Yago González
e1429c8069 translations: Reorder and update Spanish terms 2017-01-17 14:53:27 -08:00
Yago González
3d6e56eb15 translations: Improve the Spanish style guide. 2017-01-17 14:53:27 -08:00
Cynthia Lin
8d82d6f3c2 docs: Document *Administrator only feature* macro in user documentation styling guide. 2017-01-17 14:45:15 -08:00
synicalsyntax
2c6a467ba0 docs: Remove instances of "(admin only)" in index.md.
All admin only docs are now located under “Administering a Zulip
organization”
2017-01-17 14:45:15 -08:00
Cynthia Lin
0e543c7bad docs: Create and use *Administrator only feature* macro. 2017-01-17 14:45:15 -08:00
Steve Howell
cc7ccb56d4 Revert "Fix inconsistent spacing in message actions popover."
This reverts commit 1f13a991f4.

Moving to tables makes it so that we can't navigate the menu
with the keyboard.

Fixes #3352
2017-01-17 14:40:49 -08:00
Ayush Goyal
a85b539c4a zulip_tools: Improve color and copy for run() errors.
Tweaks to the text are edited by tabbott.
2017-01-17 14:37:15 -08:00
Tim Abbott
699d30b1eb provision: Ensure that stderr output isn't buffered badly.
Previously, if a script called by provision threw an error, the
traceback for the called script would be lost far above the traceback
from provision itself in the terminal history, resulting in a great
deal of confusion about what the actual problem was.
2017-01-17 14:28:10 -08:00
Robert Hönig
789ae8648a Add wrapper and log file output for provisioning.
Before this commit, provisioning was done by executing provision.py,
which printed the log directly to stdout, making debugging harder.
This commit creates a wrapper bash script 'provision' in tools, which
calls 'zulip/scripts/tools/provision_vm.py' (the new location of
provision.py) and prints all the output to
'zulip/var/log/zulip/zulip_provision.log' via 'tee'.
Travis tests and docs have been modified accordingly.
2017-01-17 14:23:28 -08:00
Tim Abbott
87a6c258a0 docs: Update Changelog since last release. 2017-01-17 14:10:33 -08:00
Tim Abbott
4f67b9802d travis: Use fixture for authors page in CI. 2017-01-17 13:42:37 -08:00
Tommy Ip
c407919db3 Add /authors page.
Contributor visualization showing the avatar, user name and number
of commits for each contributors. The JSON data would be updated
upon deployment, triggered by the `update-prod-static` script.
2017-01-17 13:35:55 -08:00
Tim Abbott
747f66bfe1 docs: Add README.md files for scripts/ and tools/. 2017-01-17 11:01:27 -08:00
ParthMahawar
c0fdc451a0 interactive bots: create EncryptBot bot 2017-01-17 09:13:33 -08:00
Robert Hönig
effaa75625 Improve virtual_fs.py bot.
This commit fixes a bug with deleting directories,
prettifies the program's path output, and adds the
commands 'cd' (without 'cd ..') , 'rmdir' and 'pwd'.
2017-01-17 08:00:56 -08:00
Tim Abbott
9bb390133b admin: Fix emoji creation.
f3b9abee14 apparently failed to update
the frontend.
2017-01-17 00:21:32 -08:00
Tim Abbott
9821b3ebef reactions: Fix JS error for not-yet-fetched messages. 2017-01-17 00:10:41 -08:00
Tim Abbott
89212d9985 emoji: Remove unnecessary duplicate regular expression from urls.py.
Whether the emoji is valid is already being checked elsewhere, and
this duplicate regular expression makes it harder to understand what's
going on with Zulip's validation of emoji.
2017-01-16 23:54:58 -08:00
Tim Abbott
121b926962 emoji: Fix 500 trying to remove nonexisting realm emoji. 2017-01-16 23:48:07 -08:00
Tim Abbott
19cb5013d3 emoji: Extract zerver.lib.emoji. 2017-01-16 23:45:28 -08:00
Tim Abbott
f3b9abee14 Convert realm emoji upload to use PUT properly. 2017-01-16 23:45:12 -08:00
Tim Abbott
09b04f2aec docs: Edit user documentation style guide a bit. 2017-01-16 22:15:01 -08:00
synicalsyntax
eaa4f4cfa5 docs: Rewrite user documentation styling guide. 2017-01-16 22:15:01 -08:00
Tim Abbott
aad3ca0224 Extract docs/user-docs.md from docs/README.md. 2017-01-16 21:58:25 -08:00
Tim Abbott
19b89eb050 bugdown: Rename realm_id to realm_filters_key.
This should substantially improve the clarity of the code, since
inside bugdown, this is only being used as a hash key that happens to
usually be a realm ID, not used as a Realm ID.
2017-01-16 21:48:55 -08:00
Steve Howell
7afb19e0d4 Add test driver for the API. 2017-01-16 21:12:39 -08:00
Steve Howell
c6b2d531ef Extract tools/lib/test_server.py
This new module abstracts the setting up of a test
server for tests to run, pulling existing code from
casper and paving the way for API tests in the future.
2017-01-16 21:12:39 -08:00
Steve Howell
29ef623ce9 Add option to skip flaky Casper tests. 2017-01-16 21:12:39 -08:00
JefftheBest1
a9c8c826a4 Fix 'message' typo in message_list_view.js. 2017-01-16 21:11:17 -08:00
Jackson
013fab70ad Fix grammatical and spelling errors in Zulip/docs. 2017-01-16 20:16:12 -08:00
Mahim Goyal
1f13a991f4 Fix inconsistent spacing in message actions popover.
This was implemented by changing the format of the popover from a list
to a table.

Fixes #3010.
2017-01-16 20:10:06 -08:00
Steve Howell
c36932d29e Fix unread counts display when pinning/un-pinning.
The fix works by having build_stream_sidebar_row()
automatically update its own unread count when we
build a sidebar row.  Currently we rebuild sidebar
rows when we pin/unpin rows.

As an aside, we currently don't really need to rebuild
the sidebar row when we pin, since we're only moving
the DOM, not altering it.  But this may change in the
future, so I decided to leave that code path in place.
We may decide to do things in the future like showing
pinned streams with bolder fonts or special icons or
whatever.

Fixes #2902
2017-01-16 20:07:08 -08:00
Steve Howell
9616d91bdd minor: Move update_count_in_dom() higher in module.
This change will prevent a lint error in the subsequent
change.  This just moves code in the file.
2017-01-16 20:07:01 -08:00
Steve Howell
9806d429af Add unread.num_unread_for_stream() function. 2017-01-16 20:07:01 -08:00
Steve Howell
4597fdae27 refactor: Change params to update_count_in_dom().
We now just pass in unread_count_elem and count to
update_count_in_dom(), and it does the work of finding
count_span and value_span now.
2017-01-16 20:07:01 -08:00
synicalsyntax
6045730902 docs: Document *Save changes* macro in user documentation styling guide. 2017-01-16 19:59:37 -08:00
synicalsyntax
dab0bf80ae docs: Add *Save changes* macro to *Allow anyone to join without an invitation* 2017-01-16 19:59:37 -08:00
Cynthia Lin
aa9e40b39a docs: Add *Save changes* macro to *Change a user's name* 2017-01-16 19:59:37 -08:00
Cynthia Lin
7ff7d0e76c docs: Add *Save changes* macro to *Change the default language for your organization* 2017-01-16 19:59:37 -08:00
Cynthia Lin
d1a49bd174 docs: Add *Save changes* macro to *Change your avatar* 2017-01-16 19:59:37 -08:00
Cynthia Lin
1925cf4037 docs: Add *Save changes* macro to *Change your name* 2017-01-16 19:59:37 -08:00
Cynthia Lin
86e58d283c docs: Add *Save changes* macro to *Change your organization's name* 2017-01-16 19:59:37 -08:00
Cynthia Lin
b090959fbc docs: Add *Save changes* macro to *Change your password* 2017-01-16 19:59:37 -08:00
Cynthia Lin
cc313edbce docs: Add *Save changes* macro to *Configure audible notifications* 2017-01-16 19:59:37 -08:00
Cynthia Lin
0c305b85ce docs: Add *Save changes* macro to *Configure desktop notifications* 2017-01-16 19:59:37 -08:00
Cynthia Lin
8306e8aa8c docs: Add *Save changes* macro to *Configure mobile notifications* 2017-01-16 19:59:37 -08:00
Cynthia Lin
ac998960b3 docs: Add *Save changes* macro to *Only allow admins to create new streams* 2017-01-16 19:59:37 -08:00
Cynthia Lin
e484d00627 docs: Add *Save changes* macro to *Only allow admins to invite new users* 2017-01-16 19:59:37 -08:00
Cynthia Lin
012415a1dc docs: Add *Save changes* macro to *Restrict editing of old messages and topics* 2017-01-16 19:59:37 -08:00
Cynthia Lin
3123ab29e7 docs: Add *Save changes* macro to *Restrict user email addresses to certain domains* 2017-01-16 19:59:37 -08:00
Cynthia Lin
11f36df37c docs: Create *Save changes* macro. 2017-01-16 19:59:37 -08:00
hackerkid
c55a0dd237 provision: Check for shell_profile files before creating them. 2017-01-16 19:58:01 -08:00
JefftheBest1
faa847148b docs: Improved the headings in some docs. 2017-01-16 19:54:21 -08:00
Raghav Jajodia
4d65f9d6cf Fix left sidebar rendering issue with some zoom levels.
Fixes #3296.
2017-01-16 19:45:33 -08:00
Bojidar Marinov
df00ad3e84 search: Prevent crashes with multiple search operators.
Fixes #3071.
2017-01-16 19:42:49 -08:00
Jackson
e76bcba56b Fix spelling and grammatical errors in zerver/help docs. 2017-01-16 19:34:45 -08:00
Brock Whittaker
431a69a769 Change filtered/desaturated checkbox to SVG for performance.
Due to the fact that getComputedValue is called when using filter and
opacity attributes, it is much more efficient to use an SVG that has a
changing fill color rather than something that may be interpreted by
browsers as a layout change that requires layout recalculation.

This should result in noticeably smoother and more responsive :hover
events for the streams with greyed checkmarks.
2017-01-16 18:26:09 -08:00
Vamshi Balanaga
583f1e503e docs: Add user guide for Send a message in a different language. 2017-01-16 18:24:06 -08:00
Tim Abbott
9be76e91dd Fix capitalization in 'Add a new bot'. 2017-01-16 18:00:10 -08:00
Tim Abbott
c4836bca44 Rename titles for 'Zulip Labs' to 'Experimental settings'. 2017-01-16 18:00:10 -08:00
Tim Abbott
86ddd2277e Fix capitalization in 'Deactivate your account'. 2017-01-16 18:00:10 -08:00
Tim Abbott
9921f3279f Fix capitalization in 'Deactivate account'. 2017-01-16 18:00:10 -08:00
Tim Abbott
2619ee666e Fix capitalization in 'Authentication methods'. 2017-01-16 18:00:10 -08:00
Tim Abbott
b68a970018 Fix capitalization and grammar in 'Add a new filter'. 2017-01-16 18:00:10 -08:00
Tim Abbott
1a16c9bd53 Fix capitalization and grammar in 'Delete streams'. 2017-01-16 18:00:10 -08:00
Tim Abbott
6bc1653333 Fix capitalization in 'Create bot'. 2017-01-16 18:00:10 -08:00
Tim Abbott
15b718e2d1 Fix capitalization in 'Your bots'. 2017-01-16 18:00:10 -08:00
Tim Abbott
450ce61e6c Fix internationalization in streams page buttons/labels. 2017-01-16 18:00:10 -08:00
Tim Abbott
abd4767b50 Fix capitalization in 'Allowed domains'. 2017-01-16 18:00:10 -08:00
Tim Abbott
ee0e4c88bd Fix capitalization in 'Add new default stream'. 2017-01-16 18:00:10 -08:00
Tim Abbott
45dc2d599c Fix capitalization in 'Add a new emoji'. 2017-01-16 18:00:10 -08:00
Tim Abbott
8dc96166fd Fix capitalization in 'Your account'. 2017-01-16 18:00:10 -08:00
Tim Abbott
37e7898303 Fix capitalization in 'Default streams'. 2017-01-16 18:00:10 -08:00
Tim Abbott
d38277b095 Fix capitalization in 'New alert word'. 2017-01-16 18:00:10 -08:00
Tim Abbott
572e3565fb Fix capitalization in 'Add/Custom Alert Word(s)'. 2017-01-16 18:00:10 -08:00
Tim Abbott
1703c0c897 Fix capitalization in 'Select default language'. 2017-01-16 18:00:10 -08:00
Tim Abbott
3667ca8114 Fix capitalization in 'Default language'. 2017-01-16 18:00:10 -08:00
Tim Abbott
e1e7788e67 Fix capitalization in 'Deactivated users'. 2017-01-16 18:00:10 -08:00
Tim Abbott
ab75b41a6f Fix capitalization in 'Save changes'. 2017-01-16 18:00:10 -08:00
Tim Abbott
2bbad279ae Fix capitalization in 'Display settings'. 2017-01-16 18:00:10 -08:00
Tim Abbott
0667ae5d26 Fix capitalization in 'Change password'. 2017-01-16 18:00:10 -08:00
Tim Abbott
56bc421a6f Rename 'Filter Streams' to 'Filter streams'. 2017-01-16 18:00:10 -08:00
Tim Abbott
284931967a Rename 'All Streams' to 'All streams'. 2017-01-16 18:00:10 -08:00
Tim Abbott
d5f718a3e7 Rename 'Manage Streams' to 'Manage streams'. 2017-01-16 18:00:10 -08:00
Tim Abbott
dd8fb093c8 Rename 'Stream Settings' to 'Stream settings'. 2017-01-16 18:00:10 -08:00
Sampriti Panda
b4b6516ca0 narrow: Fix narrowing errors for topics with name 'home'.
Added a `.home-link` class to 'Home' links to separate them
from topic links with the name 'home'

Fixes #3340
2017-01-16 09:46:05 -08:00
Steve Howell
7b5bc40b42 Remove broken K+R link from reading list. 2017-01-16 09:00:20 -08:00
synicalsyntax
b228221fdf docs: Document *Follow steps* macro in user documentation styling guide. 2017-01-15 11:17:16 -08:00
synicalsyntax
c85274d665 docs: Add *Follow steps* macro to *Make a user an administrator* doc. 2017-01-15 11:16:18 -08:00
Cynthia Lin
9812e776c7 docs: Add *Follow steps* macro to *Invite a friend to Zulip* doc. 2017-01-15 11:16:18 -08:00
Cynthia Lin
12aa861b4f docs: Add *Follow steps* macro to *Configure mobile notifications* doc. 2017-01-15 11:16:18 -08:00
Cynthia Lin
7041a0d0e2 docs: Add *Follow steps* macro to *Change your organization's name* doc. 2017-01-15 11:16:18 -08:00
Cynthia Lin
84659574c9 docs: Add *Follow steps* macro to *Change a user's name* doc. 2017-01-15 11:16:18 -08:00
Cynthia Lin
1b173ee99a docs: Create *Follow steps* macro. 2017-01-15 11:16:18 -08:00
Cynthia Lin
67cc345fab docs: Fix x icon formatting. 2017-01-15 11:07:22 -08:00
Cynthia Lin
10769306b9 docs: Fix formatting error in *Upload and share files* doc. 2017-01-15 11:04:42 -08:00
Cynthia Lin
2cd8d0e70e docs: Conform *View an image at full size* doc to documentation styling guidelines. 2017-01-15 11:04:42 -08:00
synicalsyntax
760a267668 docs: Conform *View the exact time a message was sent* doc to documentation styling guidelines. 2017-01-15 11:04:42 -08:00
synicalsyntax
83946e29ec docs: Conform *View information about a message* doc to documentations styling guidelines. 2017-01-15 11:04:42 -08:00
synicalsyntax
6e77c9e9e6 docs: Update *View the markdown source of a message* doc.
Rewrite for better clarification.
2017-01-15 11:04:42 -08:00
synicalsyntax
191ef9fc33 docs: Update *Organize the Streams sidebar* doc.
Adds links to the stream actions described in the doc, also moves it to
a more relevant place in `index.md`
2017-01-15 11:04:42 -08:00
synicalsyntax
f64cb818e2 docs: Update *About streams and topics* doc. 2017-01-15 10:56:24 -08:00
synicalsyntax
ecc2259815 docs: Fix *Restrict user email addresses to certain domains* doc.
There were some formatting errors.
2017-01-15 10:56:24 -08:00
Steve Howell
44233cef4b Extract contrib_bots/bot_lib.py from run.py.
Splitting out some of the bot functions into a library
will make it easier for heavily customized bots to have
their own version of run.py, instead of the shared one
that we use for everyone now.  If they use bot_lib.py
directly, they will still most likely conform to
the "Handler" interface as long as they call
run_message_handler_for_bot.

Most bots should continue to use contrib_bots/run.py
for now.
2017-01-14 12:44:50 -08:00
JefftheBest1
69f9c300b8 ui: Change grey to gray in ui.js comment. 2017-01-14 12:36:06 -08:00
JefftheBest1
8e0aa90065 docs: Improved titles in signing-out.md. 2017-01-14 12:27:53 -08:00
Rafid Aslam
b4c02edc6b create_user: Remove Python 3 related hack about bot_owner.
This commit reverts commit "29673411df8dffd50198c0f01c5db8561a782adf"
due to the bug is not reproducible anymore (it seems likely this was a
bug in Django fixed between Django 1.8 and 1.10).

Fixes #1297.
2017-01-14 12:22:38 -08:00
adnrs96
153ad18807 Lint for duplicate ids in templates.
In this commit we enhance our current template linter to detect
duplicate ids and report them during lint checks. html_branches.py
was topped up with a new function build_id_dict for the purpose.

Also the get_tag_info function in same file was updated to parse
ids and classes more robustly in cases of template variables.
split_for_id_and_class function was added to serve this purpose.

Unit tests for both the functions were created under
tests/test_html_branches. Also a directory under tests called
test_template_data was created to hold templates for testing under
newly created functionality.

check_templates was modified to print to console any duplicates
detected.
showell reviewed my commit and helped me out.

Fixes #2950.
2017-01-13 17:00:22 -08:00
Sampriti Panda
196cf4367b urls: Move /messages/render to POST endpoint 2017-01-13 16:11:51 -08:00
hackerkid
510659d402 Add virtualenv activation in .zprofile. 2017-01-13 15:13:44 -08:00
JefftheBest1
d71cf373ec docs: Added extra step to Restrict user email addresses to certain domains 2017-01-13 15:12:30 -08:00
JefftheBest1
02aec2b2e3 docs: Organize the streams sidebar. Fixes #3272 2017-01-13 14:48:28 -08:00
Yago González
814c24cfd6 docs: Reorganize steps in Documenting your integration. 2017-01-13 13:50:58 -08:00
Rafid Aslam
38331aa81a right-sidebar: Remove border on the top of user list
Remove the border on the top of user list, especially on the top
of "USERS" word. The border is moved to bottom of feedback section.
2017-01-13 10:25:28 -08:00
Robert Hönig
b8fbfe305f Remove superfluous comment in triage_message(). (#3291) 2017-01-13 10:21:45 -08:00
Juan Verhook
4d500e626e interactive bots: Create your own virtual assistant 2017-01-13 07:22:04 -08:00
Rafid Aslam
85def38418 Change error handling in get_subscribers() in Zulip API client.
Fixes #3281.
2017-01-13 07:14:50 -08:00
Tim Abbott
b6476fdd81 stream creation: Disable autocomplete on filter text box. 2017-01-12 22:53:05 -08:00
Maydha K
dd23e09592 interactive bots: Create tic-tac-toe bot. 2017-01-12 17:26:19 -08:00
Robert Hönig
89a64de986 De-dup "outside_viewport" notifications on different tabs.
Pass down 'local_id' through functions that handle notifications for messages
that are sent locally. If 'local_id' is undefined, the message was not sent in
the respective tab, so no "outside_viewport" notification should be displayed.
This fixes #1783.
2017-01-12 17:08:18 -08:00
Katy310
7206685dae Make more streams visible when window is narrow.
When user list displays on the left, the maximum height of the
<code>stream-filters-container</code> is determined by the function
<code>confine_to_range(lo,val,high)</code>. By changing the value of
<code>lo</code> to 80, the <code>stream-filters-container</code>
resizes to 80 px instead of 40 px.

Fixes #2510.
2017-01-12 16:53:45 -08:00
Jackson
591efe2d64 interactive bots: Add FourSquare bot and documentation. 2017-01-12 16:51:13 -08:00
brockwhittaker
b3b361bae0 Add onhover grey checkmarks for unsubscribe streams.
This adds styling such that when you hover over a stream in the streams
list and you are not subscribed, you will see a faint grey checkmark
that serves as a target of where to click so you can subscribe to a
stream.
2017-01-12 16:47:32 -08:00
brockwhittaker
7762614482 Add deep link to unsubscribed streams list.
This adds a deep link behind a “+” icon above the streams list on the
left-sidebar which opens the subscriptions page and then also toggles
the tabs to go to the unsubscribed stream list.
2017-01-12 16:47:32 -08:00
Yago González
5fea825260 docs: Add the Reading list. 2017-01-12 16:42:52 -08:00
Tim Abbott
a64a1de023 lint: Be more permissive with Markdown links. 2017-01-12 16:42:51 -08:00
anirudhjain75
f2980f2504 docs: Edit about-streams-and-topics.md to conform to style guide 2017-01-12 16:30:01 -08:00
anirudhjain75
84d065265b docs: Edit browse-and-join-streams.md to conform to style guide 2017-01-12 16:28:42 -08:00
anirudhjain75
8b180b1455 docs: Edit create-a-stream.md to conform to style guide 2017-01-12 16:28:13 -08:00
Vamshi Balanaga
72cfc64144 docs: Fix grammatical error in Verify that your message has been succesfully sent 2017-01-12 15:48:30 -08:00
Anirudh Jain
705ae523db emoji picker: Add emoji next at cursor instead of end of message.
Simplified by tabbott.

Fixes: #3155
2017-01-12 15:31:18 -08:00
Steve Howell
baef662dcb Add tools/review for reviewing PRs.
This script ensures you are starting on master in a pristine
state, and then it creates a branch called review-NNNN for
PR #NNNN in your local repo, along with some basic stats about
the PR.
2017-01-12 15:26:40 -08:00
Rafid Aslam
d3ee53bdef Move endpoints to use stream_id instead of stream_name in their URLs
- Change `stream_name` into `stream_id` on some API endpoints that use
`stream_name` in their URLs to prevent confusion of `views` selection.

For example:
If the stream name is "foo/members", the URL would be trigger
"^streams/(?P<stream_name>.*)/members$" and it would be confusing because
we intend to use the endpoint with "^streams/(?P<stream_name>.*)$" regex.

All stream-related endpoints now use stream id instead of stream name,
except for a single endpoint that lets you convert stream names to stream ids.

See https://github.com/zulip/zulip/issues/2930#issuecomment-269576231

- Add `get_stream_id()` method to Zulip API client, and change
`get_subscribers()` method to comply with the new stream API
(replace `stream_name` with `stream_id`).

Fixes #2930.
2017-01-12 15:23:31 -08:00
Rafid Aslam
156eefacc2 API: Add json/get_stream_id endpoint
Add `json/get_stream_id` endpoint, used to convert `stream_name`
into `stream_id`.
2017-01-12 15:23:31 -08:00
Rafid Aslam
ead32b179c Add missing encodeURIComponent() on some API uses
Fixes #2930.
2017-01-12 15:23:31 -08:00
Rishi Gupta
f375caed46 /activity: Fix URL route for analytics.views.get_realm_activity.
analytics.views.get_realm_activity was taking a 'realm_str', but the URL
route was expecting a 'realm'. Changed the URL route to take a 'realm_str'.
2017-01-12 15:21:06 -08:00
Brock Whittaker
de6c7ad360 Fix Emoji Popover being leaked in certain circumstances.
Fixes the leaked popover issue where a popover for a dead element was
unable to be removed because it wasn’t connected to a parent that
existed in the DOM. Now they are cleaned up on every call to
popovers.hide_all().

Fixes: #3077.
2017-01-12 15:06:38 -08:00
Rishi Gupta
c2ca4cb1bb day2 email: Soften advice against using long topics.
In response to feedback that joining (and sending a first message to) a new
chat platform/org is already intimidating enough, and "Not Recommended" gets
the point across in a gentler way.
2017-01-12 15:04:51 -08:00
Tomasz Kolek
053feb947c Change way of handling comments event in jira integration. 2017-01-12 14:54:32 -08:00
Tomasz Kolek
9a60220c37 Refactor jira integration.
Remove events that don't exist.
Move handling issue events to separate function.
Make formatting strings using format function.
Change camelCase variable name convetion to using underscores.
Make unknown events error more clear.
Add issue_event_type_name param to all fixtures.
2017-01-12 14:54:32 -08:00
Tim Abbott
a6ba6432eb docs: Revise user guide for verifying messages were sent. 2017-01-12 14:34:16 -08:00
Vamshi Balanaga
84db825f88 docs: Add user guide for Verify that your message has been successfully sent. 2017-01-12 14:31:27 -08:00
synicalsyntax
c500266b70 docs: Conform *Upload and share files* doc to documentation styling guidelines. 2017-01-12 14:11:49 -08:00
synicalsyntax
4e85a0e409 docs: Conform *Preview your message before sending* doc to documentation styling guidelines. 2017-01-12 14:11:49 -08:00
synicalsyntax
2d1ef283a0 docs: Conform *Add emoji* doc to documentation styling guidelines. 2017-01-12 14:11:49 -08:00
synicalsyntax
b3cc10377e docs: Conform *Restrict user email addresses to certain domains* doc to documentation styling guidelines. 2017-01-12 14:11:49 -08:00
synicalsyntax
7c57c84eb2 docs: Conform *Set notifications for a single stream* doc to documentation styling guidelines. 2017-01-12 14:11:49 -08:00
synicalsyntax
be26c4e67e docs: Conform *Use Zulip on Android* doc to documentation styling guidelines. 2017-01-12 14:11:49 -08:00
synicalsyntax
2505a1be5c docs: Conform *Signing out* doc to documentation styling guidelines. 2017-01-12 14:11:49 -08:00
synicalsyntax
57d2dd9d44 docs: Conform *Deactivate your account* doc to documentation styling guidelines. 2017-01-12 14:11:49 -08:00
polypmer
2c58af9305 Check and Uncheck All only on visible (filtered) users.
When filtering users in the new stream form, check all
and uncheck all will only effect those users who are filtered,
visible in the dom.

Includes a Casper test for the new condition.
2017-01-12 13:58:54 -08:00
Steve Howell
7bd16b3946 dev tools: Diagnose venv problems more clearly.
In tools/diagnose, we now catch an ImportError if
we cannot import django, and we instruct the
devloper about the mostly likely remedies.
2017-01-12 13:46:05 -08:00
royabouhamad
aa14627b07 Interactive bots: Create a thesaurus bot. 2017-01-12 13:07:12 -08:00
andrewallen00
badd4be155 docs: Add user guide for configure mobile notifications. 2017-01-12 10:52:08 -08:00
Steve Howell
5ec0bc1213 Fix typing import in tools/diagnose. 2017-01-12 10:49:11 -08:00
brockwhittaker
3cb0db586d Change the "top of messages" logo to SVG from PNG.
This changes the logo that sits at the top of the messages to an SVG
rather than a PNG used as the current navbar logo that is filtered to
be grayscale.

This fixes a significant performance regression that had been caused
by adding that logo to the top of the feed.

Thanks to @rishig for generating the SVG!
2017-01-12 10:36:29 -08:00
K.Kanakhin
aaf82ae090 documentation-crawler: Check images in help documentation.
This checks both that all images under static/images/help/ are used in
the help documentation, and also that none of the image tags are broken.

- Improve documentation spiders and crawler with spider error state.

Fixes #3070.
2017-01-12 10:02:32 -08:00
K.Kanakhin
9fecd85e4a user-docs-images: Remove unnecessary user docs images.
Fixes #3070.
2017-01-12 10:02:26 -08:00
Tim Abbott
8842954e3c help: Remove links to screenshots of icons. 2017-01-12 10:00:49 -08:00
Robert Hönig
8b6a28dfa6 Fix virtual_fs bot trying to read a directory
This commit prevents the bot from crashing when a command
like 'fs read /home' is entered. Instead, an error is
displayed.
2017-01-12 09:16:17 -08:00
JefftheBest1
2d7ee577d5 docs: Join a Zulip Organization 2017-01-12 09:12:08 -08:00
Bojidar Marinov
bc056488b6 docs: Edit alert-words.md to conform to style guide. 2017-01-12 08:52:19 -08:00
Bojidar Marinov
d4b0f04fac docs: Edit configure-audible-notifications.md to conform to style guide. 2017-01-12 08:52:19 -08:00
Bojidar Marinov
c0fd0e3ee3 docs: Edit configure-desktop-notifications.md to conform to style guide. 2017-01-12 08:52:19 -08:00
Bojidar Marinov
ee9eb2004e docs: Edit mute-a-stream.md to conform to style guide. 2017-01-12 08:52:19 -08:00
Bojidar Marinov
d4571c75d3 docs: Edit and extend mute-a-topic.md to conform to style guide. 2017-01-12 08:52:19 -08:00
JefftheBest1
a549ed6e65 Removed accommodate typos 2017-01-12 04:53:31 -08:00
JefftheBest1
f0afa3e8df Fixed typos with receive 2017-01-12 04:52:44 -08:00
JefftheBest1
9de75f5167 Fixed typos with separate 2017-01-12 04:52:05 -08:00
JefftheBest1
110398bf36 Fixed typos in test-queue-worker-reload 2017-01-12 04:51:27 -08:00
JefftheBest1
ff8639f9db Fixed typos with threshold. 2017-01-12 04:50:20 -08:00
JefftheBest1
effa7523a4 Fixed a typo in zulip_change_commit.py 2017-01-12 04:49:47 -08:00
JefftheBest1
5008f45112 Fixed typo in munin.conf.erb 2017-01-12 04:49:19 -08:00
Steve Howell
3ee733eb51 Extract encode_operand/decode_operand in hashchange.js.
These are just one-liners for now, but they will set us up
to do different encodings for different narrows.
2017-01-11 18:31:17 -08:00
Steve Howell
030c6649ae tests: Improve hashchange coverage for operators.
Test round tripping of operators in hashchange.js.
2017-01-11 18:31:17 -08:00
Tim Abbott
da84ff3746 backends: Fix some slightly confusing error messages. 2017-01-11 18:08:29 -08:00
JefftheBest1
71d34e91bd Fixed typos in backends.py 2017-01-12 13:05:50 +11:00
Vamshi Balanaga
a232060e18 docs: improve docs for contrib_bots. 2017-01-11 16:32:02 -08:00
Sampriti Panda
e666a62c6a search: Extract 'Sent by me' suggestion logic into separate method.
This also adds a nice test suite for it.
2017-01-11 16:30:07 -08:00
Sampriti Panda
c613e510ed search: Add autocomplete for 'from' operator.
Fixes #2932.
2017-01-11 16:29:58 -08:00
Jackson
a9235e4ccb integrations: Add documentation for Papertrail. 2017-01-11 16:24:30 -08:00
Yago González
b0b9ee20e7 integrations: Add code for OpenShift. 2017-01-11 16:23:11 -08:00
JefftheBest1
e74cb2d11c Fixed typo in index.md 2017-01-11 15:50:22 -08:00
Jackson
12359f6876 docs: Edit upload-and-share-files.md to conform to style guide. 2017-01-11 15:35:56 -08:00
Jackson
174b925875 docs: Edit add-emoji.md to conform to style guide 2017-01-11 15:33:26 -08:00
Jackson
7fcf64a18a docs: Edit preview-your-message-before-sending.md to conform to style guide 2017-01-11 15:32:09 -08:00
Rishi Gupta
5d10124830 test-signup: Change failed signup test to be on an open realm.
Previously, test_failed_signup_due_to_restricted_domain used a realm with
restricted domains, but also with invite_required = True. We didn't have a
test that tested for a failed signup in an open realm with restricted
domain, so edited test_failed_signup_due_to_restricted_domain to test for
that.
2017-01-11 15:26:47 -08:00
Robert Hönig
639c4023bc Terminate run.py without throwing tracebacks.
Pressing control-c while run.py is being executed has terminated the
script, but threw an ugly traceback. To signal the user that his
method of exit was appropriate, we handle control-c calling exit(0).
2017-01-11 15:25:20 -08:00
Robert Hönig
f9730e774a Rename the RestrictedClient class to BotHandlerApi
As a first step into restructuring the run.py layout to support a
worker and an API-wrapper class, we rename the RestrictedClient
class appropriately.
2017-01-11 15:25:20 -08:00
Robert Hönig
02bfb46398 Hide 'client' and 'rate_limit' from 'contrib_bots' bots.
'contribot_bots' should only provide a restricted access to the
client API, yet 'client' and 'rate_limit were fully exposed. While
not fully restricting access to those objects, this commits hides
them with prepending underscores.
2017-01-11 15:25:20 -08:00
Tim Abbott
a1c0fa4c3d lint: Enable comma-dangle eslint rule.
This styling doesn't work on IE8 and older browsers, but we've
basically abandoned IE8 as the newest browser we don't support anyway.

If we wanted to restore IE8 support, it wouldn't be hard to reverse
this transformation as part of our static asset build process.
2017-01-11 15:23:42 -08:00
Tim Abbott
998dff9e50 lint: Add dangling commas in JavaScript objects. 2017-01-11 15:23:42 -08:00
Tim Abbott
7ca2d21d97 casper: Clean up some line-wrapping.
This feels a bit more readable than the original version; noticed it
while playing with the comma-dangle linter.
2017-01-11 15:23:42 -08:00
Steve Howell
fb9ac98510 Fix lint error with help/main.html template. 2017-01-11 14:58:53 -08:00
JefftheBest1
95604aa212 docs: Restrict user email addresses to certain domains 2017-01-11 14:49:12 -08:00
JefftheBest1
7f7df149ae Added footer to all user docs. Fixes #3112 2017-01-11 14:24:56 -08:00
Yago González
a613bc43fe frontend: Keep showing hover menu after opening popovers.
Fixes: #3172
2017-01-11 14:20:48 -08:00
Tomasz Kolek
e6ab93a4c4 Fix Bitbucket2 integration fulfilled event type.
The "merged" event type was apparently renamed to "fulfilled".
2017-01-11 14:18:07 -08:00
Tomasz Kolek
f0cc6d8029 Adjust Taiga integration to new payloads format.
Update all payloads.
Remove move task between User stories events.
Update code to handle new payload format.

Fixes: #2318.
2017-01-11 14:17:44 -08:00
Tommy Ip
e863d4d35e frontend test: De-duplicate test.
Merged two tests since they both use the same test data. The file name
of `presence_list_performance.js` also causes confusion as it is no longer
use for performance testing.
2017-01-11 14:12:41 -08:00
Steve Howell
48e68791e8 Fix duplicate HTML id: fmt_help_table.
We replace the id with a class called help-table.
2017-01-11 14:00:10 -08:00
Robert Hönig
52641a2b11 Fix exception thrown by custom notification.
The exception was thrown by a misplaced quotation mark in notifications.py.
Fixes #3175.
2017-01-11 12:49:45 -08:00
Vamshi Balanaga
e329263521 docs: Add user guide for 'Add Bot or Integration' 2017-01-11 12:20:39 +01:00
sidhant bhavnani
1bdbf26dd8 docs: Only allow admins to create new streams. 2017-01-11 11:57:21 +01:00
JefftheBest1
207b2e0b25 docs: Set notifications for a single stream 2017-01-11 10:55:58 +01:00
Rishi Gupta
b22f574224 Re-write models.get_realm to use Django convenience function. 2017-01-10 23:18:26 -08:00
Tim Abbott
145c5da8bf docs: Fix heading for roadmap doc. 2017-01-10 23:01:32 -08:00
JefftheBest1
49cb9b0236 docs: Share a message or conversation 2017-01-10 20:53:26 -08:00
Rishi Gupta
3f2a002c6e analytics/lib/counts.py: Fix one of the COUNT_STATS definitions.
Fixes an error in the definition of
COUNT_STATS['messages_sent_to_stream:is_bot']. The CountStat needs a
group_by argument since it is supposed to group by UserProfile.is_bot.
2017-01-10 20:41:07 -08:00
Rishi Gupta
977f5b9178 analytics/lib/counts.py: Fix error in count_message_type_by_user_query.
This query counts the number of messages each user has sent, subgroup'd by
whether the message was a private_message (PM or sent to a huddle), sent to
a 'private_stream', or sent to a 'public_stream'.

We need to join on zerver_stream to find out whether stream messages were
sent to public streams or private streams, but it needs to be a LEFT JOIN
rather than a JOIN so that we preserve the messages sent to non-streams.
2017-01-10 20:41:07 -08:00
cosmicasymmetry
9e59b3fb0a docs: Edit send-a-group-of-people-a-private-message.md to conform to style guide 2017-01-10 19:27:26 -08:00
cosmicasymmetry
b04200f803 docs: Edit invite-a-friend-to-zulip.md to conform to style guide 2017-01-10 19:27:26 -08:00
Jackson
663ecc11ca docs: Edit browse-and-join-streams.md to conform to style guide 2017-01-10 18:21:39 -08:00
Jackson
cd9045d9fd docs: Edit view-messages-from-a-stream.md to conform to style guide 2017-01-10 18:21:39 -08:00
Jackson
4ff4787d83 docs: Edit make-an-announcement.md to conform to style guide 2017-01-10 18:21:39 -08:00
Rishi Gupta
6374596a77 analytics: Add initial fixture for testing views. 2017-01-10 17:48:07 -08:00
Yago González
25dbe35747 api: Support file uploads to the API.
Now, the `Client.do_api_query()` method supports sending files to the
API.

This has allowed the implementation of a new method,
`Client.upload_file(file)`.  It simply uploads the file set in the
parameter, and returns the API's response (that includes the URI).

Despite the fact that `do_api_query()` supports multiple files as
parameters, `upload_file()` doesn't, because right now the API isn't
capable of managing more than a file in the same request.
2017-01-10 17:46:00 -08:00
Yago González
089c0a861d docs: Add user guide for Using Zulip on Android. 2017-01-10 17:27:06 -08:00
Anirudh Jain
dcc13c504b Move the reactions popover to point towards the chevron.
This fixes an issue where the actions popover being replaced by the
reactions popover would feature an unnecessary jolt.

Fixes: #3174
2017-01-10 17:18:55 -08:00
Tim Abbott
2de0e1eec4 lightbox: Remove use of unicode in CSS.
This caused errors in `manage.py collectstatic`.
2017-01-10 17:11:34 -08:00
Tim Abbott
6d3ea3f663 contrib_bots: Fix lint error in rate limiting code. 2017-01-10 15:10:17 -08:00
Robert Hönig
3efbadc37b Add a rate limit for bots in contrib_bots
To prevent bots from accidently entering an infinite message loop,
where they send messages as a reacting to their own messages,
this commit adds the RateLimit class to run.py. It specifies how
many messages can be sent in a given time interval. If this rate
is exceeded, run.py exits with an error.
Fixes #3210.
2017-01-10 13:42:40 -08:00
brockwhittaker
4d10c4274b Fix text overflow in lightbox.
This fixes the user’s name to not fall on the next line. Instead it
appears on the same line and overflows properly into an ellipsis so it
theoretically should never overflow on to the next line.
2017-01-10 12:50:11 -08:00
Tim Abbott
914d9a3412 reactions: Fix bottom margin to look good on selected message. 2017-01-10 12:32:30 -08:00
Tommy Ip
bb0225acec emoji reactions: Prevent scroll bar from appearing.
Fixes #3188.
2017-01-10 12:32:30 -08:00
Tim Abbott
007d4becfd Revert "update-sockjs: Update sockjs from version 0.3.4 to 1.1.1."
This reverts commit 7bf10ec74f.

Apparently, SockJS 1.1.1 is broken with the browser used in our legacy
desktop app, resulting in messages being silently not sent.
2017-01-10 11:46:15 -08:00
Tim Abbott
4a57367a51 requirements: Document more clearly ports required for Zulip. 2017-01-10 11:46:15 -08:00
Uma
dd8291bb50 Improved 'readme.md' file in contrib_bots/lib 2017-01-10 07:03:57 -08:00
Steve Howell
b45cd5538e Add node tests for password checks. 2017-01-10 04:55:41 -08:00
Bojidar Marinov
786dd0fca4 auth: Make min password length and strength configurable.
This adds some configuration options to settings.py, namely
PASSWORD_MIN_LENGTH and PASSWORD_MIN_QUALITY, which control
when the frontend validator invalidates the password.

Closes #2628
2017-01-10 04:55:41 -08:00
synicalsyntax
e6c3aaae12 docs: Fix broken link error. 2017-01-09 19:30:26 -08:00
synicalsyntax
a74cbe7bd4 docs: Confrom *Move the users list to the left sidebar* doc to documentation styling guidelines. 2017-01-09 19:30:26 -08:00
synicalsyntax
f0ab21918d docs: Confrom *Change the date and time format* doc to documentation styling guidelines. 2017-01-09 19:30:26 -08:00
synicalsyntax
764a54ae26 docs: Merge *Searching* and *Advanced search* docs.
Most information was redundant and unnecessary.
2017-01-09 16:21:22 -08:00
synicalsyntax
9387c34623 docs: Conform *View messages from a topic* doc to documentation styling guidelines. 2017-01-09 16:12:54 -08:00
synicalsyntax
86e2a98324 docs: Conform *View messages from a user* doc to documentation styling guidelines. 2017-01-09 16:12:54 -08:00
synicalsyntax
d4ec85dae2 docs: Conform *Zulip glossary* doc to documentation styling guidelines. 2017-01-09 16:12:54 -08:00
Cynthia Lin
7b2bf3b56f docs: Conform *The Zulip browser window* doc to documentation styling guidelines. 2017-01-09 16:12:54 -08:00
Cynthia Lin
fe96a6d2a6 docs: Wrap lines in *Change a stream's color* doc. 2017-01-09 16:12:54 -08:00
Cynthia Lin
44d3a07691 docs: Fix grammatical errors in *Delete a stream* doc. 2017-01-09 16:12:54 -08:00
Tommy Ip
b70f6a6b7a Add basic system architecture visualization.
This diagram shows the core components of Zulip.
2017-01-09 21:29:15 +00:00
Tim Abbott
3f8d4193da lint: Fix % comprehensions being used without a tuple. 2017-01-09 11:45:11 -08:00
Rishi Gupta
494c1a2b55 Remove unnecessary uses of Realm.domain in zerver/tests. 2017-01-09 11:26:08 -08:00
Rishi Gupta
ac29928d91 Remove domain from analytics management commands. 2017-01-09 11:26:08 -08:00
Rishi Gupta
e14f575979 Remove domain from analytics/views.py. 2017-01-09 11:26:08 -08:00
Tim Abbott
1d5edff927 setup_venv: Give up if virtualenv-clone isn't working.
virtualenv-clone can sometimes fail if the old virtualenv is
broken; in that case, we can just make a new one.
2017-01-09 11:21:42 -08:00
sinwar
3f350391ce docs: Ban the term realm from user documentation.
Fixes #3031.
2017-01-09 10:58:19 -08:00
Rishi Gupta
552d626ef2 analytics: Fix FillState.last_modified not being updated.
We were updating FillState with FillState.objects.filter(..).update(..),
which does not update the last_modified field (which has auto_now=True).
The correct incantation is the save() method of the actual FillState
object.
2017-01-08 23:36:34 -08:00
Tim Abbott
3a64857a4c lint: Fix long lines not being treated as actual errors.
This led to Travis CI not reporting on line-too-long errors.
2017-01-08 22:48:27 -08:00
Tim Abbott
464411833d requirements: Upgrade mypy to 0.4.6 release. 2017-01-08 22:48:25 -08:00
Tim Abbott
b54f8b3b14 lint: Fix incorrect line length calculations in Python 2.
Previously, we would incorrectly be counting bytes in Python 2, which
meant lines with unicode characters in them appeared to the linter to
be far longer than they actually were.
2017-01-08 22:46:02 -08:00
Rishi Gupta
190d320afa analytics: Change CountStat.property from Text to str. 2017-01-08 17:24:51 -08:00
Rishi Gupta
a07757c127 analytics/views: Fix query in get_messages_sent_to_realm. 2017-01-08 17:24:51 -08:00
Rishi Gupta
f8962d521d analytics: Fix uses of 'interval' in arguments and variable names.
interval refers to a time interval, and frequency refers to something that
semantically means something closer to 'hourly' or 'daily'.

Currently, interval can have values 'hour', 'day', or 'gauge', and frequency
can only have values 'hour' and 'day'.
2017-01-08 17:24:51 -08:00
Rishi Gupta
f5899dd14b analytics: Add lib/ function to drop all analytics tables. 2017-01-08 17:24:51 -08:00
Rishi Gupta
73dc904e9c analytics: Move time_range from views.py to lib/time_utils.py 2017-01-08 17:24:51 -08:00
Tommy Ip
011eac1d92 bots: Fix bare except clause. 2017-01-09 00:39:33 +00:00
Tommy Ip
008663abd8 zerver: Fix bare except clause. 2017-01-09 00:38:31 +00:00
Tommy Ip
7738edb62f contrib_bots: Fix bare except clause. 2017-01-08 16:25:22 -08:00
Tommy Ip
28abfca565 analytics: Fix bare except clause. 2017-01-08 16:25:22 -08:00
Tommy Ip
ada95c4fca bots: Fix bare except clause. 2017-01-08 16:25:22 -08:00
Tommy Ip
9f38277224 bots: Fix bare except clause. 2017-01-08 16:25:22 -08:00
Tommy Ip
89a126b93f zerver: Fix bare except clause. 2017-01-08 16:22:21 -08:00
Tommy Ip
3823376b3f zilencer: Fix bare except clause. 2017-01-08 16:22:21 -08:00
Tommy Ip
89dc739856 tools: Fix bare except clause. 2017-01-08 16:22:21 -08:00
Tommy Ip
e04afe9bda tools: Fix bare except clause. 2017-01-08 16:22:21 -08:00
Tim Abbott
f3b5683e77 views: Rename __init__.py to zerver.views.registration.
This completes the cleanup process of eliminating functions in the
root zerver/views/__init__.py module.
2017-01-08 16:21:15 -08:00
Tim Abbott
48f1b4e1ab views: Extract zerver.views.muting. 2017-01-08 16:21:15 -08:00
Tim Abbott
7beff88f5f views: Extract zerver/views/home.py.
This is a significant piece of the remaining effort required to
eliminate the catch-all zerver/views/__init__.py.
2017-01-08 16:21:15 -08:00
Robert Hönig
a261801cef Update bots guide statement about the interception of PMs 2017-01-07 15:02:29 -08:00
Tim Abbott
6a7befa812 third: Remove copyright notice for removed review tool. 2017-01-07 10:53:20 -08:00
Tim Abbott
24df5fbd97 Delete remains of deprecated inject-messages. 2017-01-07 10:53:20 -08:00
AZtheAsian
0dc9ac7dac Delete deprecated iframe-bot. 2017-01-07 10:53:20 -08:00
Brock Whittaker
1d414a432f Re-order reactions CSS for better understanding.
This reorders the structure of the styling for the emoji reactions
to better follow the order of the markup.
2017-01-07 10:18:32 -08:00
Brock Whittaker
e41b0b80ef Emoji CSS refactoring for FF support.
Emoji styling was broken in Firefox browser due to its lack of support
for the zoom property.

This replaces the zoom property with the transform property that now
scales the emojis down to 70% of their original size.
2017-01-07 10:18:32 -08:00
Tim Abbott
81a19375d2 hotkey: Fix exiting the subscriptions page with "escape".
This had apparently regressed because it was checking the wrong
selector, and also didn't do the right thing to exit.
2017-01-06 23:45:03 -08:00
Tim Abbott
9f1fca30df subs: Access streams to copy from by ID in new stream creation. 2017-01-06 23:19:45 -08:00
Tim Abbott
9ff8c9e358 subs: Access users by ID in new stream creation. 2017-01-06 23:18:53 -08:00
Tim Abbott
e228243723 install-aws-server: Add support for installing zulip.conf. 2017-01-06 21:58:16 -08:00
Tim Abbott
c6bdc2130b install-aws-server: secrets enhancements. 2017-01-06 21:57:20 -08:00
Tim Abbott
ed0da5f874 install-aws-server: Fix usage output. 2017-01-06 21:57:20 -08:00
Tim Abbott
3e32102016 nagios: Fix various critical issues not tagged as pageable. 2017-01-06 21:49:20 -08:00
Tim Abbott
edebf7619b puppet: Add PAM common_session disabling systemd-login.
This fixes a weird problem with systemd where logging into a server
via ssh frequently has a 15s+ lag.
2017-01-06 21:49:15 -08:00
Tim Abbott
93c2c19775 nagios: Increase process count limits. 2017-01-06 21:49:15 -08:00
Tim Abbott
2c6cb37385 munin: Add default munin configuration template. 2017-01-06 21:44:57 -08:00
Tim Abbott
46fc136943 feedback-bot: Add logging for successfully submitted feedback. 2017-01-06 21:42:16 -08:00
Tim Abbott
9ab8e7ba34 nagios: Disable swap checks for servers with no swap. 2017-01-06 21:39:07 -08:00
Tim Abbott
3e01ed1f73 nagios: Increase NTP max_check_attempts.
NTP often suffers from brief interruptions of service that lead to
spurious Nagios alerts; it makes sense to suppress these.
2017-01-06 21:32:43 -08:00
Tim Abbott
e4420b08d2 zulip_ops: Disable unattended upgrades of security packages.
Since Zulip does not handle e.g. postgres server restarts gracefully,
it's best for a system administrator to manually trigger security
updates.
2017-01-06 21:30:56 -08:00
Tim Abbott
6f9c73d0e5 zmirror: Update Debathena release in configuration.
The zulip_ops configuration is now for xenial, not obsolete wheezy.
2017-01-06 21:30:41 -08:00
Tim Abbott
bd9176d1d9 nagios: Remove some default files.
Nagios ships with a bunch of default configuration files that one
needs to delete in order to configure it.
2017-01-06 21:25:12 -08:00
Tim Abbott
7083899e77 zulip_ops: Add postgres config for enabling Nagios.
The old zulip_ops Nagios configuration depended on Nagios having the
ability to login as the zulip user (with essentially full write
access); this configuration is helpful for limiting nagios to special
"nagios" user with more limited credentials.
2017-01-06 21:24:24 -08:00
Tim Abbott
204edb0f85 zulip_ops: Cleanup pg_hba.conf configuration. 2017-01-06 21:23:51 -08:00
Tim Abbott
30c57eb2ae zulip_ops: Add basic .emacs for production. 2017-01-06 21:20:21 -08:00
Tim Abbott
eb87d04168 puppet: Remove xxxxx password hardcoding in recovery.conf. 2017-01-06 21:20:21 -08:00
Tim Abbott
6404a1a5ff zulip_ops: Add nagios-plugins-contrib.
This has a number of useful nagios plugins.
2017-01-06 21:19:59 -08:00
Tim Abbott
f7b77008ef zulip_ops: Add aptitude dependency.
This is useful for `aptitude why`.
2017-01-06 21:19:50 -08:00
Tim Abbott
2510a51a8a zulip_ops: Add letsencrypt dependency. 2017-01-06 21:19:31 -08:00
Tim Abbott
65774e1c4f zulip_ops: use check_postgres package from apt. 2017-01-06 21:18:55 -08:00
Tim Abbott
165b4d3126 nagios: Fix check_send_receive_time threshholds.
Previously, the CRITICAL state would never fire (because x > 6 =>
x > 3).  Additionally, 6s is not so unusually high as to deserve being
immediately pageable.
2017-01-06 21:16:37 -08:00
Tim Abbott
246bdbd829 update-prod-static: Fix node_modules/.bin being unavailable in prod.
Apparently `manage.py collectstatic` by default strips files starting
with "." from what it collects.  This is a reasonably precaution,
though mostly irrelevant to us, since Zulip primarily runs that as
part of build-release tarball, which runs in a clean directory.

It also breaks our current approach for transferring node_modules to
prod machines via release tarballs; this change fixes that bug.
2017-01-06 20:23:46 -08:00
Tim Abbott
7df44f2e87 minify-js: Auto-detect virtualenv when possible.
Usually, update-prod-static takes care of this, but it's useful for
debugging purposes to be able to rerun this manually.
2017-01-06 19:55:08 -08:00
Rishi Gupta
38c2dc8790 Change settings.SYSTEM_ONLY_REALMS to use Realm.string_id. 2017-01-06 19:45:08 -08:00
Rishi Gupta
89af775e03 test_classes: Remove domain from ZulipTestCase.register. 2017-01-06 19:45:08 -08:00
Rishi Gupta
021c65a656 test_classes: Remove domain from ZulipTestCase.submit_reg_form_for_user. 2017-01-06 19:45:08 -08:00
Yago González
dafe06613e docs: Add user guide for Send a status message.
Edited by tabbott for clarity.
2017-01-06 19:39:40 -08:00
Tim Abbott
3a3a1872e7 travis: Prevent upgrading oracle-java9-installer.
This fixes a minor performance problem, and also avoids errors when
Oracle's Java installer site is down.
2017-01-06 19:30:16 -08:00
Cynthia Lin
57e7941ba9 docs: Remove unnecessary content originally extracted from old ToC. 2017-01-06 18:41:57 -08:00
Tim Abbott
e256073214 docs: Remove all the redundant content from the index. 2017-01-06 18:41:07 -08:00
Tim Abbott
e2533cac7d docs: Clean up message formatting duplication. 2017-01-06 18:32:36 -08:00
Tim Abbott
49a8a0e292 docs: Remove old table on contents. 2017-01-06 18:32:24 -08:00
Cynthia Lin
e66abbebf9 docs: Clean up table of contents. 2017-01-06 18:29:06 -08:00
Cynthia Lin
ad230de81b docs: Extract new docs from sections of old index page. 2017-01-06 18:29:06 -08:00
Tim Abbott
d73cb4687e docs: Fix explanation of unicode emoji. 2017-01-06 18:29:03 -08:00
Tim Abbott
89b47bb653 Revert "Fix Small Image Preview Sizing."
This reverts commit e4761782e0.

This caused performance problems and jolting of the main UI, because
it broke the important invariant that the height of a Zulip message
should not depend on the content of slow-to-load assets such as
images.
2017-01-06 17:21:15 -08:00
Tim Abbott
0f50ef12f5 scripts: Fix path to install-node. 2017-01-06 16:48:18 -08:00
Brock Whittaker
c961172ab1 css: Fix emoji reactions jolt and padding issues.
This fixes two issues:

* If you had around 10 distinct emoji reactions on a message (enough
  to force a line wrap if the add-your-emoji button was visible),
  Zulip would add that button into a new row on hover, jolting the
  message feed.  This fixes that problem by leaving a blank last line
  for the add-your-emoji button.

* We were incorrectly showing the padding for the emoji reactions
  region even if there were no emoji reactions, causing messages to
  have too much padding.
2017-01-06 16:38:12 -08:00
Tim Abbott
54acbc41ed prod: Ensure the Zulip version of node is installed. 2017-01-06 16:18:29 -08:00
Tim Abbott
e4b065e03a Move tools/setup/install-node to scripts/setup/. 2017-01-06 16:18:29 -08:00
Tim Abbott
374e900432 upgrade-zulip: Fix bug in migrations detection. 2017-01-06 16:18:29 -08:00
Tim Abbott
c65820618f settings: Set an intelligent default for ALLOWED_HOSTS. 2017-01-06 14:46:47 -08:00
Tim Abbott
f3ee0eb67b settings: Improve ALLOWED_HOSTS defaults. 2017-01-06 14:46:47 -08:00
Tim Abbott
a6cd0650fe css: Fix styling for bulleted lists.
Previously, Zulip's bulleted list styling didn't have balanced
margins, which mean that they would look misplaced within single-line
messages.
2017-01-06 14:46:47 -08:00
Tim Abbott
bea788ec73 docs: Fix executable help documentation images. 2017-01-06 14:18:30 -08:00
Tim Abbott
e5fbea1007 upgrade-zulip: Move static asset compilation before shutdown.
This saves about a minute of downtime when using
upgrade-zulip-from-git in the default configuration.

It should also save several seconds of downtime when upgrading to a
production release tarball as well.
2017-01-06 14:04:54 -08:00
Tim Abbott
90ee8d1207 upgrade-zulip: Only pause for migrations if not current.
This saves about 1s of downtime when doing a no-op upgrade with the
default settings.  Small, but worthwhile.
2017-01-06 14:03:55 -08:00
Harshit Bansal
ceb636dbd9 Manage allowed domains from admin settings.
Fixes: #1867.
2017-01-06 12:03:31 -08:00
Tim Abbott
a39643da61 lint: Require space after likely ends of sentences in help. 2017-01-06 11:18:45 -08:00
Umair Khan
6dc8d5c39e Fix transaction issue in huddle creation.
Previously, huddles were created outside of a transaction (and then
the actual initialization of the huddle object was done inside). This
made the huddle visible to other threads of execution while the
related data was still invisible due to transaction commit latency.
2017-01-06 10:54:06 -08:00
Rishi Gupta
3514040d2e tests.py: Rename FindMyTeamTestCase to TestFindMyTeam. 2017-01-06 10:42:28 -08:00
Rishi Gupta
fdb47fc5ee find my team: Canonicalize URL route.
Change URL endpoint to use underscores, not dashes, and change name to use
the full path to the view function. See e.g. /create_realm.
2017-01-06 10:42:28 -08:00
Rishi Gupta
757297b72f Move find_my_team functions out of views/auth.py
The general __init__ file is a more natural home, and where other endpoints
(e.g. create_realm, etc) live.

Also changes forms.ValidationError to django.core.exceptions.ValidationError
to match the rest of the file/codebase.
2017-01-06 10:42:28 -08:00
Rishi Gupta
0039689acb find team flow: Update text in emails and templates. 2017-01-06 10:42:28 -08:00
Rishi Gupta
e481fef9e1 Move find_team_email subject to a templates/ file. 2017-01-06 10:42:28 -08:00
Rishi Gupta
7cb5d26999 Rename find_team_email_html.txt to find_team_email.html. 2017-01-06 10:42:28 -08:00
Rishi Gupta
f5d5b2525c notifications.py: Change email template file endings from .text to .txt.
We use .txt for all other emails (i.e. ones that don't go through
notifications.py) in the codebase.
2017-01-06 10:42:28 -08:00
Rishi Gupta
8a07545afb Rename digest_email_txt.html to digest_email.html.
The .html file ending is clearer and more in line with our other
email files.
2017-01-06 10:42:28 -08:00
Rishi Gupta
416c8f3052 digest_email_html.txt: Fix html linter errors. 2017-01-06 10:42:28 -08:00
Rishi Gupta
8d038eef2f digest emails: Move the subject line to a templates/ file.
To match how we do the subject line for the emails in followup/ and
invitation/.
2017-01-06 10:42:28 -08:00
Brock Whittaker
3f286e65d1 Add logo to the top of the message feed.
Add the Zulip logo to the top of the messages feed to show that there
are no more messages to load, or that it is loading more (if the
spinner is still around).
2017-01-06 10:37:54 -08:00
Brock Whittaker
7b00bd6f7e Remove the old spinner, replace with new one.
This removes the old content loading spinner and replaces it with a new
SVG.
2017-01-06 10:37:54 -08:00
Tommy Ip
b0b0c885a6 Update .editorconfig to use 4 spaces for handlebars/html. 2017-01-06 09:31:01 -08:00
Tim Abbott
b513e63f5e docs: Cleanup whitespace in user docs style guide. 2017-01-06 09:01:27 -08:00
synicalsyntax
c9eaf67c78 docs: Update documentation styling guide with new guidelines. 2017-01-05 20:23:26 -08:00
Rafid Aslam
88ec999cf3 tests: Bump up max length queries in test_bulk_message_fetching().
Bump up max length queries in `test_bulk_message_fetching()` to 11
in `zerver/tests/test_messages.py` to avoid test failing when run
this test alone.

Fixes #3087.
2017-01-05 17:30:47 -08:00
Brock Whittaker
3d5c24ab40 Show date correctly on message headers.
This shows a date on a message header whenever the date of that
message is different than the date of the previous message.

The previous logic was bugged and didn't display dates in headers at
date transition points.
2017-01-05 17:28:08 -08:00
JefftheBest1
af1998fbb8 docs:Added make an announcement 2017-01-05 17:26:53 -08:00
synicalsyntax
9d09ab11a9 docs: Replace images with FontAwesome icons. 2017-01-05 16:43:00 -08:00
Brock Whittaker
b976e179e6 css: Restyle Open-Graph Links.
This styles open-graph links to be cleaner and smaller.
2017-01-05 16:15:01 -08:00
Brock Whittaker
5d2ceb2f16 Change default emoji reaction styling.
This changes the styling to be slightly more compact, have more bottom
padding between the edge of the message wall, and have more consistency.
2017-01-05 15:46:06 -08:00
Steve Howell
90fa797f9b Use stream id to live-update messages for name changes.
When we change a stream name, we now use the stream id as the
key to find messages we need to live update.  This eliminates
some possible race conditions from two users renaming a stream.

This commit introduces message_live_update.js.

The new call stack is this:

    subs.update_subscription_properties
    subs.update_stream_name
    message_live_update.update_stream_name
    message_list.update_stream_name
2017-01-05 15:32:45 -08:00
Steve Howell
99b5c00ec1 Add stream id to message dictionary.
We now pass the stream id in the messages we send to
our clients.
2017-01-05 15:32:45 -08:00
Sampriti Panda
45a5e47e1b compose: Fix bug on sending message to invalid streams.
The issue is that we were trying to validate the mentions before
checking that the recipient stream was valid, leading to problems
checking the membership of the stream.

Fixes #3040.
2017-01-05 15:26:54 -08:00
Sampriti Panda
c15d1ff343 compose: Split validate_stream_message into separate functions. 2017-01-05 15:26:03 -08:00
Bojidar Marinov
5fc65efd69 messages: Allow rendering message content without having an actual message.
This is useful for doing rendering in the emoji search code path.
2017-01-05 15:16:43 -08:00
Tim Abbott
1262db40ea lint: Check for invalid '!!! warning'. 2017-01-05 15:15:19 -08:00
JefftheBest1
e724af3183 docs: Fix incorrect use of warning markdown. 2017-01-05 15:15:19 -08:00
Tim Abbott
8b839c96d4 lint: Check for long lines in all markdown files in general.
This has a few excludes for cases involving code blocks where it would
have been difficult to clean up.
2017-01-05 15:06:34 -08:00
Tim Abbott
9289c75f54 contrib_bots: Wrap CommuteBot docs. 2017-01-05 14:58:06 -08:00
Tim Abbott
bc4a9ff722 lint: Enforce no lines longer than 120 characters in help docs.
This requires some somewhat messy changes to the all-streams macro.
2017-01-05 14:54:04 -08:00
Tim Abbott
25f083a284 help: Wrap a bunch of very long lines.
Now there are no lines longer than 140 characters here.
2017-01-05 14:45:31 -08:00
Tim Abbott
efb8f8c26d docs: Wrap a bunch of long lines. 2017-01-05 14:31:34 -08:00
Tim Abbott
c57ef13a62 docs: Wrap long lines in Russian style guide. 2017-01-05 14:31:34 -08:00
Tim Abbott
5dfc13d346 docs: Wrap long lines in translation guides. 2017-01-05 14:08:42 -08:00
Tim Abbott
2ce1f7c489 help: Wrap long lines in glossary. 2017-01-05 14:04:06 -08:00
Robert Hönig
4d59e2ff74 Fix typo in Spanish and Polish translation guides. 2017-01-05 13:58:46 -08:00
Cynthia Lin
6e27a64e23 docs: Remove unnecessary images. 2017-01-05 13:40:45 -08:00
Cynthia Lin
68da889a76 docs: Modify existing images to fit with documentation styling guidelines. 2017-01-05 13:40:45 -08:00
Cynthia Lin
b8007b1b3c docs: Add macros to the *View the markdown source of a message* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
d737108e57 docs: Add macros to the *Unsubscribe from a stream* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
6b7afddd20 docs: Add macros to the *Star a message* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
1c6a765a22 docs: Add macros to the *Restrict editing of old messages and topics* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
d6e9a57fa3 docs: Add macros to the *Reply to a message* doc.
This doc needs to be modified in the future to conform to the styling guidelines; only a portion was corrected.
2017-01-05 13:40:45 -08:00
Cynthia Lin
c39aeeca5b docs: Add macros to the *Rename a stream* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
990d022cd5 docs: Add macros to the *Remove someone from a stream* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
b0f867357d docs: Add macros to the *Pin a stream* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
1796de44a8 docs: Add macros to the *Mute a topic* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
a3e035e047 docs: Add macros to the *Mute a stream* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
6a0f07802b docs: Add macros to the *Edit or delete a message* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
4a1f93817b docs: Add macros to the *Create a stream* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
20151a81e9 docs: Add macros to the *Collapse a message* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
c8824b96c1 docs: Add macros to the *Change who can join a stream* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
a9d0d0a8a8 docs: Add macros to the *Change the topic of a message* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
4aa70af05f docs: Add macros to *Change the stream description* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
22ea5f27a5 docs: Add macros to *Change the color of a stream* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
bed7bc98bc docs: Add macros to *Browse and join streams* doc.
Also modified to serve as a reference for navigating to the Subscriptions page.
2017-01-05 13:40:45 -08:00
Cynthia Lin
24ba8d8f08 docs: Add macros to *Add or invite someone to a stream* doc. 2017-01-05 13:40:45 -08:00
Cynthia Lin
083c331e2d docs: Create *Stream Settings* macro. 2017-01-05 13:40:45 -08:00
Cynthia Lin
d49b119391 docs: Create *Stream Settings scroll* macro. 2017-01-05 13:40:45 -08:00
Cynthia Lin
ae79bb9f01 docs: Create *Stream actions* macro. 2017-01-05 13:40:45 -08:00
Cynthia Lin
eff16b9766 docs: Create *Message actions* macro. 2017-01-05 13:40:45 -08:00
Cynthia Lin
097fbdefe4 docs: Create *Filter Streams* macro. 2017-01-05 13:40:45 -08:00
Cynthia Lin
6ad98e83b9 docs: Create *Down Chevron* macro. 2017-01-05 13:40:45 -08:00
Cynthia Lin
7f9b1b6490 docs: Create *All Streams* macro. 2017-01-05 13:40:45 -08:00
Cynthia Lin
89e9d79bb6 docs: Modify *Subscriptions* macro.
Modified to more resemble format of *Settings* and *Administration* macros.
2017-01-05 13:40:45 -08:00
andrewallen00
b376875541 interactive bots: Create yoda translator bot 2017-01-05 11:24:24 -08:00
AZtheAsian
e8dafcd905 mypy: Add annotations to api/integrations/asana/zulip_asana_mirror. 2017-01-05 11:08:21 -08:00
Jackson
81bea7f926 integrations: Add documentation for Delighted. 2017-01-05 10:47:30 -08:00
Jackson
032b5e9db9 integrations: Add webhook code, API endpoint, and tests for Delighted. 2017-01-05 10:47:30 -08:00
Vamshi Balanaga
1b2472b5cb integrations: Modify solano labs integration.
This adds support for the "running" status and adds a test fixture.
2017-01-05 10:19:32 -08:00
Tim Abbott
b48fcf4f8d change-your-language: Add additional details and links. 2017-01-04 23:21:45 -08:00
synicalsyntax
111dabe74f docs: Edit change-your-language.md to conform to style guide. 2017-01-04 23:16:17 -08:00
Rishi Gupta
83392bf974 message edit: Change the empty topic placeholder to be the original topic.
If a user removes the topic in the message edit form, we use the original
topic, not the empty topic.
2017-01-04 22:51:36 -08:00
Akhil
d8caf16e59 compose: Show description in autocomplete.
Stream descriptions are now displayed along with the name. The
autocomplete results include streams with matches in the stream
descriptions. Added styling for description in compose.css.

Fixes #2398.
2017-01-04 22:48:34 -08:00
ausDensk
059b124027 mypy: Annotate /api/integrations/rss/rss-bot.
With a few tweaks by tabbott.
2017-01-04 22:42:11 -08:00
Steve Howell
ef893dc8dd Live-update user list for name changes.
When somebody changes their name, we will now update
the buddy list right away.  The old code was trying
to do this through a code path that was designed for
true presence updates, but it was also passing in an
empty array, instead of undefined, which caused it to
fail to invoke the intended part of the codepath to
redraw the buddy list.

Now we just call the new activity.redraw() function,
which does the right thing for the buddy list.

The group PM list was live-updating before this change,
and it continues to live-update as part of the new
activity.redraw() function.
2017-01-04 19:45:15 -08:00
Tomasz Kolek
6d1cb44bd4 bitbucket2: Add additional debugging info about unsupported keys. 2017-01-04 17:29:49 -08:00
Rishi Gupta
2b0a7fd0ba Rename models.get_realm_by_string_id to get_realm.
Finishes the refactoring started in c1bbd8d. The goal of the refactoring is
to change the argument to get_realm from a Realm.domain to a
Realm.string_id. The steps were

* Add a new function, get_realm_by_string_id.

* Change all calls to get_realm to use get_realm_by_string_id instead.

* Remove get_realm.

* (This commit) Rename get_realm_by_string_id to get_realm.

Part of a larger migration to remove the Realm.domain field entirely.
2017-01-04 17:12:23 -08:00
Tim Abbott
0a6d960f37 emoji: Fix graphical artifacts of adjacent emoji in sprite sheet.
We didn't have any margin between the different emoji symbols
previously.
2017-01-04 17:12:23 -08:00
Jackson
652ae2639e help: Replace screenshots and cleanup markdown source article.
With some small copy edits by tabbott.

Fixes #2987.
2017-01-04 16:28:36 -08:00
Bojidar Marinov
e293a84331 narrow: Fix the client sending more than one search operator. 2017-01-04 16:02:41 -08:00
Bojidar Marinov
ffabf5fc49 Add .editorconfig for most file extensions with more than one use.
I didn't add anything about the following extensions since they had
way too many different styles:

- .txt
- .conf
- .erb (saw tab, 2-spaced, 4-spaced and 8-spaced files around the codebase)

Fixes #3099.
2017-01-04 15:15:31 -08:00
Brock Whittaker
6079584c85 perf: Use offsetHeight rather than getBoundingClientRect() in condenser.
Using the offsetHeight getter is ~2.5x faster than
getBoundingClientRect() on what can be an expensive operation to do in
the hundreds of times.

Note: Tim thinks that this may have been different a few years ago,
since we tested fairly carefully before settling on
getBoundingClientRect, but benchmarks pretty clearly show offsetHeight
is faster today, so we should use that.
2017-01-04 12:42:16 -08:00
Brock Whittaker
e7687bff6f Hide/Show Optimization with #group-pm-list.
The #group-pm-list now only should change state from hidden to
displayed once, which removes time spent recalculating styles in the
DOM.
2017-01-04 12:36:55 -08:00
Yago González
a2ebb066b4 docs: Fix formatting typo. 2017-01-04 10:12:07 -08:00
Cynthia Lin
bf063cebbc docs: Update documentation styling guide with new macro information. 2017-01-04 08:50:38 -08:00
Cynthia Lin
7d4949f897 user docs: Remove unnecessary images. 2017-01-04 08:50:38 -08:00
Cynthia Lin
7fec4d4074 user docs: Add *Subscriptions* macro to *Rename a stream* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
26ea7ac328 user docs: Add *Administration* macro to *Set default streams for new users* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
58d364f3ae user docs: Add *Administration* macro to *Delete a stream* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
00c940f91d user docs: Add *Administration* macro to *Change a user's name* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
ae03816cae user docs: Add *Administration* macro to *View a list of bots in your organization* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
e49b76ee11 user docs: Add *Administration* macro to *Make a user an administrator* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
cfc63a55a8 user docs: Add *Administration* macro to *Deactivate or reactivate a bot* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
329f2b278f user docs: Add *Administration* macro to *Deactivate or reactivate a user* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
31fdc56260 user docs: Add *Administration* macro to *Add a custom linkification filter* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
0241b8baa9 user docs: Add *Administration* macro to *Add custom emoji* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
6f58710b48 user docs: Add *Administration* macro to *Change the default language of your organization* doc.
Renaming doc in accordance with https://github.com/zulip/zulip/issues/3031
2017-01-04 08:50:38 -08:00
Cynthia Lin
6d13b92b14 user docs: Add *Administration* macro to *Restrict editing of old messages and topics* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
9fbfc275e5 user docs: Add *Administration* macro to *Only allow administrators to invite new users* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
ac04e5ce9c user docs: Add *Administration* macro to *Allow anyone to join without an invitation* doc. 2017-01-04 08:50:38 -08:00
Cynthia Lin
b6b42c3b4c user docs: Add *Administration* macro to *Change your organization's name* macro 2017-01-04 08:50:38 -08:00
synicalsyntax
e1c9d0f814 user docs: Modify *Settings* macro to use *Go to the* macro.
Created a *Go to the* macro that can be used by both *Settings* and
*Administration* macro.
2017-01-04 08:50:38 -08:00
synicalsyntax
a36d39f774 user docs: Create *Administration* macro. 2017-01-04 08:50:38 -08:00
synicalsyntax
ab9356ad44 user docs: Remove outdated *Settings* macro. 2017-01-04 08:50:38 -08:00
Steve Howell
8655472135 Use zproject.settings in tools/diagnose. 2017-01-04 08:48:54 -08:00
Steve Howell
7029917129 Add check_migrations() to tools/diagnose script. 2017-01-04 07:51:22 -08:00
Steve Howell
cd16a26c9a Add check_venv() to tools/diagnose script. 2017-01-04 07:51:22 -08:00
Steve Howell
0fd9f23505 Add tools/diagnose script.
This script does a basic sanity check on a dev environment.
2017-01-04 07:51:22 -08:00
Umair Khan
f208813ea3 Add Find My Team feature. 2017-01-03 21:33:42 -08:00
vaibhav
268770489b typeahead: Prevent duplicate private message recipients.
This matches the recipients and displays the ones which haven't been
added already.

Fixes: #2499.
2017-01-03 20:37:47 -08:00
Tim Abbott
fa3a1de9c7 zulip_codebase_mirror: Move Text/six imports after sys.path changes. 2017-01-03 20:24:03 -08:00
AZtheAsian
c155b9162d mypy: Annotate api/integrations/codebase/zulip_codebase_mirror. 2017-01-03 20:23:06 -08:00
Vamshi Balanaga
fb6ae449da integrations: Add documentation for solano labs. 2017-01-03 20:18:34 -08:00
Vamshi Balanaga
234310bfd1 integrations: Add webhook code, API endpoint, and tests for solano labs. 2017-01-03 20:18:34 -08:00
Vamshi Balanaga
d6b551d508 integrations: Add webhook payloads for solano labs 2017-01-03 20:18:34 -08:00
Alex Morozov
338c05a15b docs: Create a Russian translation style guide. 2017-01-03 19:33:43 -08:00
Bojidar Marinov
1c044688a4 compose: Make ctrl-enter, meta-enter, etc. add newline with enter_sends.
Tweaked by tabbott to ensure we update the compose box size as well.

Fixes #2989.
2017-01-03 19:14:38 -08:00
Tim Abbott
e943c1d247 compose: Export autosize_textarea. 2017-01-03 19:14:38 -08:00
Tommy Ip
92dd4c1b98 Automatically hide all popovers on scroll. 2017-01-03 18:45:21 -08:00
anirudhjain75
3bd70075c4 doc: Add user documentation for view the list of bots in an organization.
With several cleanups by tabbott.
2017-01-03 18:44:37 -08:00
Cynthia Lin
4f17d6cc61 docs: Add user guide for *Configure audible notifications* feature 2017-01-03 18:39:22 -08:00
Tim Abbott
767f30a7e5 zulip_basecamp_mirror: Move some imports after sys.path updates. 2017-01-03 18:36:12 -08:00
Jackson
98ca518461 mypy: Add annotations to api/integrations/basecamp/zulip_basecamp_mirror 2017-01-03 18:34:26 -08:00
Brock Whittaker
d8fc30a776 Change escape key interception with subscription overlay.
The escape key used to be intercepted if the subscription pay display
was set to “block”, but now since we use the class “show” and lack to
hide and show the overlay, the query needs to change.
2017-01-03 17:55:22 -08:00
Alicja Raszkowska
e21fe8b886 css: Create a separate file for right-sidebar CSS.
Create a new file right-sidebar.css.
Move all right-sidebar CSS from zulip.css to right-sidebar.css.
2017-01-03 16:57:51 -08:00
Tim Abbott
0018cd588e docs: Clean up testing with casper selectors discussion. 2017-01-03 16:56:50 -08:00
Yago González
872f288e76 docs: Add explanation for \$\$ selector. 2017-01-03 16:55:10 -08:00
Rishi Gupta
cf762eaf84 Change X.realm.id to X.realm_id across codebase.
This makes it more clearly the pattern in the Zulip codebase, and thus
decreases the risk of accidentally doing database queries.
2017-01-03 16:46:26 -08:00
Rishi Gupta
caccf8ee17 Remove models.get_realm(domain). 2017-01-03 16:46:15 -08:00
Rishi Gupta
130f981901 messages.send_message_backend: Take a realm_str instead of a domain. 2017-01-03 16:46:15 -08:00
Rishi Gupta
b206d6f251 message.py: Change domain to realm_id in render_markdown args. 2017-01-03 16:46:14 -08:00
Rishi Gupta
c6e12e74be Change domain to realm_id in bugdown and realm filter dicts and caches. 2017-01-03 16:25:20 -08:00
Rishi Gupta
be6f54d7bb messages.py: Add sender.realm.id to MessageDict. 2017-01-03 16:25:20 -08:00
Rishi Gupta
50d67d9a13 test_messages: Add warning about running test_bulk_message_fetching alone.
Running this test fails if it is not run as a part of the larger
test_messages suite. This commit adds a comment to that effect.
2017-01-03 16:25:20 -08:00
Cynthia Lin
e3bf6ebac7 user docs: Add *Settings* macro to *Add an alert word* doc. 2017-01-03 16:15:51 -08:00
Cynthia Lin
1883dea064 user docs: Add *Settings* macro to *Configure desktop notifications* doc. 2017-01-03 16:15:51 -08:00
Cynthia Lin
2c9803e24a user docs: Add *Settings* macro to *Deactivate your account* doc. 2017-01-03 16:15:51 -08:00
Cynthia Lin
0c8f06692f user docs: Add *Settings* macro to *Move the users list to the left sidebar* doc. 2017-01-03 16:15:51 -08:00
Cynthia Lin
3f84fa663c user docs: Add *Settings* macro to *Change the date and time format* doc. 2017-01-03 16:15:51 -08:00
Cynthia Lin
41271da7c7 user docs: Add *Settings* macro to *Change your language* doc.
Also updated outdated UI in pictures.
2017-01-03 16:15:51 -08:00
Cynthia Lin
2725ae5963 user docs: Add *Settings* macro to *Change your avatar* doc. 2017-01-03 16:15:51 -08:00
Cynthia Lin
c32f8b4d01 user docs: Add *Settings* macro to *Change your password* doc. 2017-01-03 16:15:51 -08:00
Cynthia Lin
9aa0a103e1 user docs: Add *Settings* macro to *Change your name* doc. 2017-01-03 16:15:51 -08:00
Cynthia Lin
742d19c1b0 user docs: Create *Settings* macro. 2017-01-03 16:15:51 -08:00
Brock Whittaker
e4761782e0 Fix Small Image Preview Sizing.
Before the sizing of the preview would be 100px in height regardless of
whether the image was that tall. Now it is any value up to 100px.
2017-01-03 15:59:25 -08:00
Jackson
29ce856843 Clean PUT /users/me/pointer to POST /users/me/pointer. 2017-01-03 15:43:11 -08:00
Jackson
0a9869868c Clean PUT /users to POST /users 2017-01-03 15:40:00 -08:00
Jackson
6ec8abab86 Clean PUT /default_streams to POST /default_streams. 2017-01-03 15:40:00 -08:00
Brock Whittaker
50f6681319 Fix z-index Issues.
This fixes the z-index issue with the navbar along with hiding any
popovers when you enter into the lightbox.

Fixes #3078.
2017-01-03 15:33:54 -08:00
Jackson
566d55b7c6 mypy: Annotate api/integrations/hg/zulip-changegroup.py 2017-01-03 11:44:43 -08:00
Rafid Aslam
f897cc5a8b tests: Add --force option to tools/test-all
Fixes #2996.
2017-01-03 11:42:53 -08:00
Rafid Aslam
fdaed99222 tests: Add --force option to tools/test-help-documentation.py 2017-01-03 11:42:53 -08:00
Rafid Aslam
e1ac6fbece Add --force to tools/run-dev.py when run run-casper with --force
Add `--force` option to `tools/run-dev.py` when run
`frontend_tests/run-casper` with `--force` option.
2017-01-03 11:42:53 -08:00
Tim Abbott
0c9eccfa58 reactions: Fix missing preventDefault in actions handler. 2017-01-03 10:58:46 -08:00
Tim Abbott
3a9a6308fd Fix per-user database queries for emoji reactions.
This was a classic database-queries-in-loop bug.
2017-01-03 10:53:26 -08:00
Tommy Ip
7719a34e2c Automatically hide actions popover on scroll.
Fixes #3012.
2017-01-03 09:33:05 -08:00
Cynthia Lin
d3743d2b15 docs: Add user guide for *Add a custom linkification filter* feature 2017-01-03 11:31:04 +01:00
Tim Abbott
c199c73b93 docs: Fix formatting error in README.md. 2017-01-02 22:52:31 -08:00
andrewallen00
27a9341039 docs: Add user guide for configure desktop notifications. 2017-01-02 21:23:14 -08:00
Cynthia Lin
edb98b8428 docs: Update style guide for user documentation.
docs: Update style guide for user documentation.
2017-01-02 17:46:11 -08:00
Robert Hönig
4f9bbb1c8a Fix duplicate notifications when multiple Zulip tabs are openend.
We attempted a number of different approaches to solving this problem:

First, we tried using HTML5 local storage to keep track of which
browser should have created the desktop notification.  This failed
because one needs locking, and it doesn't appear there is an working
locking implementation for HTML5 local storage that could allow us to
do this across tabs.  See #2936 for details.

Ultimately we went with setting the message ID as a tag.  Tags are
intended to be used for updating existing desktop notifications, which
means this implementation causes new notifications to flicker in and
out sometimes when multiple tabs are open, but that certainly beats
having duplicates.

Fixes #99.
2017-01-02 16:58:51 -08:00
Brock Whittaker
fb6d35871b notifications: Cleanup click-through implementation.
This refactors the notification on click by storing values through the
jQuery $.fn.data option.

Substantially modified by tabbott.

Replaces #2940.
2017-01-02 16:51:23 -08:00
Tim Abbott
2003fb7b12 notifications: Fix raw_operators not being set for 1:1 PM messages. 2017-01-02 16:46:51 -08:00
Tim Abbott
2ef19901dd notifications: Improve HTML/CSS for desktop notifications. 2017-01-02 16:42:04 -08:00
Tim Abbott
0b78fe54e8 notifications: Wrap notifications_html definition. 2017-01-02 16:40:18 -08:00
Alya Abbott
dab7ceb620 Add style guide for user documentation. 2017-01-02 16:34:15 -08:00
Alya Abbott
8852db34c6 Update signing in page. 2017-01-02 16:34:15 -08:00
Alya Abbott
6bedbbb399 Add forgotten password doc.
Fixes #2998.
2017-01-02 15:19:16 -08:00
Callum
76807d4c82 docs: Add user guide for alert words. 2017-01-02 15:04:33 -08:00
Cynthia Lin
5db1a69542 user docs: Use subscriptions macro in *Remove someone from a stream* doc. 2017-01-02 09:29:03 -08:00
Cynthia Lin
d72a4c8429 user docs: Use subscriptions macro in *Unsubscribe from a stream* doc 2017-01-02 09:29:03 -08:00
Cynthia Lin
c1edbb2576 user docs: Use subscriptions macro in *Remove someone from a stream* doc. 2017-01-02 09:08:15 -08:00
Cynthia Lin
30d06bfd1f user docs: Use subscriptions macro in *Change who can join a stream* doc. 2017-01-02 09:08:15 -08:00
Cynthia Lin
f0fe351bf7 user docs: Use subscriptions macro in *Change the stream description* doc. 2017-01-02 09:08:15 -08:00
Cynthia Lin
3cda2d540e user docs: Use subscriptions macro in *Change the color of a stream* doc. 2017-01-02 09:08:15 -08:00
Cynthia Lin
5117f7dc3a user docs: Use subscriptions macro in *Create a stream* doc. 2017-01-02 09:08:15 -08:00
Cynthia Lin
0a54f2b467 user docs: Use subscriptions macro in *Browse and join streams* doc. 2017-01-02 09:08:15 -08:00
Cynthia Lin
eedc6ffc3f docs: Add user guide for *Add custom emoji* feature. 2017-01-02 09:07:39 -08:00
anirudhjain75
5f4a822655 mypy: Annotate zerver/tests/test_decorators.py. 2017-01-02 08:59:49 -08:00
Sampriti Panda
246ac7cadc mypy: Annotate api/integrations/twitter/twitter-search-bot 2017-01-02 08:01:37 -08:00
Cynthia Lin
a5e45f4213 user docs: Use subscriptions macro in stream invite doc. 2017-01-01 19:49:23 -08:00
Cynthia Lin
1118d303dc user docs: Add the subscriptions macro. 2017-01-01 19:49:14 -08:00
Tim Abbott
ec3e5e844a reactions: Clean up popovers and hover logic.
Previously, the emoji reactions popovers were keyed off the
edit_content area, which is problematic because that area was
created/deleted on hover, resulting in orphaned popovers (which
wouldn't close properly normally).  That had been hackishly addressed
in the original PR with the overbroad `$('.popover').remove();`.  To
remove that, we fix the actions popover to always be based on an
element that exists in the page.

There probably more to do here, but this is good enough to merge emoji
reactions and iterate from here.
2016-12-30 21:42:54 -08:00
Arpith Siromoney
9c64a08cad Add frontend support for emoji reactions.
This commit replaces the placeholder "clipboard" button with a reaction button.
This is done on any message that can't be edited. Also, on messages sent by
the user the actions popover (toggled by the down chevron icon) contains
an option to add a reaction.

When clicked, a popover with a search bar and a list of emojis is displayed.
If the right sidebar is collapsed (the viewport is small), the popover is placed
to the left of the button.
Focus is set to the search bar. Typing in the search bar filters emojis.

Emojis with which the user has reacted to this message are highlighted.
Clicking them sends an API request to remove that reaction.
Clicking on non-highlighted emojis sends an API request to add a reaction.
When the popover loses focus it is closed.

The frontend listens for reaction events. When an add-reaction event is
received, the emoji is displayed at the bottom of the message with a
count initialized to 1. If there was an existing reaction to the message with
the same emoji, the count is incremented.

Old messages fetched from the server contain reactions.
They are displayed (along with title and count) at the bottom
of each message.

When clicking the emoji reaction at the bottom of the message, if the
user has already reacted with that emoji to this message, the reaction
is removed and the count is decremented. Otherwise, a reaction is added
and the count is incremented.

Hovering over the emoji reaction at the bottom of the message displays
a list of users who have reacted with this emoji along with the
emoji name.

Hovering over the emoji reactions at the bottom of the message displays
a button to add a reaction.

Fixes #541.
2016-12-30 21:42:54 -08:00
Tim Abbott
965a22e2bd reactions: Fix support for "+1" emoji.
Previously, we didn't allow the `+1` character in the URL pattern.
2016-12-30 21:42:24 -08:00
Tim Abbott
a61386cbbc github: Fix GitHub integration CSRF issue.
The new GitHub dispatcher integration was apparently totally broken,
because we hadn't tagged the new dispatcher endpoint as exempt from
CSRF checking.  I'm not sure why the test suite didn't catch this.
2016-12-30 20:31:08 -08:00
Jackson
88da3dea7e mypy: Annotate api/integrations/trac/zulip_trac.py 2016-12-30 20:05:14 -08:00
Tim Abbott
5c0730d7ca reactions: Fix check for valid emoji.
The previous logic did not correctly handle the case where there were
realm emoji (non-realm emoji would be inaccessible).
2016-12-30 17:51:31 -08:00
Tim Abbott
8d66a4f53f test_signup: Fix test failure due to user docs include/. 2016-12-30 17:46:55 -08:00
Tim Abbott
687d0cbf9e docs: Add support for including markdown files in others.
This uses a third-party dependency, python-markdown-include.

The example use for settings is intended primarily as a demonstration.
2016-12-30 17:16:29 -08:00
Brock Whittaker
338dcfc889 Partial match previous search terms in streams page.
Before in a query string like:

“all, s, verona”

It would only strong match the first two terms, but now it’ll partial
string match all terms equally.
2016-12-30 17:13:48 -08:00
Umair Khan
9834731dfd ldap: Suppress logging output of fakeldap. 2016-12-30 16:55:06 -08:00
Umair Khan
b6cb6a4f0c ldap: Inherit FakeLdap exceptions from ldap. 2016-12-30 16:55:06 -08:00
Umair Khan
8acf2609de ldap: Use newer commit of fakeldap in requirements. 2016-12-30 16:55:05 -08:00
Rishi Gupta
605361ec86 makemessages: Fix string with unnamed arguments in analytics/views.py. 2016-12-30 16:52:24 -08:00
Rishi Gupta
386e22c564 Add node tests for message_edit.get_editability. 2016-12-30 16:51:00 -08:00
K.Kanakhin
0d8c18a6dd nagios-plugins: Add websocket checking to nagios message sending test.
- Add websocket client to create connection with SockJS websocket server.
  It contains callback method to launch after connection setup.
- Add '--websocket' parameter to 'check_send_receive_time' script to
  check websocket connection.
- Add testing  websocket connection to production installation checking.
- Add cronjob to launch websocket connection nagios test.

This makes it possible for Zulip Nagios monitoring to check for
problems impacting the websockets sending code path, which is what all
web users use.
2016-12-30 15:36:37 -08:00
Alya Abbott
c444ae2850 Update text in the "move the users list" doc. 2016-12-30 15:31:46 -08:00
Tommy Ip
29c291b981 mypy: Annotate *api/integrations/perforce/zulip_change-commit.py*. 2016-12-30 15:19:34 -08:00
Rohan Tibrewal
8e1724e81e Vagrant: Make host_ip a variable set in ~/.zulip-vagrant-config. 2016-12-30 14:50:08 -08:00
Tim Abbott
c9a1d4a074 Move portico-only JS to static/js/portico/.
Fixes #3014.
2016-12-30 14:47:49 -08:00
Tim Abbott
0ddaa13eeb lint: Fix indentation error in user_settings.py. 2016-12-30 14:31:04 -08:00
Jackson
0d48adb8fe integrations: Add documentation for HelloSign. 2016-12-30 14:28:27 -08:00
Jackson
aeac3848c8 integrations: Add webhook code, API endpoint, and tests for HelloSign. 2016-12-30 14:19:31 -08:00
Prabod Rathnayaka
6f087e468e Add setting hiding private message content in desktop notifications.
Tweaked by tabbott to fix a refactoring bug, set the default to True,
fix the real-time sync, and add tests for this.

Fixes #2355.
2016-12-30 14:10:34 -08:00
Tim Abbott
a0f3f3dfa0 lint: Forbid script tags in handlebars templates. 2016-12-30 12:43:56 -08:00
Alya Abbott
c650f299fd Update change-your-avatar user doc. 2016-12-30 12:43:56 -08:00
Vamshi Balanaga
bf71ad162c Update Google Calendar Integration.
Update integration to use the latest Google API client.
Move Google Account authorization code to a separate file.
Move relevant files from 'bots/' to 'api/integrations/google/'.
Add documentation for integration.
2016-12-30 12:01:31 -08:00
Tim Abbott
5a51f5f9d5 bots: Move gcal-bot into official API release. 2016-12-30 12:01:31 -08:00
Rafid Aslam
50afe5a6c2 sync_api_key: Fix ConfigParser deprecation warnings.
Fix `ConfigParser` deprecation warnings in
`zilencer/management/commands/sync_api_key.py`.

Fixes #2727.
2016-12-30 11:52:22 -08:00
Joshua Pan
0c2d424816 mypy: Get rid of six.moves.configparser and add appropriate classes. 2016-12-30 11:41:17 -08:00
lonerz
3c1c65eaf8 mypy: Annotate api/integrations/twitter/twitter-bot 2016-12-30 11:40:45 -08:00
Tim Abbott
27e38304e0 i18n: Fix several strings incorrectly not tagged for translation.
I found these by grepping for `value=` in the codebase.

Thanks for Alex Morozov for the report.
2016-12-30 09:54:21 -08:00
Cynthia Lin
77d8056d5f docs: Add user guide for *Allow anyone to join without an invitation* feature 2016-12-30 13:19:01 +01:00
Tim Abbott
b36e94c954 bugdown: Blacklist linkifying the .md TLD.
Fixes #2065.
2016-12-29 18:17:50 -08:00
Alya Abbott
b809d8edee Fix up change-your-password doc. 2016-12-29 16:34:05 -08:00
Alya Abbott
85bd74f957 Cleans up change-your-name doc page. 2016-12-29 16:34:03 -08:00
Alya Abbott
d0cf1249ef Clean up the edit-settings doc page. 2016-12-29 16:31:13 -08:00
Alya Abbott
2b460e0e51 Move edit-profile -> edit-settings. 2016-12-29 16:28:25 -08:00
Rishi Gupta
674f068b92 Script to add all current Zulip users to a mailchimp list. 2016-12-29 16:24:40 -08:00
Rishi Gupta
13d1a636d5 queue_processors.SignupWorker: Upgrade to MailChimp API v3.0.
Removes the dependence on postmonkey, which is a wrapper around
MailChimp API v1.3. MailChimp recommends using their v3.0 API directly,
rather than through a wrapper library.
2016-12-29 16:16:18 -08:00
Rishi Gupta
c61938f719 SignupWorker: Use dictionary indexing instead of get for name and email.
We always pass in EMAIL in data, and NAME in merge_vars.
2016-12-29 16:16:18 -08:00
Brock Whittaker
71dd9387f8 Removing #full_name IDs.
There was a duplicate #full_name ID being added many times in tables.
They should be removed because they are not being called anywhere and
should not exist in multiples.
2016-12-29 16:15:14 -08:00
Brock Whittaker
a9e49338de Change #name_change_container to class.
This changes the selector #name_change_container to a class because
there should never be more than one of an ID.
2016-12-29 16:15:14 -08:00
Rishi Gupta
52c18e9c9d run-dev: Change provisioning error messages to not reference tests.
Previously, we got the following as a part of the output when running
`tools/run-dev.py` without provisioning:

    It looks like you checked out a branch that has added
    dependencies beyond what you last provisioned.  Your tests
    are likely to fail until you add dependencies by provisioning.

which is a bit confusing.
2016-12-29 16:13:49 -08:00
Bojidar Marinov
8876179ef7 message-edit: Always rerender home view after topic editing.
When editing a message changes the current narrow, we rerender the
narrowed view earlier in the function, so we don't need to do it here.
But we still need to rerender the home view, or the messages will be
displayed incorrectly once the user unnarrows!

Tweaked by tabbott for clarity and simplicity.

Fixes #2464.
2016-12-29 16:11:54 -08:00
Brock Whittaker
1046f16bb6 Add debugging device to check for duplicate IDs in markup.
This checks for duplicate IDs in the markup of the body.
2016-12-29 15:56:48 -08:00
Rishi Gupta
823659848c Change UserProfile.enter_sends to default to False.
Adds a database migration.
2016-12-29 15:55:23 -08:00
lonerz
e1d4fb90d7 hotkeys: Add '@' as a hotkey to compose message with mention. 2016-12-29 15:43:35 -08:00
lonerz
c80bad5b55 popovers: Add popover actions to mention a user.
This adds actions to the user and message popovers to mention the user
(either the sender of a message or the selected user).
2016-12-29 15:39:41 -08:00
Tim Abbott
0847515203 Fix text_type->Type mypy merge conflict error. 2016-12-29 15:03:37 -08:00
Rishi Gupta
9e5325a164 Add /stats page with basic stats graph.
Adds a new url route and a new json endpoint.
2016-12-29 14:20:13 -08:00
Rishi Gupta
7b057392c6 decorator.py: Add to_utc_datetime converter function. 2016-12-29 14:20:13 -08:00
Rishi Gupta
31efe858ef Clean up imports in analytics/views.py. 2016-12-29 14:20:13 -08:00
umkay
05bbdb379d analytics: Add plotly.js dependency.
Increases provision number.
2016-12-29 14:20:13 -08:00
Rishi Gupta
40529cdd14 timestamp.py: Add {floor,ceiling}_to_{hour,day} to parallel floor_to_day. 2016-12-29 14:20:13 -08:00
Robert Hönig
f7c29f1b7f interactive bots: Create converter bot. 2016-12-29 19:28:35 +01:00
andrewallen00
881342a5ca docs: Add user guide for reply to a message
docs: Add user guide for reply to a message

docs: Add user guide for reply to a message

docs: Add user guide for reply to a message

docs: Add user guide for reply to a message

docs: Add user guide for reply to a message
2016-12-29 19:26:56 +01:00
Juan Verhook
cfa9c2eaf2 mypy: Update zerver directory to use Text 2016-12-29 09:12:15 -08:00
Arpith Siromoney
5639f21188 Add missing exports to js modules 2016-12-29 06:01:33 -08:00
Cynthia Lin
0d5a0d02b3 docs: Add user guide for *Restrict editing of old messages and topics* feature 2016-12-29 10:35:10 +01:00
Yago González
497dc4756e interactive bots: Use dev API when in a dev setup.
Now the development API (which is inside the repo, api/) is used when the envionment is a development one.

Credits to Steve Howell (@showell) for the instructions on how to fix this.
2016-12-28 19:25:56 -08:00
KingxBanana
5ad10bb265 Update unsubscribe-stream.md
- "locate" instead of "located"
2016-12-28 17:18:25 -08:00
KingxBanana
e32d93bc42 Update streams-and-private-messages.md
- "read or send messages in the stream." is wrong. You can't read to a stream.
- Added "a" to make it sound better line  10
- Changed end of line 10 a bit
2016-12-28 17:18:24 -08:00
KingxBanana
bb0ea65ad8 Update sign-in.md
- Changed from "Login" to "Log in" line 19
2016-12-28 17:18:14 -08:00
KingxBanana
b60b695f58 Update send-stream-message.md
- Fixed line 10
2016-12-28 17:18:14 -08:00
KingxBanana
9b17a58970 Update send-group-pm.md
- Fixed line 47
- Removed "message" after "group" a couple of times to make it sound better
2016-12-28 17:18:14 -08:00
KingxBanana
9841021c6d Update keyboard-shortcuts.md
- Added missing "topic"
- Changed some "allows" that sounded wrong
2016-12-28 17:18:14 -08:00
KingxBanana
286ac7ca7b Update keyboard-shortcuts.md
- Changed "a messages" to "messages"
- Fixed typo: "stream message" -> "private message"
2016-12-28 17:18:14 -08:00
KingxBanana
1bd46a1b93 Update image-full-size.md 2016-12-28 17:18:14 -08:00
KingxBanana
892c2c0427 Update glossary.md
- Updated **Home** to include PM's
- Fixed line 21
- Fixed line 27
- Fixed line 31
- "the user is choosing to stop recieving" instead of "the user is choosing to stop recieve"
2016-12-28 17:18:14 -08:00
KingxBanana
06374f004a Update format-your-message-using-markdown.md
- Fixed typo: "test" -> "text"
- Changed line 75 a bit
- Removed a `"` that was wrongly placed
- Changed an if sentence to make it grammatically correct
- Fixed line 85
2016-12-28 17:18:12 -08:00
KingxBanana
4dfbaf8e7f Update editing-past-messages.md
- Changed "separate answer" to "separate guide", because "separated answer" wasn't the best wording imo.
2016-12-28 17:18:00 -08:00
KingxBanana
bde9d64baa Update edit-profile.md
- Added hyperlink for changing language
- Removed manage notifications from top, as it was not in the guide
2016-12-28 17:18:00 -08:00
KingxBanana
414cbc2bd2 Update delete-a-stream.md
- "Follow these instructions" instead of "follow this instructions"
2016-12-28 17:18:00 -08:00
KingxBanana
98f55c96de Update collapse-a-message.md
- "Select" instead of "selecting"
2016-12-28 17:18:00 -08:00
KingxBanana
de6882f051 Update change-your-name.md
- "this is fully are supported" incorrect.
2016-12-28 17:18:00 -08:00
KingxBanana
2f64ebd751 Update change-stream-color.md
- "Suits" instead of "suites"
2016-12-28 17:18:00 -08:00
KingxBanana
3f7914d451 Update browse-and-join-streams.md
- Read and send to incorrect: You don't read to a stream.
2016-12-28 17:18:00 -08:00
KingxBanana
251006fa59 Update advanced-search.md.
- There was no "previous" image
- There was no space between the - and the text
- The difference between **keyword** and **"keyword"** was unclear
2016-12-28 17:17:57 -08:00
KingxBanana
de73eaeef8 Update add-invite-stream.md
- Once the email address is entered in the **Email address** sounded weird.
- After, now sentence incorrect
2016-12-28 17:17:38 -08:00
KingxBanana
10a58564e6 Update add-emoji.md.
The order of the possible ways to use emoji in the introduction was
different from the order they were explained in.
2016-12-28 17:17:34 -08:00
KingxBanana
590b84f9e5 Update about-stream-topic.md 2016-12-28 17:16:59 -08:00
Tommy Ip
7f187418d4 mypy: Annotate *api/integrations/nagios/nagios-notify-zulip*. 2016-12-28 15:44:47 -08:00
Steve Howell
178b3898d5 Add TODO to deprecated show-last-messages. 2016-12-28 15:17:24 -08:00
Steve Howell
3d804de962 Fix FeedbackBot queue processor.
Recent changes to the API removed Client.register(), and
this change restores the correct API call, although the
codepath this affects is probably ready for eventual
deprecation.
2016-12-28 12:12:34 -08:00
Tim Abbott
b677d63ed7 mypy: Fix missing class in request.pyi and document. 2016-12-28 09:37:28 -08:00
Tim Abbott
5ad9a9d014 compose: Fix websockets having been accidentally disabled.
When we renamed use_socket to use_websockets, we only renamed it on
the backend, and thus it became effectively hardcoded to false.
2016-12-28 09:24:19 -08:00
Tommy Ip
3d015eb259 mypy: Annotate *api/integrations/svn/post-commit*. 2016-12-28 08:54:53 -08:00
Sampriti Panda
5316c364bb docs: Add user guide for Change your organization's name 2016-12-28 12:33:57 +01:00
sidhant bhavnani
5b4d9774e0 Docs: Only allow admins to invite new users 2016-12-28 11:28:06 +01:00
Tim Abbott
45324e08c1 bots: Fix jabber_mirror_backend annotations.
mypy was super confused because the name "zulip" was both an import
and a global variable in the file.
2016-12-27 21:39:32 -08:00
Harshit Bansal
9931ad1324 Loosen realm filter pattern validator to support Git commit IDs.
Specify, we no longer require a prefix.

Also improves the clarity of the examples in the documentation.

Fixes: #2696.
2016-12-27 20:31:08 -08:00
Tim Abbott
39f0ffdedd Move static/third/gemoji to static/generated/emoji.
Fixes #1153.
2016-12-27 20:16:23 -08:00
Tim Abbott
ea8e34008d lint: Fix pep-8 rules on recently added files. 2016-12-27 20:16:23 -08:00
Tim Abbott
08dae5108e emoji: Move tools/setup/emoji_dump to tools/setup/emoji. 2016-12-27 19:58:41 -08:00
Tim Abbott
726e2649b4 lint: Run linters on settings.py files.
This finishes clearing unnecessarily excluded items from the global
tools/lint-all exclude list.  The remaining items are third-party code
or generated code that doesn't make sense to lint.

Fixes #822.
2016-12-27 19:53:44 -08:00
Tim Abbott
d47ea7a608 lint: Add comments to EXCLUDED_FILES entries. 2016-12-27 19:48:43 -08:00
Tim Abbott
f46d99ba85 lint: Remove zerver/migrations from main exclude list. 2016-12-27 19:45:33 -08:00
Tim Abbott
ab89664d90 lint: Clean up main exclude list and move to pyflakes. 2016-12-27 19:45:33 -08:00
Tim Abbott
92a62cccd3 help: Fix broken link to rename-a-stream. 2016-12-27 17:27:11 -08:00
Tim Abbott
1c5e8cd47b lint: Check for spelling of organization and fix errors. 2016-12-27 17:25:01 -08:00
anirudhjain75
8e3f1e1745 doc: Add user documentation for change the default language feature 2016-12-27 17:21:19 -08:00
Tim Abbott
fa2aa42b03 do_invite_users: Avoid creating broken PreregistrationUser objects.
While this may not have created a clear user-facing bug, it seems less
confusing for do_invite_users to only create PreregistrationUser
objects for users who actually received an email invitation.
2016-12-27 17:14:21 -08:00
Bojidar Marinov
9682d26561 invite: Leave not yet invited users in the invite modal's textarea.
Also, make zerver tell us whether invitations were sent.

Fixes #2287.
2016-12-27 17:14:21 -08:00
anirudhjain75
aaf0852aba doc: Add user documentation for set the default streams
Create user documentation for setting the defaul streams
for new users.
2016-12-28 02:03:05 +01:00
Tim Abbott
ad513bab33 Fix broken invite screen caused by duplicate #stream-checkboxes ID.
In 06615bee00, we accidentally
introduced a duplicate HTML ID for #stream-checkboxes, which in turn
caused the "invite users" page to no longer work.  This fixes that
problem.
2016-12-27 16:53:10 -08:00
Tomasz Kolek
56f530331d Add default topics mechanism to stripe integration.
Fixes: #2586.
2016-12-27 16:27:54 -08:00
Tomasz Kolek
02bf4646fc Refactor transfer part of stripe integration. 2016-12-27 16:27:54 -08:00
Tomasz Kolek
6dca1ecc40 Refactor order part of stripe integration. 2016-12-27 16:27:54 -08:00
Tomasz Kolek
a75d94d3cf Refactor invoice part of stripe integration. 2016-12-27 16:27:54 -08:00
Tomasz Kolek
e843af5d27 Refactor customer part of stripe integration. 2016-12-27 16:27:54 -08:00
Tomasz Kolek
d1c486b8e9 Refactor charge part of stripe integration. 2016-12-27 16:27:54 -08:00
anirudhjain75
4e17a76350 user guides: Change URLs to match article titles.
Fixes #2855.
2016-12-27 15:48:16 -08:00
paxapy
8e7fa6b2de emoji: Add add_emoji_by_admins_only realm setting.
This setting controls whether normal users can add realm emoji.

Fixes #978.
2016-12-27 15:46:14 -08:00
Igor Tokarev
3cb7d665da emoji: Display emoji author in admin interface.
Fixes: #984.
2016-12-27 15:45:55 -08:00
Igor Tokarev
1238d08f72 emoji: Add emoji author data in API. 2016-12-27 15:42:21 -08:00
Igor Tokarev
ffa724f8fc emoji: Add author field to RealmEmoji table and track. 2016-12-27 15:42:04 -08:00
Sanskar Modi
dee5a0c8d7 Added styling on compose notification warning button.
With CSS suggestions from Tommy Ip.
2016-12-27 15:21:20 -08:00
Rafid Aslam
778e509464 interactive bots: Create xkcd bot. 2016-12-27 22:52:51 +01:00
Steve Howell
a96fdd18b1 Make Private Messages work better when zoomed in.
Some of the work here was done Tomasz Kolek.

When we click on "more conversations" in "Private Messages,"
we call it being "zoomed in."  Before this change, when
new PMs arrived, we would rebuild the list and zoom out
again.  Now we track the zoomed_in state with a variable.
Also, if you are zoomed in and switch from one PM narrow
to another, we also keep you zoomed in.

This fix also removes some extraneous/redundant code.

Fixes: #2561
2016-12-27 13:36:30 -08:00
Vamshi Balanaga
561562da3d Modify GitHub Issue bot to use new authentication module. 2016-12-27 11:58:36 -08:00
Vamshi Balanaga
9701d5e555 Modify GitHub comment bot to use new authentication module, and edit documentation accordingly. 2016-12-27 11:58:36 -08:00
Vamshi Balanaga
89d1f96db9 Create GitHub authentication module. 2016-12-27 11:58:36 -08:00
Umair Khan
fe1848377c i18n: Bump i18next-parser version.
Fixes #2882
2016-12-27 14:39:39 +05:00
Brock Whittaker
51153a6ce2 Change scope of pointer events for lightbox overlay.
This was intercepting pointer events even though the lightbox was
closed. This fixes the issue with the streams exit not working in some
responsive cases.

Fixes: #2818.
2016-12-26 18:31:18 -08:00
hackerkid
713b69ceab Fix position of restore draft button.
The Restore draft button currently appears before Markdown preview
button. This commit moves restore draft to right most position.
2016-12-26 18:30:58 -08:00
Callum
0dbe1bb87e docs: Add user guide for starring messages 2016-12-26 18:10:31 -08:00
Maydha K
161159ff04 docs: Add user guide for change the stream description. 2016-12-26 18:06:11 -08:00
Rishi Gupta
717afcb408 Remove calls to get_realm in preparation for its deprecation.
Also removes two calls to email_to_domain.
2016-12-26 17:53:32 -08:00
Rishi Gupta
e9a6bd1986 Change register/<domain>/ URL route to register/<realm_str>/. 2016-12-26 17:51:00 -08:00
Rishi Gupta
ea64b18f91 zerver.views: Be confident that request.session['domain'] is valid.
We only write domain to the session variable in one place,
accounts_home_with_domain, where we check that the domain is valid, that the
domain corresponds to an open realm, and that we are in the non-subdomains
case.

Previously, we were confusingly checking only a subset of the conditions
on reading back the domain in create_preregistration_user, and not checking
any of them when reading back the domain in get_realm_from_request.
2016-12-26 17:50:46 -08:00
Rishi Gupta
d6e7014f06 Refactor views.create_homepage_form into its callers.
The indirection is no longer that useful, and obscures Django's conventional
style for calling a form.
2016-12-26 17:50:23 -08:00
Rishi Gupta
146f2ca482 Refactor get_realm_from_request out of views.create_homepage_form. 2016-12-26 17:49:58 -08:00
Rishi Gupta
1ce9a8a458 Remove confusing comments in HomepageForm and RealmCreationForm. 2016-12-26 17:49:58 -08:00
Rishi Gupta
ddf480136c Remove unused domain argument from RealmCreationForm. 2016-12-26 17:49:58 -08:00
Rishi Gupta
ec658d038d Refactor HomepageForm to use a Realm instead of a string_id. 2016-12-26 17:49:58 -08:00
Rishi Gupta
ea634cb982 forms: Refactor HomepageForm to be more pythonic. 2016-12-26 17:49:58 -08:00
Rishi Gupta
a87e653c32 Refactor models.completely_open to take a Realm instead of a domain. 2016-12-26 17:49:58 -08:00
Tim Abbott
cd7d8bfbea travis: Add test-help-documentation to CI for real.
75c4e3191d actually only added it to
`test-all`.
2016-12-26 16:17:42 -08:00
Rishi Gupta
4cf894fcb9 mypy: Update docs to recommend typing.Text instead of six.text_type. 2016-12-26 16:11:37 -08:00
Rishi Gupta
6d780d8dc2 mypy: Convert api/ and docs/ to use typing.Text. 2016-12-26 16:11:37 -08:00
Robert Hönig
79bbba04cf Update the bots development guide for change in triage_message 2016-12-26 16:10:54 -08:00
Tim Abbott
fc496ee279 npm: Upgrade phantomjs-prebuilt to 2.1.14. 2016-12-26 15:26:38 -08:00
Tim Abbott
d579372e8c npm: Upgrade istanbul to 0.4.5. 2016-12-26 15:21:52 -08:00
Rishi Gupta
05abca0848 name_restrictions: Add a few more reserved subdomains. 2016-12-26 14:59:09 -08:00
Rishi Gupta
73a77e2da8 integrations: Fix spelling of mailchimp. 2016-12-26 14:59:09 -08:00
Tommy Ip
7b6603b169 admin: Fix strike-through styling in users & bots tab.
Fix an issue where the `deactivated_user` class is unintentionally
applied to the reactivate user and reactive bot buttons.

Fixes #2905.
2016-12-26 14:51:12 -08:00
Juan Verhook
535ce90272 mypy: Convert zerver/views to use typing.Text. 2016-12-26 13:43:09 -08:00
Rafid Aslam
259e2f0ab4 image-overlay: Fix long image alt text overlapping.
Fix long image alt text overlaps `Download` and `Open` buttons
by changing `<span>` to `<div>`.

Fixes #2912.
2016-12-26 13:40:07 -08:00
Cynthia Lin
853c78753a docs: Add user guide for *Mute a topic* feature 2016-12-26 10:40:06 -08:00
Cynthia Lin
f61d1574cc docs: Add user guide for *Deactivate or reactivate a bot* feature
docs: Add user guide for *Deactivate or reactivate a bot* feature
2016-12-26 10:12:11 -08:00
Rafid Aslam
fd5c43341d interactive bots: Create Giphy bot 2016-12-26 09:38:50 -08:00
Rafid Aslam
947fdf0b37 contrib_bots: Expose some information about user profile
- Expose some information about user profile in `RestrictedClient`
class, like `full_name` and `email` of the user.

- Add `client` argument to `triage_message()`, now it's possible to
call bot with another method instead of calling the specified
keyword.
2016-12-26 09:38:50 -08:00
Abhay Kashyap
13a1425bb7 Created DefineBot and document and added them 2016-12-26 09:07:10 -08:00
Sampriti Panda
fe803fff55 docs: Fix broken link in "About Stream Topic" documentation 2016-12-26 08:22:49 -08:00
Jackson
127ae05073 docs: Add user guide for Mute/Unmute a stream 2016-12-26 08:21:16 -08:00
Sampriti Panda
cc2cae7fdb subs: Refactor filtering logic from subs.filter_table into seperate function 2016-12-26 07:42:38 -08:00
Sampriti Panda
c6d8d72735 tests: Add tests for subs.filter_table 2016-12-26 07:42:38 -08:00
Robert Hönig
1c163c704d Fix wrong command in the bots guide 2016-12-25 10:38:15 -08:00
Robert Hönig
ef3069a5d3 mypy: Convert the isinstances function in /zerver/lib/ to use typing.Text. 2016-12-25 10:33:45 -08:00
Robert Hönig
0917493588 mypy: Convert zerver/lib to use typing.Text. 2016-12-25 10:33:45 -08:00
anirudhjain75
654e8de5ba Doc: Add user guide for Change user's name feature 2016-12-24 11:16:32 -08:00
Cynthia Lin
eb56698202 docs: Add user guide for *Make a public stream private* feature 2016-12-24 11:03:42 -08:00
Rafid Aslam
d0502537ab API: Migrate POST /ui_settings/change to PATCH /settings/ui 2016-12-24 11:02:02 -08:00
KingxBanana
5f77ce1ce8 notifications.js: Make in-browser notifications clickable
You can now click the notifications you get in your browser and go
to that stream/topic/private message using jQuery's .on() method.

Fixes: #1996.
2016-12-24 10:17:24 -08:00
Cynthia Lin
38b0b3ffb5 docs: Add user guide for *Deactivate or reactivate a user* feature
docs: Add user guide for *Deactivate or reactivate a user* feature
2016-12-24 10:11:09 -08:00
Juanvulcano
2fd1316d70 Removed json/update_message
Update test_alert_words.py

Update test_messages.py

Update messages.py
2016-12-24 10:08:22 -08:00
Tommy Ip
067c0b684e docs: Add user guide for *Keyboard shortcuts* feature. 2016-12-24 09:45:25 -08:00
andrewallen00
db0a1b31a3 docs: Add user guide for send a group private message.
docs: Add user guide for send a group private message.

docs: Add user guide for send a group private message.
2016-12-24 09:29:24 -08:00
JefftheBest1
b8ee0e91d2 Migrated json/subscribtions/remove to REST endpoint 2016-12-24 09:27:25 -08:00
Jackson
3a109a56df Migrate notify_settings to settings/notifications
Remove notify_settings from legacy_url.py
2016-12-24 09:24:23 -08:00
anirudhjain75
8acdbef8aa Eliminate legacy json/make_stream_public and json/make_stream_private URL
Migrate from POST to PATCH
2016-12-24 08:54:49 -08:00
Sampriti Panda
39dde79ab8 tests: Improve argument name in check_for_toggle_param_patch 2016-12-24 08:38:33 -08:00
Sampriti Panda
87e7dc6799 urls: Remove legacy URL for left_side_userlist and move over to REST PATCH endpoint 2016-12-24 08:38:33 -08:00
Tommy Ip
acb02cbdd3 docs: Add user guide for *Make a user an administrator* feature. 2016-12-24 08:36:15 -08:00
Tommy Ip
654d9590ef interactive bots: Create Howdoi bot.
This bot allows users to search technical questions from Stack
Overflow.
2016-12-24 08:22:44 -08:00
Cynthia Lin
87d759d597 docs: Add user guide for *Rename a stream* feature 2016-12-23 17:44:17 +01:00
Jackson
333cf0f015 Migrate legacy /json/time_setting to new REST style endpoint. 2016-12-23 08:08:27 -08:00
Cynthia Lin
4db2da66c3 docs: Add user guide for *Delete a stream* feature 2016-12-22 14:55:28 -08:00
Cynthia Lin
e6f61625a1 docs: Add user guide for *About streams and topics* feature 2016-12-22 14:42:34 -08:00
Rishi Gupta
92c54ac3dc user guides: Add ~30 titles for help articles. 2016-12-22 14:12:27 -08:00
Rishi Gupta
6f5d75ffd8 user guides: Edit names of a few help articles. 2016-12-22 14:12:27 -08:00
Tommy Ip
1e0de94293 API: convert get_subscribers from legacy URL to REST endpoint. 2016-12-22 09:25:12 -08:00
Cynthia Lin
dfa32d7eb0 docs: Add user guide for *Deactivate your account* feature 2016-12-22 09:01:33 -08:00
Maydha K
1c788d3fb5 docs: Add user guide for viewing messages from a stream. 2016-12-22 16:58:18 +01:00
Tim Abbott
7d99380488 update_display_settings: Move validation to beginning.
This makes the function more friendly for adding additional
functionality to.
2016-12-22 06:58:53 -08:00
Tim Abbott
0299f41c80 settings: Extract update_display_settings_backend. 2016-12-22 06:57:06 -08:00
anirudhjain75
c9db6b6658 Clean up legacy language_settings endpoint. 2016-12-22 06:54:04 -08:00
Tim Abbott
5cd6ff20b0 models: Fix bare except clause. 2016-12-22 06:46:43 -08:00
Jackson
62f88aa776 interactive bots: Create CommuteBot. 2016-12-21 18:46:59 -08:00
Jackson
e7fe9217a5 docs: Add user guide for Viewing the markdown source of a message. 2016-12-21 17:48:36 -08:00
Brock Whittaker
41f6420df0 help: Add Tip CSS.
This adds the CSS for a tip section. Utilizes the CSS ::before
pseudo-selector and fontawesome.
2016-12-21 15:40:55 -08:00
Yago González
ca190bd394 bug fix: Handle empty at-mentions gracefully.
An exception in the webapp was trown when an empty mention was sent.
Examples of problematic messages are "@" or "@****".

In order to fix this, the regex that identifies mentions has been
modified, so it now requires the mention to have a "content" (by
replacing the ? quantifier by +).

A test case has been added to `frontend_tests/node_tests/echo.js` to
check that this works properly in the future.
2016-12-21 15:32:12 -08:00
Niels Terwiesch
0d21d931bf docs: Add user guide for Remove user from stream. 2016-12-21 15:20:38 -08:00
Cynthia Lin
1a6b6655a5 docs: Add user guide for *Signing in* feature 2016-12-21 15:08:29 -08:00
Jackson
7b209f7f7f docs: Add user guide for Collapse a Message. 2016-12-21 15:06:37 -08:00
JefftheBest1
0e6078fade Wrapped text in admin user and bot tables.
Fixes: #2569.
2016-12-21 14:55:50 -08:00
Tim Abbott
a90532e074 admin: Clean up Zulip labs changing reloading browser. 2016-12-21 14:21:06 -08:00
Sampriti Panda
425a55e568 settings: Implement delete avatar functionality 2016-12-21 13:35:22 -08:00
Sampriti Panda
e72cd0b1cc urls: convert set_avatar from legacy URL to REST endpoint 2016-12-21 13:35:22 -08:00
Sampriti Panda
567fab1137 tests: Add client_put_multipart to allow for file uploads using PUT 2016-12-21 13:35:22 -08:00
Tim Abbott
e538d7ef03 admin: Fix waiting period status UI not hiding. 2016-12-21 13:19:40 -08:00
Rafid Aslam
73acebb729 API: Remove json/fetch_raw_message from zproject/legacy_urls.py 2016-12-21 13:08:40 -08:00
Rafid Aslam
bfe84a10f0 API: Migrate POST json/fetch_raw_message to GET json/messages/<id> 2016-12-21 13:08:40 -08:00
Tommy Ip
400c8c1f65 Prioritize stream subscribers in typeahead list.
When autocompleting names using @mention, subscribers of the stream
would appear at the top of the list. Added new test module to reflect
this change.
2016-12-21 12:59:43 -08:00
Maydha K
516ccd706c docs: Add user guide for the announce stream. 2016-12-21 12:13:27 -08:00
anirudhjain75
5321f246ef docs: Add User Guide for private message 2016-12-21 12:05:05 -08:00
Tim Abbott
7a56f0137e Fix accidentally merged test error in Node tests. 2016-12-21 12:02:05 -08:00
Cynthia Lin
61c4db8ad2 docs: Add user guide for *Invite a friend to Zulip* feature 2016-12-21 11:42:39 -08:00
Sanskar Modi
e6beaa2711 Improve @all warnings user interface significantly.
* Doesn't pop up the warning until you actually try to send the message
* Eliminates the red warning.
* Changes confirm text to "Yes, send".
* Adds a stream size threshhold of 15 people; smaller streams don't
  prompt about this.

Fixes #2257.
2016-12-21 11:40:47 -08:00
Steve Howell
680ff3f80c Remove mypy exemption for api/zulip/__init__.py.
This required instead exempting these files:

    bots/jabber_mirror_backend.py
    tools/deprecated/iframe-bot/show-last-messages

Turning on mypy for the API exposes issues in the annotations
of other files.
2016-12-21 11:22:42 -08:00
Steve Howell
efc2d1a675 Simplify, document, and fix the API code.
We used to create endpoints with Client._register.

Now we now have explicit methods for the endpoints.

This allows us to add docstrings and stricter mypy annotations.

This fix also introduces a call_endpoint() method that avoids
the need for manually building urls with API_VERSTRING when you
know the URL pattern of the endpoint you want to hit (and when
the API doesn't have a convenient wrapper).

I fixed a bug with create_users where it now uses PUT instead
of POST.

I also removed client.export(), which was just broken.

I had to change recent-messages and zulip-export, which were
using client.do_api_query and Client._register.

Now it's easier to just call client.call_endpoint() for
situations where our API doesn't have convenient wrappers,
so that's what I did with those scripts.
2016-12-21 11:22:42 -08:00
Shubham Singh
bade6f496b Fix autocompleting stream names inside message editing.
Fixes #2577.
2016-12-21 11:09:42 -08:00
Tim Abbott
753a25268c help: Enable and use the markdown admonition extension.
This allows us to add warnings and tips in the Zulip help documents.
2016-12-21 11:01:49 -08:00
Juan Verhook
4cbfac68ca Added User Guide for the Delete a Stream Feature. 2016-12-21 10:56:28 -08:00
Tommy Ip
8e86ed7364 Improve join chat button.
Update join chat button to match with other badges in README.md.
2016-12-21 10:51:54 -08:00
Cynthia Lin
4ecc9deb92 docs: Add user guide for *View the exact time a message was sent* feature 2016-12-21 07:57:05 -08:00
K.Kanakhin
e122dcab5c dev-proxy-logging: Add client ip transference to proxy server.
- Add rewriting 'X-REAL-IP' header for each request through dev
  proxy server.
- Change webpack configuration ip to 0.0.0.0 to fix socket.io build
  for launching remote dev server.
2016-12-21 17:18:02 +06:00
K.Kanakhin
4750d30341 dev-proxy-logging: Disable dev proxy logging by default.
- Add parameter to proxy launchig script, which enables logging
  for dev proxy server (disabled by default).
2016-12-21 17:18:02 +06:00
andrewallen00
75340c93b0 docs: Add user guide for send a stream message
docs: Add user guide for send a stream message
2016-12-20 18:36:49 -08:00
Cynthia Lin
365a4808bc docs: Add user guide for *Change date and time format* feature
docs: Add user guide for *Change date and time format* feature
2016-12-20 18:24:59 -08:00
Rafid Aslam
aece2c7c45 populate_db: Fix naive datetime warnings
Fix naive datetime warnings in
`zilencer/management/commands/populate_db.py`.

Fixes #2729.
2016-12-20 17:48:22 -08:00
Cynthia Lin
6964959017 docs: Add user guide for *View information about a message* feature 2016-12-20 17:26:14 -08:00
Jackson
59eb7a54e2 integrations: Add documentation for GoSquared. 2016-12-20 16:59:36 -08:00
Jackson
4ff4f12aea integrations: Add webhook code, API endpoint, and tests for GoSquared. 2016-12-20 16:59:36 -08:00
anirudhjain75
db894b9912 Create "join chat" button for Zulip.
The image that we are using can be found in the zulip repository
in the directory`static/images/help` named as chat-with-zulip-button.

We use the new button in the readme, and we also provide instructions
on how to embed the button in other sites in the help docs.

Fixes: #2270
2016-12-20 16:10:21 -08:00
Cynthia Lin
f2d7f37757 docs: Add user guide for *Change the topic of a message* feature
docs: Add user guide for *Change the topic of a message* feature
2016-12-20 15:21:24 -08:00
Cynthia Lin
6e11b76725 docs: Add user guide for *View your current stream subscriptions* feature. 2016-12-20 12:06:05 -08:00
Rishi Gupta
c7c0e36508 analytics: Add InstallationCount checks to prototype TestCountStat.
Was enabled by commit 41e8ee3 where we moved TIME_ZERO to before the realms
created by populate_db.py.

Also removes the stub for TestAggregates, since the remaining thing to be
tested was the aggregation from RealmCount to InstallationCount, and the end
to end checks provided by the TestCountStat tests should be sufficient.
2016-12-20 12:03:23 -08:00
Rishi Gupta
dbc94d0fc0 analytics: Remove test for no longer supported behavior.
In a previous design, there was no FillState table, and one could run any
CountStat at any time. This is no longer supported.

This test was making sure that if one ran a CountStat at a certain hour, and
then ran it at a previous hour, the old rows would still be there.
2016-12-20 12:03:23 -08:00
Rishi Gupta
e09aaf1020 analytics: Remove tests that will be subsumed by TestCountStats. 2016-12-20 12:03:23 -08:00
Rishi Gupta
6748b72ccc analytics: Remove tests now covered by test_active_users_by_is_bot. 2016-12-20 12:03:23 -08:00
Rishi Gupta
2211b8b102 analytics: Change count_message_by_stream to join on UserProfile.
It seems unlikely we will need count_message_by_stream without the
UserProfile table in the future, so write count_message_by_stream_and_is_bot
in the usual query form and replace count_message_by_stream with it.
This also has the benefit of shortening our list of "special case" queries
from two to one.

The pathways of the removed test will be covered more thoroughly in the new
TestCountStats tests.
2016-12-20 12:03:23 -08:00
Rishi Gupta
6992f9784c analytics: Update TestCountStat prototype. 2016-12-20 12:03:23 -08:00
Rishi Gupta
c6a6c871ee analytics: Change TIME_ZERO in tests to be in the past. 2016-12-20 12:03:23 -08:00
Rishi Gupta
d95fb33d8d analytics: Add subgroups to unicode representations in models.py. 2016-12-20 12:03:23 -08:00
Rishi Gupta
f34af0896d analytics: Add subgroup argument to assertCountEquals. 2016-12-20 12:03:23 -08:00
Rishi Gupta
31cf8db28c analytics: Allow assertCountEquals to work on InstallationCount. 2016-12-20 12:03:23 -08:00
AZtheAsian
09b1c18fbe integrations: Add documentation for Stripe 2016-12-20 11:56:04 -08:00
Rafid Aslam
e49bd6a6c7 event_queue: Improve error message for ConnectionError exception
Improve error message for "ConnectionError:
HTTPConnectionPool(host='localhost', port=9993): Max retries
exceeded" exception.

Fixes #215.
2016-12-20 11:49:12 -08:00
Tim Abbott
7f7cae332b logging: Fix handling of tracebacks with no exc_info. 2016-12-20 11:49:12 -08:00
Robert Hönig
5ea1b835c9 Rename and reorder the bots guide 2016-12-20 11:40:04 -08:00
Joy Chen
7da65ecb1a docs: Add user guide for rename a stream 2016-12-20 11:13:11 -08:00
Cynthia Lin
56e1fb6df6 docs: Add user guide for *Restore the last unsent message* feature. 2016-12-20 11:01:44 -08:00
lonerz
25368c6863 bots-guide: Fix numbering indentation 2016-12-20 10:32:30 -08:00
Rafid Aslam
5cc8838df4 tests: Add assert_url_serves_contents_of_file() to ZulipTestCase
Add `assert_url_serves_contents_of_file()` in `ZulipTestCase` class
and deduplicate some codes.

Fixes #1276.
2016-12-20 08:06:22 -08:00
Rafid Aslam
64f595b061 tests: Add test about avatar image was uploaded properly or not
Add test about avatar image was uploaded properly or not in
`tests.BotTest.test_add_bot_with_user_avatar` and
`tests.BotTest.test_patch_bot_avatar`.

Add `get_test_image_file()` and `avatar_disk_path()` in
`zerver.lib.test_helpers` and deduplicate some codes.

Fixes #1276.
2016-12-20 08:06:22 -08:00
=
f83139e28c Interactive bots: Create Github Issues bot. 2016-12-19 21:57:21 -08:00
KingxBanana
23f3271551 Clear popovers on stream narrows fix (Issue #2281) 2016-12-19 21:05:18 -08:00
Steve Howell
7317dd1825 Fix broken links in bots-guide.md. 2016-12-19 19:30:25 -08:00
Steve Howell
732967f80e Fix broken link -> send-private-message. 2016-12-19 19:16:52 -08:00
Robert Hönig
63e1ca05ea Add developer documentation for bots 2016-12-19 16:29:42 -08:00
Maydha K
4da1ffae9c docs: Add user guide for previewing your message. 2016-12-19 13:39:42 -08:00
Cynthia Lin
4d1b67286d docs: Add user guide for *Send a private message* feature (#2785)
docs: Add user guide for *Send a private message* feature
2016-12-19 13:07:56 -08:00
Umair Khan
9069cad79d logging: Set django.request to ERROR in testing.
Fixes #2731
2016-12-19 09:12:11 -08:00
Tim Abbott
062d14fd63 help: Fix trailing whitespace in pin-a-stream article. 2016-12-19 09:03:29 -08:00
K.Kanakhin
75c4e3191d tests: Add help documentation checking script to CI 2016-12-19 08:31:39 -08:00
K.Kanakhin
589ae27190 documentation-crawler: Exclude privacy page from documentation checking 2016-12-19 08:31:39 -08:00
K.Kanakhin
a57752d158 help-documentation: Fix links in user help documentation 2016-12-19 08:31:39 -08:00
KingxBanana
28b49cb440 docs: Add user guide for pin a stream 2016-12-19 08:22:50 -08:00
Sampriti Panda
c0326d1938 Add lint rule to disallow python calls with versions (e.g: python2, python3)
Fixes #2435
2016-12-19 08:00:48 -08:00
Cynthia Lin
f826c87a73 docs: Add user guide for *Change your avatar* feature 2016-12-19 07:40:41 -08:00
Cynthia Lin
3227484fbf docs: Add user guide for *Add or invite someone to a stream* feature 2016-12-18 19:33:11 -08:00
Maydha K
ab927d3e96 docs: Add user guide for viewing an image at full size. 2016-12-18 13:51:34 -08:00
Saumya Rawat
d3a7d0202f dev: Auto-create log directory in management command.
Check 'zulip/var/log' folder exists and create if not as FileHandler only checks for existence of log file.
2016-12-17 17:18:49 -08:00
Maydha K
85558df4bb docs: Add user guide for pressing enter to send. 2016-12-17 16:46:42 -08:00
Cynthia Lin
64e4eea000 docs: Add user guide for *Edit or delete a message* feature 2016-12-17 16:45:13 -08:00
andrewallen00
cdef7ede83 interactive bots: Create comment on issue GitHub bot.
interactive bots: Create comment on issue GitHub bot.

interactive bots: Create comment on issue GitHub bot.

interactive bots: Create comment on issue GitHub bot.

interactive bots: Create comment on issue GitHub bot.
2016-12-17 16:33:08 -08:00
Akhil
06615bee00 streams: Implement copy-subscribers feature.
In the new stream creation modal, added checkboxes for each stream
and a toggle to see or hide the checkboxes. Altered filtering to
filter streams and users. Added corresponding casper tests.

When a stream is checked/unchecked, it does not affect the state
of any user checkbox. This may be visually unclear as users can be
added even if their checkboxes are empty.

Fixes #2448
2016-12-17 11:20:47 -08:00
Cynthia Lin
e87cc4e622 docs: Add user guide for *Unsubscribe from a stream* feature 2016-12-17 08:51:38 -08:00
Arpith Siromoney
f144009c6d Change color of white emojis (1️⃣, 2️⃣, etc) to blue.
The following emojis are colored white (with a transparent background)
and are hard to read in the context of Zulip. This commit changes their
colors to blue. The emojis are:

hash, zero, one, two, three, four, five, six, seven, eight and nine.

This fixes #1969.
2016-12-16 09:46:37 -08:00
K.Kanakhin
fa68a678cc help-documentation-tool: Add tools for checking user help documentation.
- Add spider for documentation crawler, which processes user help
  documentation on test development server.
- Add tool script for help documentation checking launching.

Fixes #2639
2016-12-16 09:04:04 -08:00
K.Kanakhin
2cbc7bb2c1 documentation-crawler: Create common spider for documentation checking.
Fixes #2639
2016-12-16 09:04:04 -08:00
K.Kanakhin
bae5afe458 Initialize markdown extensions once per process instead markdown engine.
- Markdow engine is not safe threading as global variable. In some cases
  it generates previous markdown templates on concurent requests. It's
  enough to generate markdown extensions per process to save time. Also
  this solution is thread safe.
2016-12-16 09:04:04 -08:00
K.Kanakhin
b0816dff73 help-documentation: Fix typos in help documentation.
Fixes #2639
2016-12-16 09:04:04 -08:00
Tomasz Kolek
34511065dc Fix tests problem with backward incompatible function name.
Add __init__ methods to some of testing clases with overriding method name.
2016-12-16 07:04:55 -08:00
Umair Khan
7f3fdb2663 Django 1.10: Immediately save session to mitigate race conditions. 2016-12-16 16:24:12 +05:00
paxapy
28bd9d035c click_handlers.js: Handle clicks on stream links using data-stream-id.
This causes Zulip to correctly handle clicks on announcements for
renamed streams.

The stream name that the user typed will still be displayed, which
isn't ideal, but is probably the best we can do without more invasive
rerendering of old messages.

Fixes #426.
2016-12-15 22:48:19 -08:00
paxapy
18e43895ff streams.py: replace stream_subscribe_button with new #stream syntax.
Previously, we included a special subscribe button in new stream
notifications, but that had 2 problems:

(1) The subscribe button would render badly if the stream was renamed.
(2) There wasn't an easy way to look at the stream when deciding
whether to subscribe.

This fixes the second problem, but not really the first.
2016-12-15 22:43:14 -08:00
Tim Abbott
d3b1f6e273 populate_db: Add notifications stream for Zulip realm. 2016-12-15 22:43:08 -08:00
Umair Khan
6c1d805495 travis: Fix production suite flakiness.
Previously, we were doing this request to the production server before
waiting for all the supervisord processes to start; it's possible this
could cause failures where we hit the server before the Django uwsgi
processes are up.

Hopefully fixes #2723.
2016-12-15 22:04:57 -08:00
Tim Abbott
81dbf8c80a lint: Enforce no external resources in CSS. 2016-12-15 22:02:10 -08:00
Brock Whittaker
105ef7caae Add markdown page styling.
This styles inline images, the markdown page as a whole, and the
notification buttons to be CSS rather than images.

[Tweaked by tabbott to temporarily remove the Yantramanov font, since
we should be committing that to the repo so Zulip works correctly without
Internet access]
2016-12-15 21:59:58 -08:00
Cynthia Lin
208da224e1 docs: Add user guide for *Advanced search* feature. 2016-12-15 21:48:07 -08:00
Tim Abbott
9ddec92d8a docs: Add missing link to Zulip sign out docs. 2016-12-15 21:43:56 -08:00
Tim Abbott
ab8cd37bd8 markdown: Fix performance probelm loading /help/.
Apparently, we were running the markdown processor a second time on
the HTML output of the configured markdown processor.

Fixes #2735.
2016-12-15 21:43:56 -08:00
Tim Abbott
9d6e1030de test_public_urls: Fix URL coverage instrumentation bug. 2016-12-15 20:58:46 -08:00
Tim Abbott
66bce06a5a lint: Fix E127 vilations due to recent assertEquals migration. 2016-12-15 20:51:27 -08:00
Tim Abbott
7cd3a5873d admin: Remove unnecessary set_up_deactivate_user_modal. 2016-12-15 18:18:26 -08:00
Brock Whittaker
d20e643c59 admin: Fix Deactivate/Reactivate User Buttons.
This fixes the behavior to be consistent and remove the “Working…” bug.
2016-12-15 18:17:07 -08:00
Brock Whittaker
36319ca501 Give the #home entry in the gear menu an invisibility cloak.
Previously, this would create a weird blue banner across the top of
the gear menu.

We can't remove it, since it’s required for the gear menu navigation.

Description edited by tabbott.
2016-12-15 18:13:33 -08:00
Steve Howell
47a655a3cc Extract people.extract_people_from_message() and fix bug.
This commit extracts people.extract_people_from_message()
from message_store.add_message_metadata(), and now
add_message_metadata() extract people before it calls
process_message_for_recent_private_messages(), which
fixes a bug where we are trying to look up an email
for a deactivated user who was in the message but not
in the pre-loaded list of people.

Fixes #2701
2016-12-15 17:44:58 -08:00
Steve Howell
b46d7654f8 Change people.remove() to people.deactivate() and fix bug.
This commit changes people.remove() to be people.deactivate(),
and it fixes a bug where deactivating users was causing tracebacks
in the PM list if somebody had PM'ed the deactivated user
recently.
2016-12-15 17:44:58 -08:00
Steve Howell
b2bb2f8ea0 Extract people.init() function.
We need this for node tests, so that you don't have to explicitly
remove every user between tests.  (Also, people.remove() is about
to have different semantics.)
2016-12-15 17:44:58 -08:00
Tomasz Kolek
bb6d189fa8 Add github dispatcher to have one elegant url for both github integrations.
Dispatcher avoids to create new URL for github_webhook.
2016-12-15 17:42:28 -08:00
Tim Abbott
7bf3fb30ea tests: Remove unnecessary duplicate HelpTest.
It had a mysterious performance problem and we have a test for that
code path anyway.
2016-12-15 17:14:36 -08:00
Tim Abbott
bf80873d4f tests: s/assertRaisesRegexp/assertRaisesRegex/ due to deprecation. 2016-12-15 17:11:42 -08:00
Tim Abbott
6bb959ff4e url_preview: Fix BeautifulSoup DeprecationWarning. 2016-12-15 17:05:10 -08:00
Tim Abbott
a116c86f62 tests: s/assertEquals/assertEqual/ due to deprecation.
Fixes #2730.
2016-12-15 17:02:03 -08:00
vaibhav
75bf501553 Add optional waiting period for users to create streams.
This adds support for only allowing normal users with account age
equal or greater than a "waiting period" threshold to create streams;
this is useful for open organizations that want new members to
understand the community before creating streams.

If create_stream_by_admins_only setting is set to True, only admin users
were able to create streams. Now normal users with account age greater
or equal than waiting period threshold can also create streams.

Account age is defined as number of days passed since the user had
created his account.

Fixes: #2308.

Tweaked by tabbott to clean up the actual can_create_streams logic and
the tests.
2016-12-15 16:54:30 -08:00
Niels Terwiesch
e04fe084b7 docs: Add user guide for change stream color. 2016-12-15 16:28:20 -08:00
Tomasz Kolek
6fdc026f64 Move get_profile_backend to views/users.py.
Fixes: #2710.
2016-12-15 16:04:23 -08:00
Rishi Gupta
93a10a475a counts.py: Fix count_message_type_by_user_query. 2016-12-15 16:02:12 -08:00
Rishi Gupta
4f3e1b2ece analytics/lib/counts.py: Fix messages_sent_to_stream:is_bot.
Adds a new query.
2016-12-15 16:02:12 -08:00
Rishi Gupta
87b47ec283 analytics: Add __unicode__ method to the CountStat object. 2016-12-15 16:02:12 -08:00
Rishi Gupta
71edcb6490 bulk_create: Refactor bulk_create_users to use more pythonic style.
Note: This changes semantics slightly; you now can't call
bulk_create_users with a list of N users containing duplicates and
expect it to work.
2016-12-15 16:00:48 -08:00
Umair Khan
d85e85c9eb linter: Add rule to check title attribute for i18n.
Fixes #2698
2016-12-15 13:44:13 -08:00
Umair Khan
db5d86ab9e i18n: Title attribute should be translatable. 2016-12-15 13:44:13 -08:00
Umair Khan
ab25cd7401 casper: Redirect to english url. 2016-12-15 13:44:13 -08:00
Umair Khan
4155795a16 docs: Fix i18n documentation for translating blocks. 2016-12-15 13:44:13 -08:00
Rishi Gupta
6b39f3222c Remove Realm.domain from populate_db.py.
Fixes #2286.
2016-12-15 13:22:17 -08:00
Rishi Gupta
fc188de8e0 bulk_create: Refactor bulk_create_users to take Realm instead of domains.
Previously bulk_create_users would figure out a user's realm from their
email domain. Now require that a realm be passed explicitly.
2016-12-15 13:22:17 -08:00
Rishi Gupta
84bb73ab65 bulk_create: Clean up ORM calls in bulk_create_streams. 2016-12-15 13:22:17 -08:00
Rishi Gupta
56c8b58cbc populate_db: Remove create_streams.
Is extraneous indirection.
2016-12-15 13:22:17 -08:00
Rishi Gupta
ee9b59321c populate_db: Refactor create_streams.
Remove unused field from stream_dict.
2016-12-15 13:22:17 -08:00
Rishi Gupta
fbf48f7ec6 bulk_create: Refactor bulk_create_streams to not take domain dictionary.
First step in cleaning up populate_db.create_streams and
bulk_create.bulk_create_streams. Part of a series of commits to remove
Realm.domain from populate_db.
2016-12-15 13:22:17 -08:00
Umair Khan
c24fbd28b2 Shift to python-gcm for Android push notifications.
Fixes #2650
2016-12-15 12:17:07 -08:00
Tim Abbott
4cef220789 bots: Remove obsolete tddium-notify-humbug. 2016-12-15 12:16:26 -08:00
Sampriti Panda
0fb3c07c6e integrations: Add documentation for AppFollow 2016-12-15 11:13:27 -08:00
Sampriti Panda
91780180f6 integrations: Add webhook code, API endpoint, and tests for AppFollow 2016-12-15 11:13:27 -08:00
Tim Abbott
2674a3f78b bots: Remove old zulip.com configuration files. 2016-12-15 09:39:32 -08:00
Tim Abbott
e1ed8e61d8 api: remove use of zulip.com domain in API bindings. 2016-12-15 09:35:37 -08:00
Tomasz Kolek
34d7c2266b Add documentation for changing SITE param in hubot configuration. 2016-12-14 23:58:56 -08:00
Tomasz Kolek
aa7014f946 Add documentation for changing SITE param in redmine configuration. 2016-12-14 23:58:56 -08:00
Umair Khan
efccefc386 Upgrade to the latest Django release, 1.10.4.
Most of the changes to support this were merged some time ago; what
remains are these changes:

* Update requirements.txt
* Django 1.10: Upgrade success-http-headers.txt file.

- We no longer get the absolute urls, see
  https://docs.djangoproject.com/en/1.10/releases/1.9/#http-redirects-no-longer-forced-to-absolute-uris
- The headers are capitalized, previously, they were in upper case.

* Bump PROVISON_VERSION to 3.0 since this is a disruptive change.

Fixes #3.
2016-12-14 22:43:20 -08:00
Umair Khan
770a899239 Django 1.10: Use single cache prefix for casper tests.
There is a change in Django 1.10 due to which whenever the password
of the user is changed the session hash changes. This change affects
us because we cache user profile objects and these cached objects need
to be refreshed. However, the signal sent by Django in which objects are
refreshed fails to refresh the cache for Tornado because it uses a
different cache prefix.

Note: Backend tests are not affected because they don't rely on Tornado.
2016-12-14 22:40:33 -08:00
Umair Khan
9f5c961a1b Django 1.10: Use django-bitfield from Disqus.
Disqus is the upstream for django-bitfield and has now merged in the
support for Django 1.10 we were previously getting from another
repository.
2016-12-14 22:38:35 -08:00
Tim Abbott
f0f4be4af7 lint: Fix remaining no-unused-vars eslint rule violations. 2016-12-14 22:36:47 -08:00
Tim Abbott
fe2d38392f subs: Restore debouncing of stream filtering.
This appears to have been accidentally removed in the redesign.
2016-12-14 22:36:47 -08:00
Rafid Aslam
45f39be37f lint: Fix many no-unused-vars eslint rule violations.
These have been carefully audited by tabbott to ensure they are
unlikely to cause regressions.
2016-12-14 21:34:51 -08:00
Brock Whittaker
80ad28bab5 Don't repeat date header if message date is same as previous.
This primarily works to make sure that new queued messages don’t end up
with redundant date headers on them.
2016-12-14 20:41:33 -08:00
Tim Abbott
0b33be50f3 lint: fix some whitespace issues in new reactions code. 2016-12-14 20:37:13 -08:00
Tommy Ip
0329b67048 admin: Limit bots in settings page.
Updated `get_editable()` so that organization admins only see their
own bots in their personal settings page; this removes a lot of
unnecessary clutter.

Fixes #2657.
2016-12-14 19:29:02 -08:00
Tommy Ip
fa4050d62d Improve error handling in is_current_user().
Realm bots have a owner of `null` but that is not explicity handled
in `is_current_user()`.
2016-12-14 19:27:43 -08:00
Kracekumar R
61d2297c17 Add reactions in the /json/messages endpoint. 2016-12-14 19:21:04 -08:00
Steve Howell
546cc27f0d minor: Add code comment re:unread counts. 2016-12-14 19:10:55 -08:00
Steve Howell
5444486acb Have unread_topic_counter.get_counts() return a result.
Before this change, we passed in a hash to get_counts() to
mutate, but now we make the caller responsible for splicing
results into a bigger data structure.

The function now involves no mutation.
2016-12-14 19:10:55 -08:00
Steve Howell
b11fbf0b4b Consolidate stream/topic logic for unread messages.
This change introduces an unread_topic_counter object
that manages unread counts for streams and topics.  Consolidating
all the logic into a single class will set us up to add
logic for dealing with topic counts that includes provisional
counts of unread messages from the server.  It also makes
the current code a little easier to reason about.

Most of this change was simply extracting functions, but
I also removed a few unnecessary and inconsistent calls to
`stream_data.canonicalized_name` that preceded our use of
Dict with a fold_case argument.
2016-12-14 19:10:55 -08:00
Rafid Aslam
2dffe5c95a contrib_bots: Allow to import code from subdirectory of lib
Allow to import code from subdirectory of `contrib_bots/lib`.
Because sometimes bot requires grouping in their directory,
especially for the bot that has configuartion file and documentation.
2016-12-14 16:35:49 -08:00
Brock Whittaker
c25694a9d9 Do not reload page on form submission in settings page.
Currently under Zulip Labs and Notifications, saving changes reloads
the page. This shouldn’t happen.

Fixes #2697.
2016-12-14 16:32:32 -08:00
Brock Whittaker
706b2e7978 Absolutely position the .recipient_row_date.
Firefox doesn’t handle multiple floats well so this is a better
solution — to absolutely position it in the recipient row container.
2016-12-14 15:44:54 -08:00
Rishi Gupta
a5add3dfb6 user guides: Synchronize names of articles with names of links. 2016-12-14 15:40:48 -08:00
Rishi Gupta
df25e61328 help/index.md: Add names of articles to create. 2016-12-14 15:40:48 -08:00
Brock Whittaker
6ed7ba8935 Blur all links after clicking.
The links don’t have to stay focused and produce unintended side
effects.
2016-12-14 15:37:43 -08:00
Brock Whittaker
660144a79d Blur the active element on settings/streams modal exit.
This blurs any focused element so that you can’t accidentally enter
into anything on a hidden modal.
2016-12-14 15:37:43 -08:00
Steve Howell
af857d883b contrib_bots: Add "Python dependencies" to docs. 2016-12-14 15:03:51 -08:00
Steve Howell
45e4edf105 contrib_bots: Add "Third Party Configuration" to docs. 2016-12-14 15:03:51 -08:00
Igor Tokarev
f154a3b742 tests: Improve test coverage of templates.
Addresses part of #1677.
2016-12-14 13:08:33 -08:00
Harshit Bansal
dc4e56abae Show offending stream name incase of a non existent stream.
Fixes: #2171.
2016-12-14 12:17:20 -08:00
Tomasz Kolek
f2319d1b08 Add unittests for receives_offline_notifications function.
Fixes #2645.
2016-12-14 12:03:12 -08:00
Tomasz Kolek
bec9ce755d Add unittests for receives_online_notifications function.
Fixes: #2645.
2016-12-14 11:49:59 -08:00
Rishi Gupta
92a72f7039 mypy: Use typing.Text in actions.py. 2016-12-14 11:40:34 -08:00
Umair Khan
8e30530cc5 subdomains: Make GitHub login work with subdomains.
Fixes #2501.
2016-12-14 11:09:39 -08:00
Umair Khan
2fc6b9a0e4 backends.py: Return type of do_auth should be HttpResponse. 2016-12-14 11:08:53 -08:00
Rafid Aslam
78f3fd7999 API: Expose is_mentioned in message dictionary.
Expose `is_mentioned` in `message` dict which contains
boolean value about our account is mentioned in the message
content or not.

This is already available via `flags`, but it seems worth making this
data point more explicit, given its importance in writing bots.

Fixes #2667.
2016-12-14 10:52:13 -08:00
Rafid Aslam
63c157a22b API: Expose more information in get_profile_backend()
Adding more additional information about user profile to
`zerver.views.pointer.get_profile_backend`, like `user_id`,
`full_name`, `email`, `is_bot`, `is_admin`, and `short_name` of the
user.
2016-12-14 10:51:39 -08:00
Tim Abbott
988a2e2d8e generate_invite_links: Use realm host properly. 2016-12-14 10:46:45 -08:00
Tim Abbott
639dc9108d set_default_streams: Fix multi-line help output. 2016-12-14 10:40:04 -08:00
reyha
82e32ad255 Access realm by string_id in management commands.
`Realm.string_id` replaces 'Realm.domain'
in the management commands.

Fixes #2325.
2016-12-14 10:38:03 -08:00
hackerkid
7f8aef1a17 Add additional resources to code review. 2016-12-13 23:12:10 -08:00
hackerkid
3236b8ee2b Add translation in the code review check list. 2016-12-13 23:12:10 -08:00
Tim Abbott
ee3fbe9193 api: Clean up the README.md somewhat. 2016-12-13 22:55:40 -08:00
Tim Abbott
9248edaaeb api: Require a recent version of the typing module. 2016-12-13 22:55:40 -08:00
Tim Abbott
34c3e03ef8 api: Update list of example scripts to include. 2016-12-13 22:55:40 -08:00
Tim Abbott
204ab0a3da api: Update author to Zulip open source project. 2016-12-13 22:55:40 -08:00
Tim Abbott
ad9c3d7d18 README: Reframe discussion of our Google group. 2016-12-13 22:31:16 -08:00
Sumana Harihareswara
ef439bb809 Reduce mailing list links in README for GSoC funnelling.
The zulip-devel mailing list is receiving enough low-quality
interest emails from people interested in GSoC that we
are reducing the number of links to the list in the README,
and adding more wording to funnel GSoC applicants to the
appropriate venues.
2016-12-13 22:29:42 -08:00
Brock Whittaker
61fb6cf418 user guides: Fix some formatting in index. 2016-12-13 21:56:58 -08:00
Brock Whittaker
e160ebf833 sidebar: Change Private Messages Icon to Envelope.
Originally the private messages icon was a user icon, but it has been
changed to envelope for clarity.
2016-12-13 21:55:55 -08:00
Umair Khan
336a041ac0 Django 1.10: Use uWSGI.
Fixes: #1121

With some tweaks by tabbott to make the number of processes configurable.
2016-12-13 21:40:43 -08:00
Umair Khan
fda0387695 Create Python version agnostic venv link for prod.
This link points to either 'zulip-venv' or 'zulip-py3-venv' and makes
uWSGI configration very easy.
2016-12-13 21:40:43 -08:00
Umair Khan
3b7959c308 Django 1.10: Update i18n.
Django 1.10 uses the correct locales for simplified and traditional
Chinese languages. Previous versions used 'zh_CN' and 'zh_TW'
respectively while now the locales are 'zh_Hans' and 'zh_Hant'. This
commit takes care of this transition by doing the following:

- Add a missing translation zh-hans locale so that our tests pass.
- Add zh_Hans locale directory under 'static'. Case of the local name
is important, if we use 'zh_HANS' then the compiled translations
do not work under certain conditions.
2016-12-13 21:40:43 -08:00
Umair Khan
c7ec5a14ee Create redirect_to_main_site function.
This function is used in OAuth logins so that we can redirect first to
the root domain (e.g. zulipdev.com if subdomains are *.zulipdev.com).
2016-12-13 21:06:52 -08:00
Tim Abbott
7e8f8551de decorator: Change /activity to be gated on is_staff.
Zulip doesn't previously make use of the standard Django is_staff flag
(in that the Django admin site is disabled), but since conceptually
the /activity page would be part of the Django admin site if we were
using it (i.e. for server-level administrators), it makes sense to key
off of that rather than the previous, fragile, check for the realm
domain name.
2016-12-13 21:06:27 -08:00
peguin40
01a0d11705 Show markdown help in message editing UI.
Fixes #2578.
2016-12-13 20:49:39 -08:00
Brock Whittaker
a460fcddef Add Date Headers to Floating Bar and Message Headers.
This adds the date of a block of messages to the floating recipient
bar along with message headers of blocks that are the first of a
particular day.
2016-12-13 20:36:39 -08:00
Brock Whittaker
2fc803786b Fix margins in Subscriptions Overlay.
There is a case with browser zoom that the inline-block split view
breaks down and the two 50% tabs fall below each other. This prevents
that issue from happening.
2016-12-13 20:35:14 -08:00
Steve Howell
0c49cebe86 Remove deprecated get_messages() API.
This also eliminates a very short script that basically
does nothing but call the long-dead API, so there's not
much to salvage there.
2016-12-13 20:33:20 -08:00
Bojidar Marinov
8b44ace3a8 frontend: Make global notifications live-update on changes.
Fixes #2527
2016-12-13 20:22:13 -08:00
Bojidar Marinov
d28f1ddfb4 zerver: Handle update_global_notifications in apply_events
Fixes #2358
2016-12-13 20:20:26 -08:00
Cynthia Lin
23652f8025 docs: Add user guide for *Browse and join streams* feature. 2016-12-13 18:48:23 -08:00
Brock Whittaker
a3fcc6e026 Change groups of muted topics to be less translucent on hover.
On hover, the transparency of muted stream/topic groups should turn up
to 0.6 so that they are easily readable by people looking to find a
particular stream/topic, but not completely opaque as to be confused
with a non-muted item.

Fixes: #2487.
2016-12-13 14:24:56 -08:00
lonerz
8f97a811c4 interactive bots: Create Wikipedia bot. 2016-12-13 13:46:11 -08:00
Brock Whittaker
65288848b1 Fix Hiding Stream Creation Prompt on "Enter".
The stream creation prompt would be hidden if someone clicked “Enter”
and the form failed. This is presumably due to some bootstrap magic.
2016-12-13 13:16:51 -08:00
Tim Abbott
c77b1b2ac0 requirements: Stop using the -e feature for installing api bindings.
The `-e api/` line in requirements.txt caused various problems with
provisioning.  It's not entirely clearly why, but it seems likely to
be a bad interaction with our virtualenv caching logic.

Given that it only had marginal value over just installing the API
bindings in the first place, we're replacing this with just `api/`
instead.
2016-12-13 11:53:55 -08:00
Bickio
868f343980 Do not open compose box if user sidebar search is empty.
Fixes #2357.
2016-12-13 11:04:08 -08:00
reallyly
94b28e0afb pep8: Fix E128 violations.
With some line-wrapping tweaks by tabbott.
2016-12-13 10:50:14 -08:00
Igor Tokarev
fae59502ab URL preview: Improve test coverage. 2016-12-13 10:43:02 -08:00
Steve Howell
bb43c4d4c9 Remove select-default-language.png.
This accidentally got committed on the prior commit. It is
not used anywhere.
2016-12-12 12:55:52 -08:00
Cynthia Lin
c0f87481c6 docs: Add user guide for *Message display settings* feature 2016-12-12 12:43:45 -08:00
Tim Abbott
441c92e42f travis: Remove postgres-9.6 from production suite as well. 2016-12-12 10:12:08 -08:00
Zach Breit
3368b90f34 docs: Add user guide for 'Changing the Default Language' 2016-12-12 09:29:58 -08:00
Steve Howell
a119719b79 Make provision messaging more explicit.
Say "do this" when we want users to run `./tools/provision.py`.
2016-12-10 08:57:41 -08:00
Rafid Aslam
e0d2839dd7 docs: Fix broken link in git-guide.md
Update 'how to resolve a merge conflict' link because it is
broken, GitHub has change the link to the newer one.
2016-12-10 06:09:46 -08:00
Juan Verhook
9869fb8d87 Add UserPresence rows to test databases.
Fixes: #2426

mypy: Added annotations to populate_db.py
2016-12-09 15:41:21 -08:00
Cynthia Lin
78a0d9456e docs: Add user guide for *Keyboard shortcuts* feature 2016-12-09 15:37:49 -08:00
Adarsh S
31be2534b3 Fix Error: templates have no tests! while running TemplateTestCase.
We need to test all the templates only when we are running the full
 test suite. While running just the Test Class we need not check all
 the templates.
2016-12-09 12:09:55 -08:00
Brock Whittaker
1886f0a015 redesign: Convert subscriptions page to overlay.
This is a major change to the /#subscriptions page, converting it to
by a side-by-side list of streams and their settings in an overlay.
There are no new features added/removed, but it's a huge changeset,
because it replaces the old navigation logic and moves the stream
creation modal to appear in the right side of this overlay.
2016-12-09 11:08:08 -08:00
Jason Le
67f28fe62d Speed up rate limiting test in test_external.
Patches out the `time.sleep` and mocks the `time.time` to one second
ahead.

Resolves #2239.
2016-12-09 10:52:11 -08:00
Zac Pullar-Strecker
4eb6adf547 mypy: Annotate zerver/tests/test_narrow.py 2016-12-09 05:48:22 -08:00
Cynthia Lin
eb35d53ed1 docs: Add user guide for *Zulip glossary* 2016-12-09 05:07:57 -08:00
Brock Whittaker
9823e4de33 components: Change label.checkbox style.
Change the label.checkbox style to be grey instead of green which I
think blends with the current aesthetic more.
2016-12-08 11:49:45 -08:00
Tim Abbott
d2d404afcc travis: Remove npm cache in prod installation.
With this change in place, we would have been able to catch the bug
fixed in the last commit in CI.
2016-12-08 10:34:09 -08:00
Tim Abbott
95a49f6ea2 node_cache: Fix buggy production deployment code.
The previous version of the production deployment code for release
tarballs did not correctly install the node_modules directory.
2016-12-08 10:34:04 -08:00
Tim Abbott
8b77889f8a test-all: Run the pep8 linter by default. 2016-12-07 23:22:59 -08:00
Tim Abbott
ff71559bdf register: Only display full URL when subdomains is enabled. 2016-12-07 23:21:45 -08:00
Brock Whittaker
faddd3b1e0 register: Move help box out of inline'd block.
Now it will be full width again (display is block).
2016-12-07 23:19:20 -08:00
Arpith Siromoney
226e3cbf02 Reactions backend: make endpoints more REST-ful.
Adding a reaction is now a PUT request to
/messages/<message_id>/emoji_reactions/<emoji_name>

Similarly, removing a reaction is now a DELETE request to
/messages/<message_id>/emoji_reactions/<emoji_name>

This commit changes the url and updates the views and tests.

This commit also adds a test for invalid emoji when removing reaction.
2016-12-07 22:28:02 -08:00
Igor Tokarev
0bac986f26 Fixed compose box PM recipient typeahead handling of focus.
This closes #2315.
2016-12-07 22:13:47 -08:00
Tomonori Murakami
a9e409a50f admin: Do not allow removing or deactivating the last org admin.
Modified by tabbott to cover and test some additional cases.

Fixes #2396.
2016-12-07 21:59:33 -08:00
Tommy Ip
fe4a0e72fc Add new button to download ~/.zuliprc from settings page.
Added new option to download .zuliprc file directly from settings
page.  This should help reduce friction when setting up new
bots/integrations. This new feature is available in the bot cards and
the 'show your API key' section. One caveat is that the filename is
automatically set to 'zuliprc' instead of '.zuliprc', since as most
browsers do not allow filenames to start with a dot.

Fixes #2327.
2016-12-07 21:28:41 -08:00
Tomasz Kolek
9933abf833 css: Fix problem with too long stream name on stream deletion modal.
Add overflow-wrap rule to zulip.css for deactivation_stream_modal h3.

Fixes: #2596.
2016-12-07 21:23:23 -08:00
Tomasz Kolek
4fe3cd98f8 css: Fix problem with too long stream name in left sidebar.
Add overflow-wrap rule for .stream-name class to left-sidebar.css.
2016-12-07 21:21:47 -08:00
Tomasz Kolek
eac002c6bd css: Fix problem with too long stream error formatting.
Add overflow-wrap rule for #response span to subscriptions.css.
2016-12-07 21:20:57 -08:00
Vamshi Balanaga
9fd375c249 integrations: Add documentation for mention 2016-12-07 21:19:03 -08:00
Joy Chen
bfb6ac5fdb streams: Add default stream description tests and functions.
This includes making the default stream description setting into a
dict.  That is an API change; we'll discuss it in the changelog but it
seems small enough to be OK.

With some small tweaks by tabbott to remove unnecessary backwards
compatibility code for the settings.

Fixes #2427.
2016-12-07 21:12:44 -08:00
Joy Chen
dd95a5e03f streams: Add default stream description population data. 2016-12-07 21:02:17 -08:00
anirudhjain75
beaa62cafa mypy: Convert several directories to use typing.Text.
Specifically, these directories are converted: [analytics/, scripts/,
tools/, zerver/management/, zilencer/, zproject/]
2016-12-07 20:51:05 -08:00
Niels Terwiesch
2288120155 docs: Add user guide for emoji 2016-12-07 20:48:39 -08:00
Tim Abbott
0855cf29f7 settings: Move INLINE_URL_EMBED_PREVIEW. 2016-12-07 20:48:19 -08:00
Igor Tokarev
c93f1d4eda Add oembed/Open Graph/Meta tags data retrieval from inline links.
This change adds support for displaying inline open graph previews for
links posted into Zulip.

It is designed to interact correctly with message editing.

This adds the new settings.INLINE_URL_EMBED_PREVIEW setting to control
whether this feature is enabled.

By default, this setting is currently disabled, so that we can burn it
in for a bit before it impacts users more broadly.

Eventually, we may want to make this manageable via a (set of?)
per-realm settings.  E.g. I can imagine a realm wanting to be able to
enable/disable it for certain URLs.
2016-12-07 17:40:18 -08:00
Tim Abbott
b68fef8933 actions: Extract update_to_dict_cache. 2016-12-07 17:26:16 -08:00
Tim Abbott
90f76c079d lint: Require space after headings in markdown. 2016-12-07 17:15:53 -08:00
Tim Abbott
279d160f99 lint-all: Fix markdown_whitespace_rules indentation. 2016-12-07 17:15:47 -08:00
Robert Hönig
b44c4680ff docs: Add user guide for *Search for messages*. 2016-12-07 17:12:34 -08:00
Rafid Aslam
7856217a63 Migrate JS modules to CommonJS style.
Closes #1488.
2016-12-07 16:11:52 -08:00
anirudhjain75
4bb6735e77 Annotate zephyr_mirror_backend.py.
With some tweaks by tabbott to update tuple->Tuple and update comments.
2016-12-07 15:57:55 -08:00
Brock Whittaker
83ca1ab149 register: Make /register responsive again.
After some tremendous changes the container now shouldn’t break badly
on narrow screens as flexbox doesn’t set it off the screen.
2016-12-07 15:33:57 -08:00
Juanvulcano
2e5eb74eec help: Create name-change.md. 2016-12-07 12:27:24 -08:00
actuallyatoaster
25ed6876be docs: Add user guide for changing password. 2016-12-07 11:59:54 -08:00
Rafid Aslam
b621817194 test_public_urls: Automate test files (in templates/zerver/help/).
This automates including of markdown files under
`templates/zerver/help/` to be tested by `test_public_urls` (in
zerver/tests/test_signup.py).

Fixes #2465.
2016-12-07 11:25:22 -08:00
Rafid Aslam
0fbbadd303 docs: Extract testing docs to their own TOC section
Fixes: #2422.
2016-12-07 07:49:20 -08:00
Sampriti Panda
a9e2de09da integrations: Add documentation for heroku 2016-12-07 05:39:45 -08:00
Yago González
e65c42cb5f eslint: Turn on errors for new-cap rule.
Now the eslint rule "new-cap" is set as: ["error", { "newIsCap": true, "capIsNew": false }]
2016-12-07 05:33:16 -08:00
1Niels
aad53443b5 docs: Add user guide for Edit Your Profile. 2016-12-06 18:19:53 -08:00
Robert Hönig
ce2671c5cf eslint: Apply no-useless-escape rule to casper tests. 2016-12-06 18:06:57 -08:00
Rafid Aslam
ce94fb2eb1 deps: Change zxcvbn download method from download-zxcvbn to npm.
- Replace download-zxcvbn with downloading it from npm.
- Change zxcvbn.js path to node_modules (because npm put it to
`node_modules` directory.
- Bump `PROVISION_VERSION` in `version.py` to 2.4.

Fixes #2423.
2016-12-06 17:54:56 -08:00
Rafid Aslam
0951b838ca deps: Update zxcvbn to 4.4.1
Update zxcvbn to 4.4.1, and change `crack_time` to
`crack_times_seconds` because `crack_time` has been changed to
`crack_times_seconds` in 4.4.1.
2016-12-06 17:51:33 -08:00
actuallyatoaster
d11cdac876 docs: Add documentation for linking to a stream.
Fixes #2560.
2016-12-06 17:47:26 -08:00
Tim Abbott
b8ec9a5a42 docs: Improve installation instruction headings.
The previous RTD headings were unclear and resulted in some users
attempting to install the Zulip production environment for doing
development.  This clarifies the situation.
2016-12-06 17:36:42 -08:00
Sampriti Panda
7c3aff92d9 integrations: Add webhook payloads, webhook code, API endpoint, and tests for heroku 2016-12-06 11:05:00 -08:00
Tudor Nazarie
5b22959f1c Annotate bots/jabber_mirror_backend.py 2016-12-06 09:52:08 -08:00
root
20a55ea6e0 integrations: Add webhook payloads for appfollow. 2016-12-05 23:48:00 -08:00
Zac Pullar-Strecker
e6e11aefb3 settings: Add option to disable websockets.
This can be useful in scenarios where the network doesn't support
websockets.  We don't include it in prod_settings_template.py since
it's a very rare setting to need.

Fixes #1528.
2016-12-05 21:55:22 -08:00
Bickio
84765e48a9 integrations: Add webhook code, API endpoint, and tests for papertrail 2016-12-05 21:48:11 -08:00
K.Kanakhin
7bf10ec74f update-sockjs: Update sockjs from version 0.3.4 to 1.1.1.
- Add browserify to npm dependencies.
- Add SockJS-client to npm dependencies.
- Add npm postinstall script to generate browser version of SockJS-client
  from npm package.
- Change deprecated SockJS object property 'protocol_whitelist' to
  'transports'.
- Fix settings.
2016-12-05 21:36:10 -08:00
Cynthia Lin
aa7f11dd6c docs: Add user guide for *Streams and Private Messages* 2016-12-05 21:22:37 -08:00
lonerz
abde152d9c eslint: change array-callback-return from warning to error. 2016-12-05 21:21:19 -08:00
Mikebarson
690d72d35f mypy: Convert more zerver/lib files to typing.Text.
This commit touches files in zerver/lib/bugdown/ and
zerver/lib/webhooks.
2016-12-05 21:17:24 -08:00
Maydha K
c51d2c3d8f docs: Add user guide for signing out 2016-12-05 16:59:18 -08:00
Vamshi Balanaga
f89e732d9e integrations: Add webhook code, API endpoint, and tests for mention. 2016-12-05 16:46:32 -08:00
sidhant bhavnani
4634c3d656 Change call signature for users_subscribed_to_stream()
The function users_subscribed_to_stream() now takes realm now, instead of domain.
2016-12-05 15:46:19 -08:00
Tim Abbott
fb3a6eead0 .eslintrc.json: Convert tabs to spaces. 2016-12-05 10:02:19 -08:00
Arpith Siromoney
6ae613c235 Eslint: Add additioanl rules, some for GCI.
This commit adds rules for GCI, turns on rules that do not error
on our codebase, and changes frontend_tests/.eslintrc.json's no-sync
rule to off (as per AirBnB's style guide).

Rules for GCI:
no-restricted-syntax, no-nested-ternary, spaced-comment,
space-infix-ops, newline-per-chained-call, padded-blocks,
no-whitespace-before-property, space-in-parens

Rules that do not error:
no-useless-constructor, no-dupe-class-members, no-duplicate-imports,
no-iterator, no-undef, dot-notation, no-case-declarations, no-unneeded-ternary,
eol-last,

Finally, eqeqeq is changed from 2 to ['error', 'allow-null'], going
from jslint defaults to airbnb's recommendation (there were no errors)
2016-12-05 10:01:56 -08:00
lonerz
dc6849952b eslint: change space-before-function-paren from warning to error.
Also fix violations.
2016-12-05 09:50:37 -08:00
Cynthia Lin
f354892ba4 docs: Add user guide for *Create a stream* 2016-12-05 05:48:13 -08:00
lonerz
a8b39e6c0f Switch yoda eslint rule from warning to error (in .eslintrc) 2016-12-04 19:48:10 -08:00
lonerz
025fe9980b Switch no-empty eslint rule from warning to error (in .eslintrc) 2016-12-05 01:35:14 +00:00
bulat22101
9f68efa47b mypy: Convert zerver/tests/ to use typing.Text. 2016-12-04 14:47:21 -08:00
Jianchun1
88e2ff3e1c docs: Add chinese translation style guide. 2016-12-04 14:36:04 -08:00
Noel Tautges
07a74a8d9c mypy: Convert zerver/views/webhooks/ to use typing.Text. 2016-12-04 11:45:46 -06:00
Arpith Siromoney
cfa2987d27 Eslint: add rules that do not error 2016-12-04 08:34:59 -08:00
Tim Abbott
15bfedec99 travis: Improve debuggability of server wget failures.
The main improvement here is causing `wget` errors to be ignored so
that we see the server logs in the event of a `wget` failure.
2016-12-03 20:48:57 -08:00
Cynthia Lin
dd62123d4b docs: Add user guide for *Format Your Messages*. 2016-12-03 20:44:01 -08:00
AZtheAsian
441743cb89 integrations: Add webhook code, API endpoint, and tests for stripe.
This integration still needs documentation.
2016-12-03 20:42:43 -08:00
Rafid Aslam
0290aeb6ab lint: Fix several no-unused-vars eslint rule violations.
These changes were extracted by tabbott from the original commit
to merge now because they have been reviewed as safe.
2016-12-03 18:43:47 -08:00
Rafid Aslam
426cb13e23 Remove enforce_arity function from util.js.
Remove `enforce_arity` function from util.js, because it is
not used anymore.
2016-12-03 18:43:46 -08:00
anirudhjain75
3b891ef080 integrations: Add webhook payloads for mention. 2016-12-03 18:04:22 -08:00
Tim Abbott
abc581898f eslint: Add components.js module to globals list. 2016-12-03 18:02:47 -08:00
Tim Abbott
d5dd7a27d5 Remove tools/deprecated/inject-messages. 2016-12-03 16:58:17 -08:00
Tim Abbott
1a161c6e33 eslint: Fix comma-dangle rules in JS support files.
This was done via eslint --fix.
2016-12-03 15:00:24 -08:00
Tim Abbott
2447f4a5b4 eslint: Update most casper tests to use new comma-dangle rules.
* In most cases, eslint --fix with the right comma-dangle settings was
  able to update the code correctly.

* The exceptions were cases where the parser incorrectly treated the
arguments to functions as lists/objects and added commas; these are
detectable with linters, and we fixed manually.  Since this is test
code, we can be reasonably confident that just fixing the failures
suffices to correct any bugs introduced by making changes
automatically.
2016-12-03 15:00:24 -08:00
Tim Abbott
459421d045 eslint: Update node tests to use new comma-dangle rules.
* In most cases, eslint --fix with the right comma-dangle settings was
  able to update the code correctly.

* The exceptions were cases where the parser incorrectly treated the
  arguments to functions like `assert_equal` as arguments; we fixed
  these manually.  Since this is test code, we can be reasonably
  confident that just fixing the failures suffices to correct any bugs
  introduced by making changes automatically.
2016-12-03 15:00:24 -08:00
Joy Chen
77938f6247 mypy: Annotate *bots/githook-post-receive* 2016-12-03 15:58:22 -06:00
Joy Chen
97a9fea89d delete check_output backport: Python 2.6 no longer supported 2016-12-03 15:57:20 -06:00
Reid Barton
ecfa397567 Fix several type annotations for mypy 0.4.6 compatibility.
A few functions had arguments removed without having their type
annotations updated accordingly. As a result mypy version 0.4.6
thinks that the first type in the annotation is supposed to be
the type of `self`, a new mypy feature which we are not intending
to use here.
2016-12-03 13:45:52 -08:00
nikolay
abc2ff4a06 pep8: Fix many rule E128 violations.
[Tweaked by tabbott to adjust some approaches used in wrapping]
2016-12-03 13:33:31 -08:00
Jason Le
144d82305d mypy: Annotate puppet/zulip_ops. 2016-12-03 11:00:25 -08:00
bulat22101
a6f91064a2 pep8: Fix E129 violations 2016-12-03 10:56:36 -08:00
bulat22101
adebc75740 pep8: Fix E502 violations 2016-12-03 10:56:36 -08:00
Rafid Aslam
e6fa4bc2fd tests: Change doc file in run-casper 'Tips for debugging'.
Change `docs/testing.rst` to `docs/testing-with-casper.md` in
'Tips for debugging' because there is no `testing.rst` file, and
remote debugging description is placed in `testing-with-casper.md`.
2016-12-03 10:45:44 -08:00
anirudhjain75
a697261e74 integrations: Add webhook payloads for papertrail. 2016-12-03 10:28:49 -08:00
Robert Hönig
5ba3e214da Add user guide for *Editing past messages*. 2016-12-03 14:20:06 +00:00
Bickio
7bf3ac7e90 integrations: Add webhook payloads for Stripe. 2016-12-02 20:05:37 -08:00
Tim Abbott
8259adaba5 lint: Add custom lint check for console.log statements.
This was previously checked for by jslint, and eslint doesn't seem to
have a nice exclude rule for it.
2016-12-02 20:05:18 -08:00
kevv87
1fb9220354 lint: Remove old jslint linter.
Now that we're using eslint, jslint is no longer required.
2016-12-02 18:49:42 -08:00
Tim Abbott
2c940b93ab js: Fix some minor whitespace issues. 2016-12-02 18:39:30 -08:00
AZtheAsian
5e9918135b eslint: change quote-props from off to error and fix violations. 2016-12-02 18:35:53 -08:00
Juan Verhook
1923045ca6 Annotate api/zulip/__init__.py.
Note that we still can't run mypy against this file and other files,
because of how the interface is dynamically created via _register.  We
will need to change that or use a stub file to make it possible to
annotate this.

This was tweaked by tabbott to fix some bugs.
2016-12-02 18:26:47 -08:00
Krzysztof Zbudniewek
b8fc3f0e65 eslint: change space-before-blocks from warning to error and fix violations 2016-12-02 17:40:09 -08:00
Arpith Siromoney
4491ea8d6b reactions: Add support for removing emoji reactions.
This commit adds support for removing reactions via DELETE requests to
the /reactions endpoint with parameters emoji_name and message_id.

The reaction is deleted from the database and a reaction event is sent
out with 'op' set to 'remove'.

Tests are added to check:
1. Removing a reaction that does not exist fails
2. When removing a reaction, the event payload and users are correct
2016-12-02 16:39:53 -08:00
Sidhant Bhavnani
8c0c12c1d9 pep8: Fix E303 violations. 2016-12-02 15:34:11 -08:00
Brock Whittaker
9f0383520c settings: Fix Zulip Labs Spacing Issue.
This fixes the spacing issue with Zulip Labs not having a space between
the icon.
2016-12-02 14:49:05 -08:00
AZtheAsian
9c0ebc7359 eslint: change no-else-return to error and fix violations 2016-12-02 14:43:09 -08:00
Brock Whittaker
d8636980ae settings: Convert bot and alert word settings to use new buttons. 2016-12-02 13:03:43 -08:00
Tim Abbott
d184288e00 css: Add box-shadow and bg-white components. 2016-12-02 13:03:43 -08:00
Tim Abbott
6e86515b15 css: Move display-none and inline-block to components.css. 2016-12-02 13:03:43 -08:00
Tim Abbott
a7681c3c2f css: Move .light to components.css. 2016-12-02 13:03:43 -08:00
Tim Abbott
b61d6bc251 settings: Use new checkboxes and buttons in display settings. 2016-12-02 13:03:40 -08:00
Tim Abbott
e13a892479 settings: Remove unnecessary outer div from display settings. 2016-12-02 13:03:35 -08:00
Tim Abbott
85d6fdda4d settings: Use new checkboxes and buttons in UI settings. 2016-12-02 13:03:32 -08:00
Brock Whittaker
51fbe4395d settings: Use new checkboxes and buttons in notification settings. 2016-12-02 13:03:23 -08:00
Brock Whittaker
7fd15984fc components: Add a new settings page checkbox.
This allows us to style checkboxes to be transparent boxes with green
borders.
2016-12-02 12:06:49 -08:00
Brock Whittaker
0e3332d86e [Bootstrap]: Fix Null Case Issue.
This fixes the case in which `this` evaluates as null and throws an
error in TravisCI.
2016-12-02 11:58:53 -08:00
Brock Whittaker
2aa9512506 Add data-name to realm filter settings section.
This new settings section, was added into master but doesn't have the
correct data-name attribute to be called by the new modal.
2016-12-02 11:56:24 -08:00
AZtheAsian
ed0bc831be eslint: change one-var from warning to error and fix violations 2016-12-02 11:25:16 -07:00
Tommy Ip
b3f4feb996 eslint: change max-len from warning to error and fix violations. 2016-12-02 14:16:33 +00:00
Alex Huang
007b693cc7 pep8: Fix E131. 2016-12-01 23:16:47 -08:00
Alex Huang
c8ddea16c3 pep8: Fix E122. 2016-12-01 23:16:35 -08:00
AZtheAsian
62494eeb97 pep8: fix E201 violations 2016-12-01 23:06:02 -08:00
AZtheAsian
7e14fe65ab pep8: fix E202 violations 2016-12-01 23:06:02 -08:00
Michael Nguyen
991c84fa1e dev-setup-non-vagrant.md: Add missing install step. 2016-12-01 23:05:18 -08:00
AZtheAsian
1ba150fa85 pep8: Fix E203 violations 2016-12-01 20:37:57 -08:00
kevv87
e6369fc29b eslint: change no-plusplus from warning to 2 and fix violations. 2016-12-01 14:27:17 -08:00
Tommy Ip
c90da24541 eslint: change keyword-spacing from warning to error and fix violations. 2016-12-01 14:22:15 -08:00
Tim Abbott
aab5ca620e tests: Improve some close paren formatting. 2016-12-01 14:18:11 -08:00
AZtheAsian
c23f9e0df7 pep8: Fix E111 violations 2016-12-01 14:18:11 -08:00
AZtheAsian
f7582f0050 pep8: Fix E124 violations 2016-12-01 14:18:11 -08:00
Tim Abbott
1a8a329b44 production-helper: Expand the apt-mark hold list. 2016-12-01 12:29:31 -08:00
Tim Abbott
87879c3916 travis: Workaround broken Travis CI java configuration.
Travis CI seems to have broken /usr/bin/java in a recent
infrastructure change.
2016-12-01 11:46:21 -08:00
Tim Abbott
0ac78ca454 setup-production: Fix path to update-prod-static.log.
This regressed in 55f2c49bbf.
2016-12-01 11:15:20 -08:00
aakash-cr7
d99b17070e edit: Fix traceback when saving edits to unsent messages.
7b0c6459b4 accidentally failed to update
one of the calleers of update_private_messages, resulting in this code
path failing consistently.

Fixes #2416.
2016-12-01 10:39:43 -08:00
Rafid Aslam
c5316b4002 lint: Fix E127 pep8 violations.
Fix pep8: E127 continuation line over-indented for visual indent
style issue.
2016-12-01 10:23:55 -08:00
Tommy Ip
7b2c313f37 eslint: change brace-style from warning to error and fix violations. 2016-12-01 10:20:22 -08:00
Tim Abbott
fd81cc1d93 test-backend: Clarify missing template tests error message. 2016-12-01 10:12:38 -08:00
Tim Abbott
f8f017c221 test_runner: Fix template rendering test.
The previous logic would allow the same template to be added to both
the shallow_tested list and the normal list.
2016-12-01 10:12:38 -08:00
Tim Abbott
5e0d2c4e1b tests: Exclude markdown files from shallow template testing.
The markdown files under templates/zerver/help/ are technically not
templates in the standard sense, and thus should not be being
checked with this code path.

(We probably do want to add a test to make sure they all render fine,
but that can be its own project.)
2016-12-01 10:12:38 -08:00
Joy Chen
2784a3e27f docs: Add user guide for Uploading and Sharing Files. 2016-11-30 22:30:56 -08:00
Vamshi Balanaga
5f60258a85 pep8: Fix E211 violations. 2016-11-30 20:13:10 -08:00
Bickio
6b0df43463 pep8: Fix E125. 2016-11-30 20:03:29 -08:00
Bickio
e009383460 pep8: Fix E231. 2016-11-30 19:59:25 -08:00
AZtheAsian
3c0ea4da6f docs: Add user guide for *mention a team member*. 2016-11-30 19:41:49 -08:00
Tim Abbott
995a692f7f provision: Check whether the system has at least 2GB of RAM.
Fixes #2336.
2016-11-30 16:07:57 -08:00
Tim Abbott
fd7cb10964 install: Check whether the system has at least 2GB RAM.
This should eliminate a common class of user error installing Zulip.

Fixes #2290, fixes #2320.
2016-11-30 16:07:57 -08:00
Tim Abbott
e73ee5a4c4 test-backend: Fix count for templates without tests. 2016-11-30 15:38:19 -08:00
Tommy Ip
e4091c6413 pep8: Fix E222 violations. 2016-11-30 21:49:02 +00:00
Tommy Ip
46b7d54b3e pep8: Fix E701 violations. 2016-11-30 20:45:09 +00:00
Heidi Dong
ba7d4e7452 mypy: Annotate bots/gcal-bot. 2016-11-29 20:49:11 -08:00
trueskawka
558d359909 translation: Create Polish translation style guide.
Add general notes on Polish translation.
Translate special terms used in Zulip.
2016-11-29 19:36:57 -08:00
Tim Abbott
ce2cc6d869 docs: Link Spanish style guide from translating page. 2016-11-29 19:35:23 -08:00
Carlos Rey
98e731e4c0 docs: Create a translation guide for Spanish. 2016-11-29 19:31:29 -08:00
Igor Tokarev
e6ae53cbff install: Add clear error message if upstart is installed on Xenial.
Fixes #2199.
2016-11-29 19:16:26 -08:00
Tim Abbott
24f0029111 integration-guide: Fix 'webhook' typo.
Fixes #2467.
2016-11-29 19:08:21 -08:00
Anders Kaseorg
6549dfd1d0 build-release-tarball: Add --py3 option for python3 shebang lines.
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2016-11-29 17:45:18 -08:00
Brock Whittaker
4935f0c693 popovers: Hide actions popover once the muting button is clicked.
The popover shouldn’t still display once a valid action on the popover
has been taken.

Fixes #2366.
2016-11-29 16:47:03 -08:00
Tim Abbott
e6ebffefa0 test_helpers: Cleanup output a bit. 2016-11-29 16:40:05 -08:00
Tim Abbott
4f6a075331 test-backend: Fix missing output for untested templates.
Our enforcement logic for untested templates unfortunately did not
give a clear error message unless you passed the --verbose option.
2016-11-29 16:38:18 -08:00
Brock Whittaker
b837221e05 Fix for possible webkit painting bug.
The left sidebar will overflow its bounds (even when set to overflow:
hidden) and go behind other text on the sidebar above. By setting the
z-index to 0 we seem to solve the problem.

This is probably actually a webkit bug, but this makes it no longer
affect us.

Fixes #1899.
2016-11-29 15:29:59 -08:00
Tim Abbott
b1fce36214 docs: Fix a link to the windows-10 instructions. 2016-11-29 15:26:23 -08:00
Tim Abbott
b035a6c606 docs: Change dev -> development everywhere. 2016-11-29 14:23:54 -08:00
Tim Abbott
6512d588ae dev-remote: Clean up some text, mostly dev->development. 2016-11-29 14:16:51 -08:00
Christie Koehler
30c6d9692e docs: Update remote dev with better details about editing. 2016-11-29 14:13:21 -08:00
Christie Koehler
e81474cd91 docs: Recommend using Git to sync changes from local to remote dev. 2016-11-29 14:13:21 -08:00
Christie Koehler
641599164d docs: Add instructions for enabling symlinks in Git BASH. 2016-11-29 14:13:21 -08:00
Christie Koehler
23cf8697d1 docs: Update Windows setup to use Git BASH instead of Cygwin. 2016-11-29 14:13:21 -08:00
Christie Koehler
03d5d5d23a docs: Minor clarifications to remote dev tips. 2016-11-29 14:13:21 -08:00
Christie Koehler
dfc465c9a2 docs: Make 'next steps' correct heading level and update links. 2016-11-29 14:13:21 -08:00
Christie Koehler
cbd3774745 docs: Update zulip path to ~/zulip/ 2016-11-29 14:13:21 -08:00
Christie Koehler
01d6d7791d docs: Update to address first-time provision issues. 2016-11-29 14:13:21 -08:00
Christie Koehler
6def9c44dc Minor clean up of developing remotely guide. 2016-11-29 14:13:21 -08:00
Christie Koehler
3913db9022 docs: Simplify hierarchy of dev setup docs.
Based on feedback from first-time contributors, this commit simplifies
the number of paths available for finding the dev setup directions you
need. Setup instructions are now organized into Recommended (Vagrant)
and Advanced (non-Vagrant).

In order to get the ToC to display correctly, I've combined all the
advanced, non-Vagrant methods into one page. I've left the old pages
intact, with a note that the content has been moved and link to the new
page. This is in case folks have linked directly to those pages.

The advanced setup directions still need to be cleaned up, but this is a
start.
2016-11-29 14:13:09 -08:00
Tim Abbott
07565c4a3e Revert "Fix race conditions in Admin casper tests."
This reverts commit aa5a7bc659.
2016-11-29 09:50:56 -08:00
Tommy Ip
844e32ccc5 tools: Remove deprecated generate-activity-metrics.py.
The script uses hardcoded hostnames that do not exist anymore,
its functionality is available through directly querying the Zulip
database.
2016-11-29 09:27:59 -08:00
Tim Abbott
ff03ad40d2 .eslintrc: Replace spaces with tabs. 2016-11-29 08:59:32 -08:00
Arpith Siromoney
f7dc2f33cd Change name of eslintrc file to .eslintrc.json
Currently it does this for the eslintrc files in zulip,
zulip/frontend_tests and static/js

This commit also fixes json style issues (quotes)
2016-11-29 08:58:39 -08:00
Umair Khan
cd19a3d870 docs: Fix manual installation instructions.
The previous version didn't correctly handle permissions around the
virtualenvs.
2016-11-29 08:56:20 -08:00
Umair Khan
aa5a7bc659 Fix race conditions in Admin casper tests. 2016-11-29 08:53:27 -08:00
Rafid Aslam
41bd88d5ed pep8: Fix E301 pep8 violations.
Fix "E301: expected (1 or 2) blank line" pep8 violations.
2016-11-29 08:51:44 -08:00
Rafid Aslam
7a2282986a pep8: Fix E225 pep8 violations. 2016-11-28 15:21:15 -08:00
Christie Koehler
f036a59b4f Move details about configuring a proxy. 2016-11-27 17:06:41 -08:00
Christie Koehler
8b67210ce5 Simplify dev env setup overview. 2016-11-27 16:58:19 -08:00
sylvan1
443cf92640 mypy: Change Generator[None, None, None] to Iterator[None].
Fixes #1648.
2016-11-27 10:42:16 -08:00
Stanley Zheng
b162969841 docker: Revert Docker development to original instructions.
There were issues with reproducing the Docker build with the latest
docker file and instructions.
2016-11-27 10:15:37 -08:00
Calvin Lee
5c262d3557 tests: Add tests for creating a new stream with a description
Modify backend test of create_streams_if_needed so that the newly
created streams have descriptions.

Modify casperjs test of filling out stream_creation_form so that
the newly created stream has a description.

Fixes: #2428.
2016-11-27 09:45:38 -08:00
Arpith Siromoney
e2270f5499 Tighten eslint rules with zero errors to airbnb values.
block-scoped-vars, guard-for-in, radix and valid-typeof are eslint
rules that were set to warning in the eslintrc. Since there
are no errors, they have been toggled to the appropriate values
from the airbnb style guide.
2016-11-27 08:12:35 -08:00
Umair Khan
287eb2cd49 provisioning: Add version warning for Vagrant 1.8.7.
Vagrant 1.8.7 is not supported due to broken curl, see
https://github.com/mitchellh/vagrant/issues/7997 for reference.
2016-11-26 23:08:43 -08:00
Tim Abbott
3d1bcb05e1 tornado: Move event_queue.py to zerver/tornado/.
Fixes #729.
2016-11-26 22:29:28 -08:00
Tim Abbott
1fcf2ff525 tornado: Move zerver.tornadoviews to zerver.tornado.views.
This furthers the overall goal of moving all the Tornado-specific code
to zerver/tornado/.
2016-11-26 22:29:28 -08:00
Tim Abbott
169d404579 tornado: Move zerver.lib.handlers into zerver.tornado.handlers.
This cleans up the confusingly duplicated file names, while also
moving more of the Tornado-specific code under zerver/tornado/.
2016-11-26 22:29:28 -08:00
Tim Abbott
d75f49b119 tornado: Move descriptor dict management code to handlers.py. 2016-11-26 22:29:28 -08:00
Tim Abbott
282f74609c tornado: Move socket code to zerver/tornado/. 2016-11-26 22:29:27 -08:00
K.Kanakhin
050768643d tornado: Add tests for sending messages with websockets.
- Add base tornado test case class.
- Add test for websocket connection.
- Add test for websocket authentication.
- Add test for sending private message with websocket.
- Add test for sending stream message with websocket.

Fixes #2230
2016-11-26 22:29:26 -08:00
Tim Abbott
f2782971e0 tornado: Clean up AsyncDjangoHandler Python style. 2016-11-26 22:05:04 -08:00
Tim Abbott
b83361bcfc tornado: Extract create_tornado_application helper. 2016-11-26 21:43:13 -08:00
Tim Abbott
9e9066f77a tornado: Extract AsyncDjangoHandler to its own file. 2016-11-26 21:43:11 -08:00
Tim Abbott
8739f4d9f1 tornado: Move tornado_ioloop_logging to new zerver/tornado tree. 2016-11-26 21:24:05 -08:00
Tim Abbott
6b42b12768 twitter-search-bot: Line-wrap very long lines. 2016-11-26 21:24:05 -08:00
Tomasz Kolek
b7dfcadf33 Document ZULIP SITE param in twitter bots. 2016-11-26 19:30:45 -08:00
Tomasz Kolek
9636d89de1 Add documentation for changing SITE param in jenkins configuration. 2016-11-26 19:30:45 -08:00
Tomasz Kolek
6d36eb00b6 integrations: Change default ZULIP_SITE to https://zulip.example.com.
Modified:
    asana
    basecamp
    codebase
    git
    jira
    svn
    trac
2016-11-26 19:30:32 -08:00
Tomasz Kolek
2c252de311 Add documentation for changing SITE param in perforce configuration. 2016-11-26 19:24:24 -08:00
Tim Abbott
a28b20b845 docs: Improve documentation around re-provisioning.
Fixes #1967.
2016-11-26 19:21:18 -08:00
Tim Abbott
eea59c1c9c docs: Add RTD link badge. 2016-11-26 19:10:39 -08:00
Tim Abbott
4f98b73d5e requirements: Document anti-recommendation of t2 style instances.
If your instance runs out of CPU credits, it will result in a nasty
outage.

Fixes #1605.
2016-11-26 19:06:45 -08:00
Anders Kaseorg
78d6c3d7e9 install: Fix RabbitMQ node name if RabbitMQ is not installed.
This indirectly causes the RabbitMQ node name for new Zulip
installations to default to zulip@localhost, which would eliminate the
persistent problems we have had

Fixes #194, #465, #1375, #1751.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2016-11-26 18:54:29 -08:00
Anders Kaseorg
092fe4fecb puppet: Write rabbitmq-env.conf before installing rabbitmq-server
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2016-11-26 18:54:12 -08:00
Tim Abbott
843ad8a947 models: Fix s/text_type/Text/ merge regression. 2016-11-26 18:46:31 -08:00
Michael Cordover
4047c7d3c4 docs: Add code of conduct. 2016-11-26 18:40:16 -08:00
Arpith Siromoney
001847ac5b Add backend support for emoji reactions.
This commit adds the following:

1. A reaction model that consists of a user, a message and an emoji that
are unique together (a user cannot react to a particular message more
than once with the same emoji)
2. A reaction event that looks like:
    {
        'type': 'reaction',
	'op': 'add',
	'message_id': 3,
	'emoji_name': 'doge',
	'user': {
	    'user_id': 1,
            'email': 'hamlet@zulip.com',
            'full_name': 'King Hamlet'
	}
    }
3. A new API endpoint, /reactions, that accepts POST requests to add a
reaction to a message
4. A migration to add the new model to the database
5. Tests that check that
   (a) Invalid requests cannot be made
   (b) The reaction event body contains all the info
   (c) The reaction event is sent to the appropriate users
   (d) Reacting more than once fails

It is still missing important features like removing emoji and
fetching them alongside messages.
2016-11-26 18:10:21 -08:00
Tim Abbott
92d1b6d6da run-dev: Fix regression ignoring --interface argument.
When we migrated run-dev.py from Twisted to Tornado a few weeks ago,
the --interface argument wasn't properly ported and thus was ignored.

This restores the original functionality of defaulting to only
listening on localhost.

Ideally, we'd replace the vagrant/zulipdev user check with something
that just checks whether a special file that is created by the
Vagrant/remote-dev-vm creation process exists; that would be more
robust.
2016-11-26 17:23:31 -08:00
Calvin Lee
4e5c4c5ffb streams: Add support for setting stream description during creation.
Add new box for stream description in the stream creation form,
modify backend so its contents end up as the stream description.

Fixes: #2283.
2016-11-26 16:55:35 -08:00
Calvin Lee
b8d7f8008a streams: move the invite_only field into the stream_dict argument.
Refactor list_to_streams and create_streams_if_needed.  The
stream_dict now has a "invite_only" key, which is mapped to
a boolean.
2016-11-26 16:52:40 -08:00
Calvin Lee
8461cc411e streams: refactor stream creation code path.
Refactor list_to_streams and create_streams_if_needed to take a list
of dictionaries, instead of a list of stream names.  This is
preparation for being able to pass additional arguments into the
stream creation process.

An important note: This removes a set of validation code from the
start of add_subscriptions_backend; doing so is correct because
list_to_streams has that same validation code already.

[with some tweaks by tabbott for clarity]
2016-11-26 16:48:59 -08:00
Tim Abbott
308069d828 test_templates: Fix missing hubot_lozenges_dict. 2016-11-26 16:19:35 -08:00
Tomasz Kolek
a79acf854f docs: Automate creation of Hubot documentation lozenges.
This removes a bunch of semi-duplicated code.
2016-11-26 15:27:54 -08:00
Rishi Gupta
4b183cd526 domain migration: Remove several instances of get_realm.
Remove the easy to remove instances of get_realm.
2016-11-26 15:19:56 -08:00
Umair Khan
0536aeba4d Django 1.10: Use same cache prefix for JS tests.
Previously, the key prefix was based on the process id due to which
the JS tests couldn't properly flush user profiles from the cache as
our application spans over multiple processes. This problem becomes
apparent when in json_change_settings view after changing the user_profile
the tornado views continue to get the cached user profile corresponding
to their process id.
2016-11-26 15:10:50 -08:00
Umair Khan
ea688620b3 Django 1.10: Remove cleanupconfirmation management command.
According to this ece9d64d34 commit, the
confirmations are never deleted.
2016-11-26 15:04:20 -08:00
Umair Khan
671c45524b Django 1.10: Use new app discovery system.
'django.db.models.loading' is removed due to which both
'django.db.models.get_app' and 'django.db.models.get_models' are removed.

See https://docs.djangoproject.com/en/1.10/releases/1.9/#features-removed-in-1-9
2016-11-26 15:04:20 -08:00
Umair Khan
c8fa25ab88 Django 1.10: Update session hash when password is changed.
Ref: https://docs.djangoproject.com/en/1.10/topics/auth/default/#session-invalidation-on-password-change for details.
2016-11-26 15:04:17 -08:00
Umair Khan
92869940c6 Fix race conditions in user settings casper tests. 2016-11-26 14:56:15 -08:00
Calvin Lee
7a3ef2b0eb tests: Add assert_in_success_response in ZulipTestCase.
Clean up the instances of self.assertIn("string", result.content.decode("utf-8")),
and replace them with self.assert_in_response("string").

Fixes: #2313
2016-11-26 14:52:44 -08:00
Steve Howell
6ed1dc9341 Create api docs from url coverage data from tests.
I also retire tools/analyze-url-coverage in this commit,
since the API docs cover most of the functionality.
2016-11-26 14:49:23 -08:00
Zev Benjamin
f66e12ac4d docs: Minor developer documentation improvements.
Fixes #2424.
2016-11-26 14:47:16 -08:00
Anders Kaseorg
207cf6302b Always start python via shebang lines.
This is preparation for supporting using Python 3 in production.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2016-11-26 14:46:37 -08:00
Anders Kaseorg
2d6525df04 install: Install python3, python3-six
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2016-11-26 13:26:18 -08:00
Anders Kaseorg
1ea8abe493 Replace python -u with PYTHONUNBUFFERED=1
(Why is -u needed at all?  I’m not sure, but test-run-dev spins forever
“Polling run-dev...” without it.)

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2016-11-26 13:20:22 -08:00
Anders Kaseorg
573ec14955 Remove shebang line from non-scripts
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2016-11-26 13:20:22 -08:00
Anders Kaseorg
d1dc2cf30e Mark scripts executable
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2016-11-26 13:20:22 -08:00
Anders Kaseorg
70c977696d requirements: Upgrade flup to 1.0.3.dev20161029 for Python 3 support
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2016-11-26 13:20:22 -08:00
Anders Kaseorg
712c98cb48 Use zulip-py3-venv when running on Python 3
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2016-11-26 13:20:22 -08:00
Steve Howell
c0f2cebe0c docs: Add initial guide to manual testing.
With a few small tweaks by tabbott.
2016-11-26 13:05:25 -08:00
Arpith Siromoney
f0df1db9fb tools: Remove tools/node and call node directly instead.
Previously, we didn't install/pin our own node.js version, and thus
had this wrapper script to manage it.  Now that install our own node
via nvm, there's no reason we still need this.

Fixes #2409.
2016-11-26 12:42:58 -08:00
Tim Abbott
25c6b9f586 pre-commit: Call lint-all with --force. 2016-11-26 12:30:16 -08:00
Steve Howell
604079a9d4 Fix formatting for Group PMs in the right sidebar.
We now sort users by the lower case value of their
full names in each of the links in the "GROUP PMs"
section of the right sidebar.  We still use "+n others"
for big huddles.
2016-11-26 11:48:52 -08:00
Steve Howell
d953eca14c Make group PMs reply-to's more consistent in case.
We now sort lists of users ids deterministically, and we also
sort list of emails deterministically and without regard to case.

This probably fixes the bug #2343, although I never got a great
repro on that.
2016-11-26 11:48:52 -08:00
Steve Howell
578b276523 node tests: Add tests for message_store.js. 2016-11-26 11:48:52 -08:00
Steve Howell
af9ff9a030 Have unread.num_unread_for_person accept a user_id.
(It used to take an email as its parameter.)
2016-11-26 11:48:52 -08:00
Steve Howell
772571fd82 Use data-user-ids-string in Private Messages sidebar.
This commit also changed message_store.recent_private_messages
to use user_ids_string instead of reply_to.
2016-11-26 11:48:52 -08:00
Steve Howell
aadfe133e2 buddy list: Use user_ids in DOM list elements. 2016-11-26 11:48:52 -08:00
Steve Howell
78474c8bee Add test users with non-lowercase emails.
We are prone to case-sensitivity bugs, so I added AARON and ZOE.
Also, for good measure, I insert them in non-alphabetical order
to try to drive out bugs from non-consistent sorting of user ids.
2016-11-26 11:48:52 -08:00
Steve Howell
8110c3f799 tools: Check provisioning version in lint-all. 2016-11-26 11:36:53 -08:00
Arpith Siromoney
28cac02cb3 Increment provision number in version.py for eslint installation. 2016-11-26 11:36:22 -08:00
Anders Kaseorg
18e49bec3a puppet: Add another missing dependency on postgresql-common
The postgres group must exist before we give files to it.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
2016-11-26 11:23:32 -08:00
Stanley Zheng
26be74c72c docs: Add additional docker commands and documentation cleanup.
With some tweaks by tabbott to fix ordering issues.
2016-11-26 11:17:00 -08:00
Stanley Zheng
23d2b787fb Dockerfile: Simplify setup workflow for Docker development.
This improves the docker cmds so that user does not have to remote
into the container to have service startup.
2016-11-26 11:09:23 -08:00
inytar
5ad831fdf0 Make sure Vagrant works with SELinux enabled
Remount SELinux filesystem if host is running SELinux.
2016-11-26 10:59:00 -08:00
aakash-cr7
73fb9c6f66 Fix alignment of 'Not Delivered buttons' on smaller devices. 2016-11-26 10:13:48 -08:00
aakash-cr7
79b4ac8155 Add tooltips to buttons appearing when message is not delivered. 2016-11-26 10:13:48 -08:00
aakash-cr7
0525b65f90 Fix positioning of error message appearing on adding custom alert words.
Fixes #2413.
2016-11-26 10:11:55 -08:00
Steve Howell
92030204bb Look for untested urls more exhaustively. 2016-11-26 09:52:37 -08:00
Steve Howell
87bcbc9616 Add test_generate_204 for /api/v1/generate_204.
This endpoint is apparently needed by the desktop app.
2016-11-26 09:52:37 -08:00
Steve Howell
1d87d6fd86 Add test_refer_friend(). 2016-11-26 09:52:37 -08:00
Steve Howell
1527823b9f code cleanup: Remove some unused variables in test classes. 2016-11-26 09:52:37 -08:00
Arpith Siromoney
29d3019262 Switch no-loop-func eslint rule from warning to error (in .eslintrc)
The one error that needed to be fixed was in static/js/echo.js.
The function in the loop was being used by _.each(). This has been
replaced by iterating through the array using a while loop instead.
2016-11-25 14:02:44 -08:00
Rishi Gupta
fdae58f96b mypy: Change six.text_type to typing.Text in confirmation/models.py.
Example commit for GCI.
2016-11-25 13:55:38 -08:00
Rishi Gupta
c5d3c09a4a mypy: Change six.text_type to typing.Text for models.py. 2016-11-25 13:55:38 -08:00
Rishi Gupta
17f71befb4 mypy: Change six.text_type to typing.Text for a few files.
Preparation for GCI.
2016-11-25 13:55:38 -08:00
deniz
0e7899d170 markdown-help: Document new italic syntax. 2016-11-25 13:39:40 -08:00
Stanley Zheng
4d7920221c docker: Fix locale to UTF-8 more strongly.
This fixes locale issues where `pip install` would fail with Python 3
inside the docker environment.
2016-11-22 13:39:58 -08:00
Tim Abbott
5896e610cb docs: Fix apt-add-repository arguments in manual instructions. 2016-11-21 12:25:40 -08:00
Tim Abbott
5283c0eef5 docs: Fix generate_secrets.py arguments for manual install. 2016-11-21 12:23:47 -08:00
Tim Abbott
f78eb9d82d puppet: Add missing dependency on postgresql-common.
postgresql-$(version) depends on postgresql-common depends on ssl-cert,
which creates the ssl-cert group.
2016-11-21 07:38:45 -08:00
tonynater
70abbf76fc dev-remote: Edit Setting Up Development Environment docs.
Added sentences which explain each installation option.
2016-11-21 04:44:36 -08:00
tonynater
a5e0d9cd5c docs: Reorder sections and add details to remote-dev docs.
This reorders the sections such that setting up the development
environment and making sure it runs comes before editing the
code. Also added some clarifying sentences to give context to bullets.
2016-11-21 04:44:02 -08:00
Alex Dehnert
65ad144c6c dev-remote: Fix typos (you->your). 2016-11-20 13:28:12 -08:00
Chelsea Voss
32f5db16fb Add pytest-runner as a prereq to pip installing python-twitter.
While I was setting up the dev environment, pip failed to install
python-twitter: https://github.com/bear/python-twitter/issues/406

This was fixed by manually installing pytest-runner before trying to
install python-twitter, for both the python and python3 virtualenvs.
2016-11-20 13:06:41 -08:00
Pweaver (Paul Weaver)
b986cf9c41 docs: add a tutorial for setting up a remote dev environemnt 2016-11-20 12:38:14 -08:00
Christie Koehler
b088c08777 Add detail about how to report issues and ask for help. 2016-11-20 11:38:16 -08:00
Christie Koehler
a0635d65c1 Add note about Vagrant 1.8.7 curl issue. 2016-11-20 11:12:17 -08:00
Alok Puranik
0889ea583f Add UTF-8 locale to Dockerfile
This fixes an issue with pip crashing on several package installs due to
non-ASCII charsets.
2016-11-19 19:11:41 -08:00
Tim Abbott
ffb3291c82 urls: Clarify comment on v1_api_and_json_patterns. 2016-11-19 19:10:23 -08:00
Alex Dehnert
c07298b8a3 docs: Don't include zulip.readthedocs.io in internal links
Two reasons not to use such links:
- when making doc changes, if you follow links in your local build, they can
  cause you to silently end up no longer reading your local changes
- they can cause you to randomly switch between http:// and https://
2016-11-19 10:16:38 -08:00
Alex Dehnert
4d474b649f docs: Fix broken markdown syntax. 2016-11-19 10:16:32 -08:00
Tim Abbott
f5935e81c7 install: Support being run not directly from /root/zulip.
This adds a dependency on the realpath package on trusty; we could try
to remove it if needed, but given that realpath is included in
coreutils on Xenial (and presumably anything else modern), I think
it's reasonable to add it.

Fixes #1797.
2016-11-18 19:56:58 -08:00
Steve Howell
5f5e6b6d83 tests: Enforce 100% URL coverage.
We now instrument URL coverage whenever you run the back end tests,
and if you run the full suite and fail to test all endpoints, we
exit with a non-zero exit code and report failures to you.

If you are running just a subset of the test suite, you'll still
be able to see var/url_coverage.txt, which has some useful info.

With some tweaks to the output from tabbott.

Fixes #1441.
2016-11-18 18:10:29 -08:00
Tomasz Kolek
d8dee522b6 Fix trello integration by adding handling HEAD confirmation request.
Previously, we rejected the HEAD requests that the trello integration
uses to check if the server accepts the integration.

Add decorator for returning 200 status code if request is HEAD.

Fixes: #2311.
2016-11-18 16:27:16 -08:00
Tim Abbott
2abe11e209 lint-all: Fix progress bar from npm run lint in linter.
Also fixes printing the `eslint` help output in the event that there
are no files to check.

See https://github.com/zulip/zulip/pull/2246#issuecomment-261673662
for details on the original problem.
2016-11-18 16:19:05 -08:00
Arpith Siromoney
497c7702cc Run eslint in tools/lint-all with npm run --silent lint
This commit adds a basic eslintrc that emulates jslint defaults.
Rules that conflict with our existing code have been switched to
warnings instead of errors. Globals have been added to the eslintrc. The
bundled js file (generated by webpack) and blueslip.js are ignored with
.eslintignore.

To display warnings, run npm run lint-loud. This runs eslint without the
--quiet option on static/js and frontend_tests.

npm run --silent lint is run by tools/lint-all (in addition to jslint).
The --silent option is used to suppress the default output from npm run.

Fixes #535.
2016-11-18 16:15:45 -08:00
Tim Abbott
2d81813145 roadmap: Add buddy list scalability to agenda. 2016-11-18 15:58:08 -08:00
Tim Abbott
e302e2148b docs: Update incorrect links to issues in roadmap docs. 2016-11-18 15:55:02 -08:00
Tim Abbott
fe837e58b4 test_realm_filters: Fix missing mypy annotation. 2016-11-17 20:29:06 -08:00
Tim Abbott
bbdd0ec08d roadmap: The realm filters feature is merged. 2016-11-17 17:15:17 -08:00
Vladislav Manchev
d7e1e4a2c0 Add initial implementation of custom realm filters.
This PR was abandoned by Vladislav and then substantially modified by
Igor Tokarev and Tim Abbott to complete it and fix a number of bugs.

Fixes #544.
2016-11-17 17:11:25 -08:00
Steve Howell
8f96853fcb presence: Convert presence_info to use user IDs.
When we filtered buddy lists, a recent change introduced some
bugs related to case-insensitive emails.  We now circumvent the
bug by indexing presence_info with user_ids.
2016-11-17 13:27:28 -08:00
Tim Abbott
9c3d448fe4 compose: Clarify @-all errors are about mentions.
Every message to that stream goes to that number of users :).
2016-11-17 12:35:35 -08:00
paxapy
012ec2beda test-backend: Use a fixed whitelist of shallow-tested templates.
This enforces the requirement that all templates not on this list are
tested.  Part of #1677.
2016-11-17 11:34:50 -08:00
Brock Whittaker
5d2b81358c Code Simplification and Emoji Drag Fix.
There’s no need for four separate `$(sel).is()` statements, one will
do. This also added .drag to the list to ignore.
2016-11-17 11:21:15 -08:00
Brock Whittaker
2663215625 Do not close message compose box on drag.
On the drag to resize emoji box action, do not close the message
compose box.
2016-11-17 11:21:15 -08:00
bungeye
87c62a6937 Update twitter-bot to use latest python-twitter API. 2016-11-17 11:17:58 -08:00
Steve Howell
ca43cbc654 logging: Reducing logging in run-dev.py for queue workers.
In dev, we no longer log that individual queue workers were launched.

Instead, in dev (and prod as well), we log a message with the total
count.
2016-11-17 11:12:02 -08:00
hackerkid
cdb716aa63 bugdown: Add explanation for unicode-emoji JS regex. 2016-11-17 10:44:07 -08:00
Steve Howell
3a8282ff44 Add test coverage for /notify_tornado.
We now have test coverage for all of our endpoints.
2016-11-17 10:11:46 -08:00
Pweaver (Paul Weaver)
059cd1e7aa tests: enable the pep8 linter in travis CI. 2016-11-17 00:11:00 -08:00
Pweaver (Paul Weaver)
8f05ea877d lint: Fix pep8 linter error regressions.
Since `lint-all --pep8` wasn't running in CI, a few errors have leaked
in.
2016-11-17 00:09:21 -08:00
Steve Howell
82a497ec08 Remove spurious blueslip error for topic lists.
If we update an unread count for a topic that is not part of
our truncated list, we don't need to complain.
2016-11-16 22:01:30 -08:00
Tim Abbott
9fec519b3d Zephyr: Remove obsolete mit.html template. 2016-11-16 17:33:42 -08:00
Tim Abbott
dde6452638 Zephyr: Fix links to the old zulip.com service. 2016-11-16 17:33:13 -08:00
Brock Whittaker
9582079cd9 edit: Fix "View source" icon being orphaned post-hover.
It turns out it wasn’t a one-liner, it was actually a -2-liner. :)
2016-11-16 14:03:54 -08:00
Steve Howell
3b594a6efa bug fix: Keep old, active, upper-case topics in the topic list.
If you narrowed to a topic that was not one of the most recent 5
topics and had uppercase characters, it would disappear from the
topic list as soon as all of its messages were read.
2016-11-16 12:17:31 -08:00
Steve Howell
f4bf154981 bug fix: Fix topic unread counts for upper-case streams.
If stream names weren't entirely lowercase, then our function
topic_list.is_for_stream() was improperly reporting false and
failing to update unread counts for the active topic widget.

This regression was probably introduced in the fairly recent
53eea250d0 commit.

Fixes #2330.
2016-11-16 10:08:44 -08:00
Tim Abbott
61816f6151 populate_db: Remove replay_old_messages code.
Now that we have the data import/export tool, that's a better
mechanism for importing data than this old and likely buggy code was.
2016-11-15 22:34:44 -08:00
Tim Abbott
6d4075cef9 docs: Extend our documentation of our documentation.
The main purpose of this effort is to document our new /help/ docs,
but we update a bunch of other stuff while we're at it.
2016-11-15 22:01:44 -08:00
Tim Abbott
e6f4cb2635 attachment: Remove DB limit on length of filenames.
This fixes an issue where we threw on error on files with long names.
2016-11-15 21:12:05 -08:00
Christie Koehler
391ff638d5 build_emoji: Add nice error message for symlink errors. 2016-11-15 21:10:39 -08:00
Christie Koehler
2488698430 provision: Add symlink creation check.
This helps automatically detect a common issue where users try to use
the Vagrant development environment on windows without administrator
permissions, which results in errors trying to create symlinks.
2016-11-15 21:10:39 -08:00
Feorlen
d56272a162 docs: Explain how the HTML webhook documentation is used.
Part of #1998.
2016-11-15 21:00:16 -08:00
Feorlen
e45c10884e docs: Fix typo and whitespace. 2016-11-15 21:00:16 -08:00
Feorlen
d8afc306ee docs: Clarify that HelloWorldHookTests is subclassing WebhookTestCase.
Part of #1998.
2016-11-15 21:00:15 -08:00
Feorlen
ed61d3086d docs: Describe what an API key is and how to get one.
Part of #1998.
2016-11-15 20:59:43 -08:00
Feorlen
113b2b39fb docs: Describe what a test fixture is.
Part of #1998.
2016-11-15 20:59:39 -08:00
Feorlen
4725a7b7de docs: Describe what a webhook is.
Part of #1998.
2016-11-15 20:58:39 -08:00
Tim Abbott
fa8480bb62 subdomains: Add option to make subdomains homepage not a login form. 2016-11-15 19:05:06 -08:00
Steve Howell
9eb825fff5 Refactor PM unread counts to use user_ids as keys.
We now use comma-delimited lists of user_ids for the following
data structures in unread.js:

    - unread_privates[<user_ids_string>]
    - get_counts.pm_count[<user_ids_string>]
2016-11-15 18:31:59 -08:00
Steve Howell
1783879108 people.js: Add methods for user_ids_string/emails_string.
Added:
    * people.user_ids_string_to_emails_string
    * people.emails_strings_to_user_ids_string
2016-11-15 18:31:59 -08:00
Steve Howell
7750d43d23 Simplify finding elements in pm_list.js.
We no longer need iterate_to_find, and we just use simpler
selectors.
2016-11-15 18:31:59 -08:00
Steve Howell
f5e1dcd11d buddy list: Sidebar menu now uses user_id, not email. 2016-11-15 18:31:59 -08:00
paxapy
b90057d557 render_messages.py: render first version of edited messages.
This decreases the number of spurious differences in rendered content
significantly.
2016-11-15 13:39:11 -08:00
reyha
9f8630fed8 tests: Access realms by string_id.
Replaces get_realm() function by get_realm_by_string_id() function
in zerver/tests.

Fixes #2226.
2016-11-15 13:32:20 -08:00
Tim Abbott
49d24cee2a subs: Fix clearing filter table on subscribe. 2016-11-15 12:49:40 -08:00
Tim Abbott
86fbc415b9 docs: Fix typo in roadmap reactions item. 2016-11-15 12:27:27 -08:00
Brock Whittaker
3d8ed7b55f subs: Rewrite Stream Filter Function.
This is more performant, along with accepting a parameter for
filtering only streams that are subscribed to if the toggle is set to
subscribed only.

Also, it now does substring matches, rather than just matching if an
entire word matches the search query.

Fixes #2141.
2016-11-15 12:21:43 -08:00
Brock Whittaker
1def0b6701 hashchange: Add hashchange ignore mechanism for overlays.
This will make it possible to do hash changes in soon-to-be-overlay
pages like the /#subscriptions and /#settings page.
2016-11-15 11:53:38 -08:00
Tomasz Kolek
074571dddc Fix English grammar in push/remove tag message. 2016-11-15 10:48:12 -08:00
Tomasz Kolek
1feedbe346 Add github webhook integration. 2016-11-15 10:48:12 -08:00
Tomasz Kolek
2335e1b8b9 Add escaping charactes (=,>,<) by checking correct spelling of GitHub word 2016-11-15 10:48:12 -08:00
Brock Whittaker
75db036733 Add toggle component.
This adds the toggle component which removes the necessity to have HTML.
2016-11-15 10:20:37 -08:00
Tim Abbott
a960ff6773 requirements: Update cryptography packages. 2016-11-15 10:13:51 -08:00
Tim Abbott
0145987fbe Update roadmap introduction section of roadmap. 2016-11-15 09:55:30 -08:00
Sumana Harihareswara
e1f7b94bf5 Roadmap doc: Update intro date. 2016-11-15 09:55:30 -08:00
Sumana Harihareswara
bef4fc94d3 Roadmap doc: Update desktop app section. 2016-11-15 09:55:30 -08:00
Sumana Harihareswara
3ca3668885 Roadmap doc: Update security, testing, & docs sections. 2016-11-15 09:55:30 -08:00
Sumana Harihareswara
b06db1e776 Roadmap doc: Remove tasks we've already done. 2016-11-15 09:55:30 -08:00
Sumana Harihareswara
1c68436465 Roadmap doc: Update technology improvement section. 2016-11-15 09:55:30 -08:00
Sumana Harihareswara
e0a1e401f6 Roadmap doc: Update realtime sync, performance, and scalability tasks.
Also move and update community, internationalization, and
development environment tasks.
2016-11-15 09:55:30 -08:00
Sumana Harihareswara
b54aa2e415 Roadmap doc: Update onboarding and administration tasks. 2016-11-15 09:55:30 -08:00
Sumana Harihareswara
eba34309dc Roadmap doc: Update user experience and social tasks. 2016-11-15 09:55:30 -08:00
Sumana Harihareswara
98e5f502d3 Roadmap doc: Update mobile tasks. 2016-11-15 09:55:30 -08:00
Sumana Harihareswara
9799da1fc2 Roadmap doc: Update internationalization section. 2016-11-15 09:55:30 -08:00
Sumana Harihareswara
0c9ed70a8d Roadmap doc: Update integrations section. 2016-11-15 09:55:30 -08:00
Sumana Harihareswara
43f77a37a4 Roadmap doc: Update number of PRs merged. 2016-11-15 09:55:30 -08:00
Steve Howell
26857ac3aa admin: Use helpers when opening user form. 2016-11-15 09:37:47 -08:00
Steve Howell
7656c31769 Extract admin.get_email_for_user_row(). 2016-11-15 09:37:47 -08:00
Steve Howell
33a87492e2 admin: Remove obsolete active_user_row class. 2016-11-15 09:37:47 -08:00
Steve Howell
ecfac010fc Extract admin.set_up_deactivate_user_modal().
This sets us up to eliminate the "active_user_row" hacks in
our next commit.
2016-11-15 09:37:47 -08:00
Steve Howell
dcfb5c30c6 admin users: Fix real-time-sync for full names.
When an ordinary user changes their name, the admin sees the change
when they open the edit form now.
2016-11-15 09:37:47 -08:00
Umair Khan
2314adc4fc Django 1.10: Compare CSRF tokens after unsalting them.
For reference: https://docs.djangoproject.com/en/1.10/ref/csrf/#how-it-works
2016-11-15 09:34:08 -08:00
Umair Khan
29254142f6 Django 1.10: Run maybe_update_realm_filter when it's needed. 2016-11-15 09:34:08 -08:00
Umair Khan
5af50db430 Django 1.10: Fix client cache while running tests.
Django reverts all the changes after running a test but the
client cache retained the deleted value, this caused the
subsequent tests to fail due to invalid foreign key constraints.
This commit fixes the issue by prefixing the cache name in
client cache with KEY_PREFIX which is bounced after every test.
2016-11-15 09:34:08 -08:00
Tomasz Kolek
ea58005796 Fix styling in api_key_box section on settings page.
Before fix, "Your API key" section was to close left side of the box.
2016-11-15 09:32:10 -08:00
Tim Abbott
57e7b741b6 rss-bot: Fix incorrect use of zulip.generate_option_group.
The fields set by the automatic option group all have `zulip_` at the
start of their names.
2016-11-14 22:48:28 -08:00
Tim Abbott
e40e756d47 echo: Fix local echo sending a message to "yourself, ".
Previously, this would incorrectly include a user with name and email
"" in the recipients list shown in the local echo code path.

We fix this and add a test for the issue.
2016-11-14 21:43:13 -08:00
Tim Abbott
d655cd1f7f Remove zulip.egg-info from .gitignore.
We've been seeing failures in Travis CI like this:
https://travis-ci.org/zulip/zulip/jobs/175921132, which seem to be
caused by an issue with .gitignore handing.  This seems to fix the
problem, though I don't yet understand why.

This reverts 7c0970d171.
2016-11-14 21:26:25 -08:00
hackerkid
67120d7a9d Support backend unicode-emoji rendering without whitespace. 2016-11-14 21:02:18 -08:00
hackerkid
249382c45d Add .vscode folder to gitignore.
gitignore: Ignore visual studio code workspace settings folder.
2016-11-14 20:45:34 -08:00
Tim Abbott
8a5ae2893e send_pm_if_empty_stream: Clean up unnecessary nesting.
This has no functional changes.
2016-11-14 20:40:05 -08:00
Tim Abbott
b09c2369c1 send_pm_if_empty_stream: Use realm object to check cross-realm.
The previous check didn't work correctly in the event that the target
stream did not exist.
2016-11-14 20:36:46 -08:00
Tim Abbott
4cfcc70e78 test_messages: Expand tests for send_pm_if_empty_stream.
This would have caught the last issue we had with this code path.
2016-11-14 20:32:52 -08:00
Tim Abbott
af675998d5 Fix send_pm_if_empty_stream with nonexistent streams. 2016-11-14 20:32:29 -08:00
hackerkid
951f1d9cdb Add missing unicode range to text: replace(inline.breaks.text)
This is a followup of #2297.
2016-11-14 20:10:54 -08:00
Steve Howell
59750a1cb9 Move more unread logic out of stream_list.js.
There are two split-outs code of the code here:

    - Animation stuff is in unread_ui.js.
    - PM unread counts get handled by pm_list.js.
2016-11-14 17:50:55 -08:00
Steve Howell
e732892654 css: De-duplicate some common styles for unread counts. 2016-11-14 16:16:55 -08:00
Steve Howell
7c1711179c Rename subject_count class to topic-unread-count. 2016-11-14 16:16:55 -08:00
Steve Howell
72b8200b0b refactor: Extract update_unread_count() in topic_list.js.
This function does the "heavy" lifting of updating an unread
count.  (It's not exactly heavy lifting, but it makes it so
the parent just needs to find the outer element of the unread
div, using whatever method makes sense for the parent.)
2016-11-14 16:16:55 -08:00
Umair Khan
9b0f9bf326 Django 1.10: apply_response_fixes was removed.
Ref: https://code.djangoproject.com/ticket/26052?cversion=0&cnum_hist=2
2016-11-14 16:09:12 -08:00
Umair Khan
3d3800314f Django 1.10: Setup django before running queue processors. 2016-11-14 16:09:12 -08:00
Umair Khan
7d51efe9a1 Django 1.10: Fix dummy data for count stat.
Django 1.10 checks the foreign key constraints as part of the testing
suite so we need to create test data which passes validation tests.
2016-11-14 16:09:12 -08:00
Umair Khan
47e8a56870 Django 1.10: Use compatible django guardian. 2016-11-14 16:09:12 -08:00
Umair Khan
e89af4c470 Django 1.10: Fix django-bitfield.
SubfieldBase was deprecated in Django 1.10 so the version we use now
doesn't rely on that class.
2016-11-14 16:09:12 -08:00
Umair Khan
5cfd54994a Django 1.10: validate is replaced with check.
See
https://docs.djangoproject.com/en/dev/releases/1.7/#modeladmin-validators
for explanation.
2016-11-14 16:09:12 -08:00
Steve Howell
e7a2b51647 Consolidate people searches (buddy list/subscribers).
We now use the same people-filtering code for the buddy
list that we use in subscriber search.
2016-11-14 16:01:13 -08:00
Steve Howell
71d93207cd Match "Charles Dickens" with "ch di" in subscriber search. 2016-11-14 16:01:13 -08:00
Steve Howell
6eb1dc3e73 Refactor filter_people_by_search_terms().
Build individual matchers for each search term.
2016-11-14 16:01:13 -08:00
Steve Howell
2746518f3c Make subscriber filter match on emails.
We will match emails that start with search terms.
2016-11-14 16:01:13 -08:00
Steve Howell
504045f47d Pass in search terms as arrays to test_filtered_users(). 2016-11-14 16:01:13 -08:00
hackerkid
b2e91eae13 Add marked.js support to emojis in miscellaneous and dingbats block.
https://en.wikipedia.org/wiki/Emoji#Unicode_blocks
2016-11-14 15:58:16 -08:00
Steve Howell
8fa519ded6 Remove some dead code in stream_list.js.
I forgot to remove this code in a recent refactoring that copied
this code into activity.js.  It should not have caused any errors,
but it's no longer needed.
2016-11-14 15:53:23 -08:00
Steve Howell
fad0a86554 Add HelpTest for help pages. 2016-11-14 15:47:35 -08:00
Steve Howell
02cf40ade8 Add test_redirect_endpoints() in test_signup.py. 2016-11-14 15:47:35 -08:00
Tim Abbott
151267edf6 Roadmap: Make several more things as finished. 2016-11-11 16:24:20 -08:00
hackerkid
8c83b34ad5 Support backend emoji rendering without whitespace. 2016-11-11 16:18:57 -08:00
Feorlen
4ed5c21821 Update Desk.com webhook integration.
Updates the HTML docs to match changes to the Desk.com website,
including all new screenshots for the custom action workflow.

Tests four types of messages that could be sent as notifications from
Desk.com. Desk.com allows an account administrator to send any text
in a custom action, so there isn't a standard format.

Custom actions send URL-encoded POST data, the test fixtures contain
URL-encoded text like what could be sent by a custom action configured
as described in the Zulip Integrations documentation to post a new
message to a stream. (See also #2169, errors in this documentation.)

New zerver.tests.webhooks.test_deskdotcom.DeskDotComHookTests:

* Static text: minimal plain text string
* Case updated: activity alert with link to a Desk.com case and message
* Unicode text Italian: activity alert with message in Italian
* Unicode text Japanese: activity alert with message in Japanese

Each posts a new message in the deskdotcom stream.

Tested on Ubuntu 14.04. I created the fixtures with Emacs, I would
appreciate if someone can check that the Italian and Japanese messages
look ok. I used the same text for a live test and it displayed correctly.

Fixes #2031
2016-11-11 16:06:22 -08:00
Tomasz Kolek
4659abae65 test_fixtures: handle a case when given database does not exist.
Sometimes i.e. when you force close (ctrl-c) during ./tools/test-backend
a next execution might raise an error becuase DATBASE_NAME does not exist.
2016-11-11 15:40:10 -08:00
Tomasz Kolek
f05b71b9ca Add handling multiple push info in one request to Bitbucket2 integration. 2016-11-11 15:36:45 -08:00
Tomasz Kolek
085cdb7028 Fix Bitbucket2 push message by truncated commits list. 2016-11-11 15:36:45 -08:00
Tomasz Kolek
ed1d7f7997 Add is_truncated param to git integrations push commits event.
Add is_truncated param for cases when we know that there were more commits
but we dont know actual number and want just inform about existing of the rest.
2016-11-11 15:36:45 -08:00
Tomasz Kolek
81f18b829d Normalize pushing tags event messages in Bitbucket2 integration. 2016-11-11 15:36:45 -08:00
Tomasz Kolek
5980a75e07 Normalize pushing tags event messages in GitLab integration. 2016-11-11 15:36:45 -08:00
Tomasz Kolek
6be27a1396 Add get_push_tag_event_message function to git integrations common (git.py). 2016-11-11 15:36:45 -08:00
Rishi Gupta
5681ee90fa models.py: Rename split_email_to_domain to email_to_domain.
In order to better match models.email_to_username.
2016-11-11 15:26:51 -08:00
Rishi Gupta
c1713c9659 Prevent code from using email domain to determine realm when subdomains.
Also removes the intermediate step of going through Realm.domain in the
non-subdomains case. Part of a larger project to remove Realm.domain
entirely.
2016-11-11 15:26:51 -08:00
Rishi Gupta
411a7b08e0 bulk_create_users: No longer de-alias user email addresses.
bulk_create.bulk_create_users is only called by initialize_voyager_db.py and
populate_db.py, both of which only have realms with single domains.

Part of a larger project to remove the Realm.domain field.
2016-11-11 15:26:51 -08:00
Rishi Gupta
91f2582c2b templates: Remove for_you block from jinja templates.
No change in behavior. The for_you block had already been removed in
portico.html long ago in a6889080ce. The
contents of the block are still present in the non-portico 404.html
and 5xx.html error pages.
2016-11-11 15:26:08 -08:00
Rishi Gupta
6608627bc0 models.py: Move Realm and RealmAlias functions to appropriate locations.
Currently refactoring the Realm and RealmAlias portions of models.py to no
longer use Realm.domain. Move various functions related and not-related to
the two model objects to more conventional places in the file.

No change to behavior.
2016-11-11 15:24:42 -08:00
Steve Howell
47ef26fa55 refactoring: Let activity.js manage its own unread counts.
This change breaks a needless dependency of activity.js on
stream_list.js.
2016-11-11 12:27:03 -08:00
Steve Howell
f3373d62e1 stream sidebar: Clean up unsubscribe logic.
From subs.js we don't redundantly try to remove an element
from ths sidebar; we just trigger the event.

In stream_list.js we continue to remove the element from
the DOM, and we also remove the widget from our internal
Dict of sidebar rows, so that if we re-subscribe, we know
we'll automatically re-build the widget from the template
and the latest data from stream_data.js.
2016-11-11 12:12:13 -08:00
Steve Howell
d867cba90b Add stream_list.stream_sidebar() class.
This new class lets us store sidebar rows inside of stream_list.js
instead of putting them on sub objects from stream_data.js.
2016-11-11 12:12:13 -08:00
Steve Howell
7b0c6459b4 Extract static/js/pm_list.js.
This handles most of the details of building the Private Messages
section in the upper left corner of the app.
2016-11-11 12:12:13 -08:00
Steve Howell
af794bec7a Remove unused stream_list.get_count(). 2016-11-11 12:12:13 -08:00
Steve Howell
6a3254f83f Clean up how we build individual stream sidebar rows.
We used to have hacky code where various functions would call
build_stream_sidebar_row() to get a jQuery object, and then they
would attach the jQuery object to the "sub" object from stream_data.js.

Now build_stream_sidebar_row() localizes the hack of attaching
a UI object to the "sub" object to just one function (and we can
clean this up in a follow-up commit).

Also, the UI object is now a JS object that can close on some useful
state information like the stream name and encapsulate how we
toggle the inactive_stream class.

Finally, we don't have build_stream_sidebar_row() needlessly append
list items to $('#stream_filters') when we know that our callers are
going to re-build the list anyway.
2016-11-11 12:12:13 -08:00
Steve Howell
13fbb96178 Remove unnecessary call to build_stream_list().
In refresh_pinned_or_unpinned_stream(), we no longer call
build_stream_list(), because that's already called in
update_streams_sidebar().
2016-11-11 12:12:13 -08:00
Steve Howell
16cb2bce8b Remove duplicate loop in build_stream_list().
The code removed in this commit added pinned streams to a list
of elems, only to have them added again by the next block of code
(but more concisely).  Through some strange quirk of appendTo() this
never created user-facing bugs, but you could clearly see in the console
that it was doing double work.
2016-11-11 12:12:13 -08:00
Steve Howell
06f4857221 buddy list: Make Group PMs appear more quickly.
It used to be the case that you would get new messages for a
huddle, but the huddle wouldn't show up on your buddy list until
the every-50-seconds mass update of the buddy list.

Now we make sure to work with non-stale jQuery objects, and,
more importantly, we resize ourselves if we add new huddles.

(The resize issue arises due to some complicated heuristics
where we don't want group PMs to take up too much of the buddy
list for users who don't have many in their history.)
2016-11-11 12:02:48 -08:00
Steve Howell
197edcca0e buddy list: Update huddles when you fetch PMs.
This fixes a bug with the group pm section of our
buddy list.  It wasn't updating when you fetched
old private messages.

We had been calling activity.process_loaded_messages() as
part of message_store.do_unread_count_updates(), which was
called sometimes unnecessarily and sometime not called when
we needed to get huddle info.

Now we call it when we need it most, which is when you
click on "Private Messages".
2016-11-11 10:41:18 -08:00
Steve Howell
eef633efa0 minor: Make get_huddles() internal to activity.js. 2016-11-11 10:41:18 -08:00
Tim Abbott
48f671a314 same_realm_jabber_user: Remove old ist.mit.edu hack.
This is no longer in use.
2016-11-10 20:50:40 -08:00
Tim Abbott
3b145b2370 add_new_user_history: Fix ordering of created UserMessage rows.
This has no functional effect because user_message IDs aren't used,
but will make the database cleaner.
2016-11-10 20:39:34 -08:00
Tim Abbott
08ca209aed add_new_user_history: Fix race with new messages arriving during signup.
Previously, if a new message arrived between when a user is subscribed
to the default streams and when the user's initial messages are
queried, we would try to create two UserMessage rows for the same
Message, resulting in an IntegrityError crash.  We fix this and add a
test for that race condition.
2016-11-10 20:38:27 -08:00
Tim Abbott
80c2df616e signup: Extract add_new_user_history. 2016-11-10 20:37:03 -08:00
Brock Whittaker
d45c050994 message_edit: Restyle message_controls options to have better spacing.
This restyles the message_controls options to center them horizontally
while fixing them closer to the right side of the edge, along with just
replacing the edit button with a preview source button once editing is
disabled.
2016-11-10 19:47:26 -08:00
Brock Whittaker
5497416a36 Move edit button to underneath message timestamp.
This moves the edit button to underneath the timestamp such that when
you hover over a message now the timestamp hides itself and the edit
button appears (if editing is allowed).

Fixes #1733 and other annoying issues with this field.
2016-11-10 19:45:09 -08:00
sinwar
4582a98c09 tests: Split out ZulipTestCase and WebhookTestCase to a separate file.
Fixes #1671.
2016-11-10 19:29:43 -08:00
paxapy
ade3bda025 markdown: Fix stream link handler in corner cases.
* Fixes handling of multiple stream links and invalid stream names.
* Fixes text regex so it handle hash sign the right way.
* Adds tests for these stream link cases.
2016-11-10 19:22:19 -08:00
Igor Tokarev
852bc6b491 bugdown: Re-enable support for italics in bugdown.
Fixes: #1103.
2016-11-10 19:14:40 -08:00
Rishi Gupta
eeca06ea08 message_edit: Fix message editing for messages that threw a backend error.
Changes editibility type from NONE to FULL, and makes Save and Cancel
buttons work. Exposes a new bug, which is that changing the topic changes
the topic for the recipient row, rather than the message. See #2278.
2016-11-10 16:45:18 -08:00
Rishi Gupta
3c75ef2d79 Allow users to submit empty content when editing messages.
The closest we have to deleting a message. Was original behavior, but was
changed in 09754c9.
2016-11-10 16:45:18 -08:00
Steve Howell
b0a8e4befe topic lists: Rebuild DOM when we zoom in or zoom out.
This change sets the stage to reload more topics from the back
end when we zoom in, and it slims the DOM for the typical use
case of being zoomed out.
2016-11-10 15:55:31 -08:00
Steve Howell
f923320de8 topic lists: Add get_stream_name() to topic list widget. 2016-11-10 15:55:31 -08:00
Steve Howell
d8b5558699 topic lists: Refactor handling of parent element.
The widget that gets built in topic_list.build_widget()
now knows how to add itself to its parent element and expose
an interface to retrieve the parent.
2016-11-10 15:55:31 -08:00
Steve Howell
3b7430ba82 topic lists: Refactor zoom-out logic for un-narrows.
For cases where we are zoomed in to a stream and then go
to a different narrow (Home, PMs, etc.), we now let
topic_list.zoom_out orchestrate the removal of the topic list
instead of stream_list.zoom_out.

This will help us when we move to a world where topic_list
redraws topic lists on zoom-in/zoom-out, because we won't
waste effort rebuilding lists that are about to be removed.
2016-11-10 15:55:31 -08:00
Steve Howell
bfc6f57195 topic lists: Move some zooming logic into topic_list.js.
The flow for topic list zooming is kind of complicated now, but
it's mostly a consequence of the way the UI works.

* stream_list tells topic_list to set up the topic list
  click handlers to have callbacks to stream_list
* topic_list click handlers call to stream_list zoom methods
  to hide/show all the other streams
* stream_list zoom methods call back to topic_list methods to
  redraw topics as needed (this isn't happening yet, but allowing
  topic_list.js to know that it's zoomed will set the stage for
  this to happen in a more controlled manner)
2016-11-10 15:55:31 -08:00
Steve Howell
53eea250d0 topic lists: Formalize that we only ever have one widget.
We now only keep zero or one widgets around in memory, and
we don't need jQuery magic any more to find the DOM elements
to remove.
2016-11-10 15:55:31 -08:00
Steve Howell
06816d19e6 topic lists: Call narrow.topic() in topic_list.js.
We no longer need stream_list.js to pass in the currently
active topic to us; we just call narrow.topic() for it.
2016-11-10 15:55:31 -08:00
Steve Howell
853126344e Add narrow.topic() helper method.
This has similar semantics to narrow.stream().
2016-11-10 15:55:31 -08:00
Steve Howell
e76422b946 Use narrow.stream() instead of stream_list.active_stream_name().
We no longer use active_stream_name(), which was mostly a
duplicate of narrow.stream().  For nonsensical queries like
"stream:foo stream:bar" the behavior may change slightly here.

We know that we don't handle non-sensical queries particularly
well, but at least if we always go through narrow.stream(),
the behavior will be consistent.

I did test this with some sensible compound narrows, like searching
for a keyword within a stream.
2016-11-10 15:55:31 -08:00
umkay
dc8463e09c analytics: Remove incorrect filter args for stat.
The filter args dictionary applies to the X table in a count X by Y query,
which in this case is the zerver_message table. This stat had an incorrect set
of arguments meant for the zerver_userprofile table.
2016-11-10 12:25:21 -08:00
paxapy
4438a09b30 Add migration to create attachments for old uploads.
This migration ensures that all historically uploaded files from
before we started tracking files in the Zulip database via the
Attachment model have Attachment objects.

This has been tested by tabbott against a production server to ensure
that it results in all old uploaded files having corresponding
attachment objects.

Merging this change is a key prerequisite for making our adding
attachment access controls in an enforcing fashion.
2016-11-10 12:14:08 -08:00
Umair Khan
07d73996d4 Django 1.10: Add tool to check urls.
Checking urls through linter was proving to be difficult as
the urls can span multiple lines.
2016-11-10 16:20:04 +05:00
Umair Khan
86b75aade2 Django 1.10: Fix i18n tests.
SimpleCookie does not accept unicode strings and the name of
Simplified Chinese is changed to zh-HANS.
2016-11-10 16:20:03 +05:00
Umair Khan
ee3ec96f38 Django 1.10: Suppress logs. 2016-11-10 16:20:03 +05:00
Umair Khan
1e91b946d9 Django 1.10: Sign google oauth requests using csrf token.
In Django 1.10, the get_token function returns a salted version of
csrf token which changes whenever get_token is called. This gives
us wrong result when we compare the state after returning from
Google authentication servers. The solution is to unsalt the token
and use that token to find the HMAC so that we get the same value
as long as t he token is same.
2016-11-10 16:20:03 +05:00
Umair Khan
d837753d4b Django 1.10: Update analytics urls. 2016-11-10 16:20:03 +05:00
Umair Khan
e127325fce Django 1.10: Update zilencer urls. 2016-11-10 16:20:03 +05:00
Umair Khan
da78f27934 Django 1.10: Upgrade zproject urls. 2016-11-10 16:20:03 +05:00
Umair Khan
010ab0637d Django 1.10: Upgrade integration urls. 2016-11-10 16:20:03 +05:00
Umair Khan
fa6b607fc2 Django 1.10: Upgrade legacy urls. 2016-11-10 16:20:02 +05:00
Umair Khan
f8e569cb69 Django 1.10: Upgrade urls of dev_urls.py. 2016-11-10 16:20:02 +05:00
Tim Abbott
46a601c4c4 Import the user documentation guide into new user docs system.
This is an import of
https://github.com/brannerchinese/zulip_user_documentation
into the main Zulip repository.  Important changes include:

* Removed trailing whitespace.
* Changed URLs for images to work properly.
2016-11-09 21:39:55 -08:00
Tim Abbott
02855498e9 render_markdown_path: Add fenced code and codehilite support.
This also causes us to only initialize the extensions once per process.
2016-11-09 21:39:55 -08:00
Tim Abbott
08043ff9a0 render_markdown_path: Add anchors for table-of-contents. 2016-11-09 21:39:55 -08:00
Tim Abbott
0568ade496 render_markdown_path: Decode UTF-8 after reading from disk.
This is required to support unicode characters in our markdown filesq.
2016-11-09 21:39:55 -08:00
Tim Abbott
cf2007d4e0 docs: Add a simple markdown-based help center.
The plan is to use this for adding user documentation to Zulip.
2016-11-09 21:39:55 -08:00
Tim Abbott
a715f083bb render_markdown_path: Allow HTML in templates. 2016-11-09 21:12:44 -08:00
Tim Abbott
d9b1a5a417 render_markdown_path: Don't cache in development.
That caching made the edit/refresh cycle for docs annoying.
2016-11-09 21:12:44 -08:00
Brock Whittaker
129d88825c messages: Wrap inline code blocks on long lines.
In 25b28bf82c and then
cb1bc70ab0, we attempted to make long
code blocks scroll in a reasonable fashion, without much success.

This change causes code blocks to be line-wrapped, without needing to
set `overflow-y: hidden` for paragraphs (which cause problems with
taller elements like emoji that overlfowed wrong).  Our octopi finally
have legs again.

It's not clear that this is the final answer, but it's the best
version we've found so far.
2016-11-09 19:26:45 -08:00
Steve Howell
16e37f8874 Limit compose at-mention typeaheads to realm users.
Fixes #2240
2016-11-09 19:20:58 -08:00
Rishi Gupta
1c869c2287 models.email_allowed_for_realm: Use RealmAlias instead of domain. 2016-11-09 16:31:48 -08:00
Rishi Gupta
70ab79d056 accounts_register: Apply email_allowed_for_realm check to all code paths.
Needed in case the user was allowed to join the realm when they got the
confirmation email, but is no longer allowed to do so. Check was previously
applied to invited users (those with a prereg_user.referred_by), and is now
applied regardless of how they get to accounts_register.
2016-11-09 16:31:48 -08:00
Rishi Gupta
d5f99c4438 views.accounts_register: Remove almost all dependence on domain. 2016-11-09 16:31:48 -08:00
Rishi Gupta
823915fa46 UserSignUpTest: Add tests for forms.HomepageForm. 2016-11-09 16:31:48 -08:00
Rishi Gupta
1e6ae537bd Remove special flow for open realm sign-up when realms have subdomains.
Redirects /register/<domain> to /accounts/register when
REALMS_HAVE_SUBDOMAINS.
2016-11-09 16:31:48 -08:00
Rishi Gupta
b114690bd5 forms.HomepageForm: Rename subdomain to string_id.
No change to behavior.
2016-11-09 16:31:48 -08:00
Rishi Gupta
38f1ab325c forms.HomepageForm: No longer take a domain argument.
domain was unused. No change to behavior.
2016-11-09 16:31:48 -08:00
Rishi Gupta
ff2fe0cf92 forms.HomepageForm: Improve error messages.
No change to behavior.
2016-11-09 16:31:48 -08:00
Rishi Gupta
d1acc54b2f forms.HomepageForm: Stop users from signing up for realms they can't join.
We do this check in accounts_register as well, but might as well tell the
user now not to get their hopes up.
2016-11-09 16:31:48 -08:00
Rishi Gupta
82b60ad29e forms.HomepageForm: Disallow mit mailing lists from open mirroring realms.
I'm guessing the old behavior was unintended, rather than policy.
2016-11-09 16:31:48 -08:00
Rishi Gupta
78dee73511 forms.HomepageForm: Consolidate check for open realm.
Does change/fix behavior in various corner cases when the domain passed in
to HomepageForm and subdomain passed in to HomepageForm correspond to
different realms.
2016-11-09 16:31:48 -08:00
Rishi Gupta
01526677c4 forms.HomepageForm: Use string_id to determine intended signup realm.
If the user comes in to HomepageForm with a set subdomain, use that to
determine the signup realm instead of the email address.

In the non-REALMS_HAVE_SUBDOMAINS case, still allow using the email address
if no subdomain is passed.
2016-11-09 16:31:48 -08:00
Rishi Gupta
eddd8fb5fe forms.HomepageForm: Reorder email checks for future edits.
No change to behavior.
2016-11-09 16:31:48 -08:00
Rishi Gupta
6e517b2dec models.py: Disable unique_open_realm feature when realms have subdomains. 2016-11-09 16:31:48 -08:00
Rishi Gupta
35481014a4 views.create_homepage_form: Ensure domain and subdomain match.
Ensure domain and subdomain correspond to the same realm when being passed
to forms.HomepageForm. Previously this was not the case when e.g. we got
here via the /register/<domain> endpoint.

This also effectively disables the register/<domain> endpoint when
REALMS_HAVE_SUBDOMAINS, or rather, foo.server.org/register/bar.com will try
to register you for the realm with string_id foo rather than realm with
domain bar.com.
2016-11-09 16:31:48 -08:00
Rishi Gupta
60b5b82b57 forms.py: Merge get_valid_realm into caller.
No change to behavior.
2016-11-09 16:31:48 -08:00
Tim Abbott
f6d3c63a01 realm_alias: Access realm alias objects in lower-case. 2016-11-09 16:31:48 -08:00
Shashank
702d3cf103 Check provision version in run-dev.py.
Don't start run-dev.py if the provisioning version is
incorrect.
2016-11-09 16:06:16 -08:00
Umair Khan
eade575267 Django 1.10: Redirect is not permanent by default. 2016-11-09 15:29:58 -08:00
Umair Khan
cfded8b5af Django 1.10: Resolve QuerySet returned by model_to_dict.
Django 1.10 resolves ManyToManyField into a QuerySet in model_to_dict.
This commit further resolves the QuerySet to the primary keys.
2016-11-09 15:29:58 -08:00
Umair Khan
f78752466c Django 1.10: URLs in response contain just the path.
The response object of the Django test client only contains the
path of the url.
2016-11-09 15:26:07 -08:00
Umair Khan
dd174b537f Django 1.10: Update code according to new get_user function.
`django.contrib.auth.get_user` function is updated in Django 1.10, due to
which everytime we update the password of the user the password hash changes.
This causes authentication failure. Previously, our code worked correctly
because we use our own session middleware and the `get_user` code had a
conditional statement which allowed our code to bypass the authentication
code.
2016-11-09 15:26:07 -08:00
paxapy
6d93b3b60c lint: Fix E703 pep8 violations. 2016-11-09 15:18:35 -08:00
paxapy
456e761294 lint: Add pep8 checker to the project.
We set this up initially with all of the rules that Zulip violates
disabled.

Also, the pep8 linter is substantially slower than the other Zulip
linters, so we've put it behind an option to `tools/lint-all`.
2016-11-09 15:17:49 -08:00
Steve Howell
5e51a93688 Change stream_data.remove_subscriber() to accept user ids. 2016-11-09 15:03:08 -08:00
Steve Howell
00068f3164 Extract stream_data.unsubscribe_myself(). 2016-11-09 15:03:08 -08:00
Steve Howell
b5ef679360 Add get_topic_history_for_stream(). 2016-11-09 13:56:27 -08:00
Steve Howell
89b2e51129 Extract is_active_subscriber() helper for streams views. 2016-11-09 13:56:27 -08:00
sinwar
7c0970d171 api: Add zulip.egg_info to gitignore.
Now that we have the development environment setup to build the API
bindings directly from api/ by default, this should be in .gitignore.
2016-11-09 13:21:19 -08:00
Steve Howell
537a3b8ca8 Change stream_data.add_subscriber() to accept user_ids.
We no longer require passing in an email to
stream_data.add_subscriber(), since we only track user ids
in stream_data.js.
2016-11-08 15:49:23 -08:00
Steve Howell
a03a7d4c95 peer_remove: Send user_id, not email, for unsubscribe events. 2016-11-08 15:36:29 -08:00
Steve Howell
61625ce51e Add draft document for user populations.
(This is mostly an internal dev document for now.  We should eventually
link it into our RTD system, perhaps after we think we are mostly
bug-free in terms of what the doc specifies.)
2016-11-08 15:28:04 -08:00
Tim Abbott
3caee213e1 test_render_mention_stream_api: Fix nondeterministic failures.
This previously dependended on the stream ID for Denmark, which is not
a constant across all installations.
2016-11-08 14:13:48 -08:00
Tim Abbott
5f70b15a00 test_bugdown: Fix duplicate test name. 2016-11-08 14:09:53 -08:00
Mohsen Ibrahim
44c8e4c58c streamLinkHandler: render stream links correctly.
After adding the ability to add stream links to messages using
the following pattern '#**stream_name**' there was a problem
with rendering this using our markdown engine because '**' means
bold text so that would render just to bold text.
To solve this I had to add regular expression in marked.js to match
that pattern and when it matches I call handleStreamLinks in echo.js
which will correctly render it to HTML.

Fixes #2218.

[tweaked by tabbott to url-encode the stream name in the URL and
adding the missing "#" in the display].
2016-11-08 13:52:31 -08:00
Mohsen Ibrahim
e0351948ba render_message_backend: Pass realm data into bugdown.
Previously, the way that render_messages was calling bugdown meant
that the preview feature didn't have access to realm data like the
list of users or streams, resulting in previews for those elements
being wrong.

Now render_message_backend uses zerver.lib.render_markdown to render
messages correctly.

[Commit message tweaked and test added by tabbott]
2016-11-08 13:43:03 -08:00
paxapy
ff1e97603d context_processors: use a common context for emails.
Fixes #1611.
2016-11-08 11:37:16 -08:00
paxapy
8c7ed80281 context_processors: refactor add_settings realm code.
The new code is substantially clearer and ensures realm_uri is always
set reasonably.
2016-11-08 11:37:16 -08:00
Tim Abbott
56552007bf create_user: Disable stream desktop notifications by default.
This feature intended to be disabled by default months ago, but due to
the override code deleted in this commit, was actually still on by default.
2016-11-08 07:48:49 -08:00
Rishi Gupta
bab481efc2 forms.py: Refactor MIT mailing list check into a modern style.
No change to behavior. non_mit_mailing_list never returned False, so it was
never possible to reach the line "Otherwise, the user is an MIT mailing
list, and .."
2016-11-07 22:37:55 -08:00
Rishi Gupta
76c99eaf55 forms.py: Change variable names to be more specific.
No change to behavior.
2016-11-07 22:37:55 -08:00
Arpith Siromoney
fbe8171813 Typing indicators backend: Pass list of user ids to send_event
send_event() expects a list of user ids (ints) except for the special case
of messages. This commit:
1. Fixes this in the call to send_event() in do_send_typing_notification()
2. Renames the variables in do_send_typing_notification() to better reflect
their content (for example, recipient_ids instead of recipients).
3. Renames the id field in the dicts sent in the typing event body (sender,
recipients) to user_id.
4. Adds assertions to the tests to verify that the tornado event user ids
are the same as the recipients in the event body.
5. Adds assertions to the tests to verify that the tornado event user
ids and the recipient user ids (in the event body) are the same as the
expected user ids (obtained from the emails using
get_user_profile_by_email)
6. Changes all assertTrues to assertEquals in the tests

This fixes #2151.
2016-11-07 22:28:09 -08:00
Meena Rajan
30acb23314 bugdown: Add support for strikethrough in markdown processor.
[Tweaked to move tests to bugdown_data.json, add additional tests, and
add frontend processor support by tabbott]
2016-11-07 22:26:38 -08:00
Rishi Gupta
6e9e2cc05f Change datetime.now() to timezone.now() in various tests.
Good practice to use timezone-aware datetime objects unless there is a
reason to do otherwise.
2016-11-07 20:13:53 -08:00
Rishi Gupta
9e6e1a1e69 Remove several instances of datetime.datetime.utcnow().
Change to the timezone-aware django.utils.timezone.now() where django is
available.
2016-11-07 20:13:53 -08:00
Rishi Gupta
9e5ec2fd29 notifications.send_future_email: Use timezone aware times.
Previous behavior raises an AmbiguousTimeError during daylight savings hour!
2016-11-07 20:13:53 -08:00
Rishi Gupta
a416a9aeae test_runner.py: Fix "Import unexpectedly succeeded" messages in tests.
Previously we were getting this message whether or not the import would have
succeeded. The regression was introduced in ea050d5f.
2016-11-07 20:13:17 -08:00
umkay
ab2fd4ef3a TestAdminSetBackends: Supply dev_auth_enabled() with realm argument.
This fixes the fact that these tests were not correctly running
against the actual realm.
2016-11-07 17:07:05 -08:00
Tim Abbott
a8fdfccc83 docs: Fix echo.contains_bugdown docs being backwards. 2016-11-07 07:54:27 -08:00
paxapy
93965a8e89 Add tools for dumping and comparing markdown renderings.
This adds a couple new tools that can be used to determine whether a
particular change in Zulip's backend markdown processor would impact
the rendering of historical messages, without a human actually looking
at the message content.  This is a useful way to verify whether a
change to our markdown syntax is likely to create problems.

[commit message and code tweaked by tabbott]
2016-11-07 07:49:56 -08:00
Kevin Chen
6107c877e8 bugdown: Add option to support "file:///" as hyperlink.
This contains contributions from Tim Abbott and Igor Tokarev.

Fixes #380.
2016-11-06 22:30:05 -08:00
Tim Abbott
50382f153a requirements: Upgrade pillow to the latest version. 2016-11-06 20:52:04 -08:00
Igor Tokarev
d0f37b4c88 text_upload: Check only size in avatar test.
This fixes an issue that made it unpleasant to upgrade the version of
PIL used in Zulip.

Fixes: #1414
2016-11-06 20:49:11 -08:00
Igor Tokarev
07d05390bf markdown: Fix client usermention regular expression.
Fixes #993.
2016-11-06 18:37:09 -08:00
Tim Abbott
44767c59a2 Coverage: Exclude migrations and management commands.
These are not particularly interesting to measure test coverage for,
since migrations are not run as the part of the test suite by
construction, and management commands aren't being tested by this test
suite.
2016-11-06 18:34:23 -08:00
Tim Abbott
11518d9fb3 Remove test_ldap_auth_email_auth_disabled_failure for now.
This test was having order-dependent failures when run after
`test_signup`.
2016-11-06 18:34:22 -08:00
Tim Abbott
bb17e575c8 auth: Add SocialAuthMixinTest. 2016-11-06 18:07:52 -08:00
Tim Abbott
c856e56afc test_auth_backend: Add missing LDAP tests in FetchAPIKeyTest. 2016-11-06 18:07:52 -08:00
Tim Abbott
c94fe5bdef test_ldap: Fix spelling of tearDown method. 2016-11-06 16:33:20 -08:00
umkay
f4c621ffe3 admin: Enable admins to toggle supported auth methods via UI.
Add a table to the administration page that will allow realm admins to
activate and deactivate the supported authentication methods for that
realm.
2016-11-06 16:29:35 -08:00
umkay
21c024fc29 auth: Make supported authentication backends a bitfield on realm.
This makes it possible to configure only certain authentication
methods to be enabled on a per-realm basis.

Note that the authentication_methods_dict function (which checks what
backends are supported on the realm) requires an in function import
due to a circular dependency.
2016-11-06 16:16:24 -08:00
Tim Abbott
b41c15fa05 auth: Reject authentication if auth backends are disabled. 2016-11-06 16:16:22 -08:00
Tim Abbott
30ab27c843 auth: Separate email_auth_enabled from ldap_auth_enabled. 2016-11-06 16:16:16 -08:00
Tim Abbott
f8bb55f9c1 auth: Refactor auth backend enabled checking code. 2016-11-06 16:16:12 -08:00
Tim Abbott
3a3cee411d auth: Remove old password_auth_enabled hack.
This was used by an old configuration for zulip.com, which is no
longer in production use.
2016-11-06 14:50:15 -08:00
Tim Abbott
7c8d502c70 docs: Add details on our markdown change requirements. 2016-11-06 11:57:10 -08:00
Tim Abbott
1641d1952f docs: Add a section on changing Zulip's markdown. 2016-11-06 11:49:37 -08:00
Tim Abbott
70c00038d9 docs: Clarify our markdown docs.
This is just a cleanup and reorganization of some of the text; no
changes are made to the actual content.
2016-11-06 11:37:22 -08:00
hackerkid
bb4eb213c1 docs: Add testing notes to markdown doc. 2016-11-06 11:22:34 -08:00
Tomasz Kolek
704ac5aa6c Fix lint-all checker by adding "_" as a escape character before Github. 2016-11-05 22:12:25 -07:00
Steve Howell
debc06b449 Rename subject-name to topic-name and move CSS to left-sidebar.css. 2016-11-05 15:03:29 -07:00
Steve Howell
06fe4bc943 Rename subject_box to pm-box/topic-box.
I'm not crazy about the names pm-box and topic-box, but they
are less confusing now.
2016-11-05 15:03:29 -07:00
Steve Howell
43c372bfb6 css: Clean up styles for subject_box.
These styles are uniform for now, so we don't need a complicated
selector.
2016-11-05 15:03:29 -07:00
Steve Howell
e38b684eea Simplify CSS for topic-sidebar-arrow. 2016-11-05 15:03:29 -07:00
Steve Howell
b1f288dddb topic lists: Rename expanded_subject to topic-list-item. 2016-11-05 15:03:29 -07:00
Steve Howell
8b7e9101ca topic lists: Rename expanded_subjects -> topic-list. 2016-11-05 15:03:29 -07:00
Steve Howell
6fe86adac8 node tests: Add newer stylesheets for HTML output. 2016-11-05 15:03:29 -07:00
Tim Abbott
ee361cbe30 js: Eliminate process_loaded_for_unread global. 2016-11-05 11:33:04 -07:00
Tim Abbott
d60ec24c1f js: Move set_user_statuses to activity.js initialization. 2016-11-05 11:33:04 -07:00
Tim Abbott
6daf2b1e46 js: Move pointer initialization code out of zulip.js. 2016-11-05 11:33:04 -07:00
Tim Abbott
d76f9b09a3 unread: Move consider_bankruptcy into unread module. 2016-11-05 11:33:04 -07:00
Tim Abbott
be3e9e3a05 Fix regression breaking websocket message sending.
In fe1ba6f3eb, we change our auth
decorators etc. to use request.POST/request.GET rather than the (now
removed request.REQUEST).  This broke sending messages via our
websockets codepath, because we failed to update the artificial
requests we generate to use request._post as well.
2016-11-05 11:33:04 -07:00
Steve Howell
75dd822d8e tests: Improve coverage of cross-realm bot limitations.
We recently made it so that a cross-realm bot can only send
messages to one realm at a time.  (It can send to a realm
outside of its offical realm, but only one of them.)  This
test adds coverage for that.
2016-11-05 10:39:32 -07:00
Steve Howell
165b6c1ff3 topic lists: Improve node test to show HTML correctly. 2016-11-05 10:38:37 -07:00
Steve Howell
1119a24ea3 node tests: Extract node_tests/topic_list.js
This moves one method over from stream_list.js.  There's still a
lot of boilerplate here, unfortunately, as topic lists have a lot
of dependencies on other parts of the system--narrowing state,
muting state, jQuery, handlebars, etc.
2016-11-05 10:38:37 -07:00
Rishi Gupta
6544c756d6 forms.py: Reorder imports. 2016-11-05 10:37:15 -07:00
Rishi Gupta
5e6d4da8a8 realm creation flow: Prevent disposable email signups.
Check user's email address against a list of 2000 disposable email
domains. Does not affect the create_realm management command.
2016-11-05 10:37:15 -07:00
Rishi Gupta
2033381d24 realm creation flow: Restrict subdomains one can create via the web flow.
Disallow Realm.string_id's like "streams", "about", and several hundred
others. Also restrict string_id's to be at least 3 characters long, and only
use characters in [a-z0-9-].

Does not restrict realms created by the create_realm.py management command.
2016-11-05 10:37:15 -07:00
Tim Abbott
c6ceae868b requirements: Upgrade twisted, adding incremental and constantly.
Twisted 16.5.0 has a couple new dependencies.
2016-11-05 09:13:35 -07:00
Tim Abbott
be506d63f6 requirements: Upgrade a bunch of minor Python package versions.
These are all minor versions and thus shouldn't have any impact.
2016-11-05 09:13:28 -07:00
Rishi Gupta
e3646f28bd test_helpers.py: Fix default args for submit_reg_form_for_user.
Previously realm_name and realm_subdomain defalted to None, which when
posted to /accounts/register, are submitted as u'None'. "None" is an invalid
Realm.subdomain, since subdomains can't have capital letters.
2016-11-04 22:01:53 -07:00
Rishi Gupta
950831810b test_signup.py: Refactor test_create_realm_with_subdomain.
Refactor test_create_realm_with_subdomain to match test_create_realm more
closely, so that it's easier to see their similarities and differences.
2016-11-04 22:01:53 -07:00
Rishi Gupta
4db10a05de test_signup.py: Move test_create_realm_with_subdomain to correct place.
Before it was in UserSignUpTest, now it is in RealmCreationTest. The diff
makes it look like test_user_default_language is the target of the move,
but it isn't.
2016-11-04 22:01:53 -07:00
hackerkid
70223ef2da [third] Update marked base to newer version 0.3.6.
This basically re-applies the Zulip changes to marked 0.3.6.

Fixes #2190.
2016-11-04 21:56:53 -07:00
Tim Abbott
51fcf1fb7a tests: Fix spelling of test_transifex.py. 2016-11-04 21:49:39 -07:00
sonali0901
df4b777b35 tests: Fix handling of subdirs and backup files in test-backend.
Fixes #1950.
2016-11-04 21:49:23 -07:00
Mohsen Ibrahim
19b01d74fa bug fix: Send stream notifications to all users for public streams.
If a stream is public, we now send notifications to all realm users
if the name or description of the stream changes.  For private
streams, the behavior remains the same.

We do this by introducing a method called
can_access_stream_user_ids().

(showell helped with this fix)

Fixes #2195
2016-11-04 21:41:41 -07:00
Steve Howell
c405b67138 tests: Ignore SAVEPOINT queries in queries_captured().
We use the queries_captured() context manager in our tests
to capture queries that happen during certain actions.  Usually
we use the list of queries to validate that we're not doing
too many database calls.

For most tests the database calls are fairly deterministic,
but SAVEPOINT-related things seem to be more random, and the
number of savepoints is usually not relevant to what the test
is trying to prevent, which is more serious problems like
O(N) database fetches.
2016-11-04 21:30:36 -07:00
Steve Howell
e17cb79701 node tests: Remove compile-settings code from templates.js. 2016-11-04 21:23:35 -07:00
Steve Howell
6a1b53a195 node tests: Remove compile-settings code from i18n.js. 2016-11-04 21:23:35 -07:00
Steve Howell
dae53573cb node tests: Fix make_sure_all_templates_have_been_compiled().
This now searches subdirectories.
2016-11-04 21:23:35 -07:00
Steve Howell
3d0c0e2e81 node tests: Remove retry logic for compiling templates.
We can now use template_finder.get() to find the name we need.
2016-11-04 21:23:35 -07:00
Brock Whittaker
ee8d54db0f Change content to rely on data-* attribute.
Content now relies on the data-no-description attribute which then
allows for it to be embedded in HTML and therefore translatable.
2016-11-04 17:26:53 -07:00
Brock Whittaker
4400665a6d subs: Move stream settings into an independent overlay.
This replaces the scrolling stream settings feature with a stream
settings overlay.
2016-11-04 17:13:26 -07:00
Tim Abbott
78ec0341c4 subs: Fix color picker issue with subscribing. 2016-11-04 17:13:26 -07:00
Tim Abbott
73f020645f subs: Remove unnecessary update_stream_color call.
The color was already being updated in the response from the server.
2016-11-04 16:37:29 -07:00
Tim Abbott
a70c5eb923 colorpicker: Migrate to use stream IDs to access things. 2016-11-04 16:37:29 -07:00
Tim Abbott
ab6fd87161 subs: Fix rename stream handling of email addresses. 2016-11-04 16:37:29 -07:00
Tim Abbott
e6734bfada subs: Cleanup stream rename logic. 2016-11-04 16:37:29 -07:00
Tim Abbott
ee976a9bdc subs: Use subscription_settings when changing descriptions. 2016-11-04 16:37:29 -07:00
Tim Abbott
45c7945818 subs: Use sub_settings in subscriber add/remove flow. 2016-11-04 16:37:29 -07:00
Tim Abbott
8e522cd933 subs: Convert stream_home_view_clicked to use sub_settings. 2016-11-04 16:37:29 -07:00
Tim Abbott
2467f765ad subs: Stop using sub_row when rendering settings. 2016-11-04 16:37:29 -07:00
Tim Abbott
16408da823 subs: Cleanup change_stream_privacy.
We now:
(1) Only look up streams by ID

(2) Correctly look up both the stream-row and subscriptions_row after
the success handler returns.
2016-11-04 16:37:29 -07:00
Tim Abbott
32a571445a subs: Use settings_for_sub when redrawing privacy stuff. 2016-11-04 16:37:29 -07:00
Tim Abbott
b67c0a4ad5 subs: Move settings_for_sub and button_for_sub earlier. 2016-11-04 16:37:28 -07:00
Tim Abbott
b1a5d57405 subs: Update get_subscriber_list to use subscription_setings. 2016-11-04 16:37:28 -07:00
Tim Abbott
109287dceb subs: Update descriptions in settings separately from stream rows. 2016-11-04 16:37:11 -07:00
Tim Abbott
7a59ae591a subs: Fix get_stream_name to use IDs from the DOM.
We haven't added a data-stream-name to the subscription_settings
object yet, and ideally we'd be moving away from using
data-stream-name anywhere.
2016-11-04 16:16:07 -07:00
Brock Whittaker
cc03d2014d subs: Add missing li open/close tags.
Two elements were sharing the same li element, when they should be
in different elements.
2016-11-04 13:58:36 -07:00
Brock Whittaker
9b90a47fd6 Change .sub_settings_title to div.
All the properties they had weren’t being activated because they were
inline elements. Change to div to activate properties.
2016-11-04 13:55:11 -07:00
Brock Whittaker
7d51b6a454 subs: Create get_stream_name to get stream name from UI.
This accepts an arbitrary click target in the DOM inside a stream row
or stream settings element and returns the stream name.
2016-11-04 13:53:12 -07:00
Steve Howell
2088e8420f User user_id, not email, in peer_add events. 2016-11-04 11:37:14 -07:00
Steve Howell
c5c3dfe33f Add subscriber counts to changelog.md. 2016-11-04 11:37:14 -07:00
Steve Howell
17e39a88ef Remove people.test_set_people_name_dict().
We use a cleaner approach to setting up test data in echo.js to
allow us to remove the one call to test_set_people_name_dict().
2016-11-04 11:37:14 -07:00
Steve Howell
8c47f7f7db Remove people.test_set_people_dict(). 2016-11-04 11:37:14 -07:00
Steve Howell
472f049cae Alphabetize subscription event cases in server_events.js.
I also split up peer_add and peer_remove into their own cases,
since they do opposite things and didn't share that much code
in common.
2016-11-04 11:37:14 -07:00
Steve Howell
c3f2740481 Remove email_dict from gather_subscriptions_helper(). 2016-11-04 11:37:14 -07:00
Steve Howell
38f2789152 Remove page_params.email_dict. 2016-11-04 11:37:14 -07:00
Steve Howell
3941334d00 Use user_ids for subscribers in stream_data.js.
We still shim a lot of methods to keep using emails, but the
internal data structure now has user_ids.
2016-11-04 11:37:12 -07:00
Steve Howell
7509f73f02 Clean up stream renaming in the JS code.
We now use stream_id as our key to rename streams, which
should prevent a few race conditions long term.  (We are
still possibly contending with other events that use
stream_name as a key, so this is not perfect.)
2016-11-04 11:30:18 -07:00
Steve Howell
e1372ddf5d Add people.get_user_id(). 2016-11-04 11:30:18 -07:00
Steve Howell
4ace9bbd77 Remove dead code related to subs.create_sub().
Since we started handling the stream/create event properly,
create_sub() became dead code.
2016-11-04 11:30:18 -07:00
Steve Howell
2f4c7d2ef9 Clean up page_params initialization in node_tests/echo.js. 2016-11-04 11:30:18 -07:00
Steve Howell
4cd39010d1 Add people.get_person_from_user_id().
This requires the introduction of people_by_user_id_dict
and changes to people.add() and people.remove().
2016-11-04 11:30:18 -07:00
Steve Howell
a2874a3fe9 node tests: Simplify compiling of templates.
Now we just have two methods of importance:

    compile_template
    render_template

The compile_template() function will automatically
(and recursively) compile any partials it depends
on and mark those as compiled.
2016-11-04 11:23:11 -07:00
Steve Howell
0085164ad9 node tests: Avoid re-compiling templates.
This is a minor optimization to avoid re-compiling templates
that have already encountered.
2016-11-04 11:23:11 -07:00
Steve Howell
dd4a8eeebd node tests: Extract render.find_included_partials(). 2016-11-04 11:23:11 -07:00
Steve Howell
155f7881b2 node tests: Extact template_finder() class. 2016-11-04 11:23:11 -07:00
Steve Howell
61d88cfc13 node tests: Use template_dir() to walk templates. 2016-11-04 11:23:11 -07:00
Tim Abbott
945c2c4f86 docs: Add a brief release checklist. 2016-11-04 10:52:48 -07:00
Umair Khan
fe1ba6f3eb Django 1.10: Deprecate request.REQUEST. 2016-11-04 10:20:24 -07:00
Umair Khan
dd314b3796 Django 1.10: context_processors have been moved to django.template. 2016-11-04 10:20:24 -07:00
Umair Khan
682aa1f298 Django 1.10: Use add_argument for options in BaseCommand. 2016-11-04 10:20:23 -07:00
Umair Khan
d3a4fa3e94 Django 1.10: Add Python Social Auth to Installed Apps. 2016-11-04 10:20:23 -07:00
Umair Khan
4c07e57b43 Django 1.10: Use lru_cache instead of memoize. 2016-11-04 10:20:23 -07:00
Umair Khan
b140236fcf Django 1.10: Do not use patterns function. 2016-11-04 10:06:00 -07:00
Umair Khan
d81446805c Django 1.10: Use caches object to access cache. 2016-11-04 10:06:00 -07:00
Umair Khan
b1d740afaa Django 1.10: Remove generic module 2016-11-04 10:06:00 -07:00
Steve Howell
9b97b5da13 Improve test coverage for people.get_recipient_count(). 2016-11-04 10:05:11 -07:00
Brock Whittaker
4c4733bcec Change logo/type on left sidebar column.
This changes to a new logo/type on the left sidebar column.
2016-11-03 18:12:00 -07:00
Tim Abbott
cb1bc70ab0 css: Set only message overflow-x to auto.
This fixes a nasty problem where if you zoomed in Chrome, you'd get
little scrollbars on every message body.
2016-11-03 18:09:36 -07:00
umkay
c43a15ed18 api: Add default protocol for localhost.
Add default "http://" to site argument locally if it is not specified
in an api call.

This fixes a problem where if you didn't manually specify `http://`
when connecting to a development server, the API bindings would hang
trying to connect using HTTPS.
2016-11-03 18:09:26 -07:00
Tim Abbott
368b585980 subs: Redesign the rows of the #subscriptions table. 2016-11-03 17:33:33 -07:00
umkay
e6ac8c3543 analytics: Add extra count stats.
Fill in remaining countstats in counts.py for our intended use cases.
2016-11-03 16:50:39 -07:00
umkay
298890d125 analytics: Rename count stats and associated properties.
Our current naming convention is getting unwieldy. The subgroup now goes
on the right side of the colon.
2016-11-03 16:50:39 -07:00
umkay
5490442580 analytics: Replace all joins in raw SQL with natural joins.
We alter the behavior of our queries to no longer write rows with 0 counts
to the db, and pad with 0s in the related views code. As a result we are
also able to combine the where and join clause conditions in the sql
queries. This new behavior is also updated in our tests.
2016-11-03 16:50:39 -07:00
umkay
b5b8623f46 analytics: Update linter to ignore interpolation in test_counts.
Ignore whitespace error for % interpolation in sql queries.
2016-11-03 16:50:39 -07:00
Steve Howell
e4930d73c4 Add user_id for new users who we discover in new messages.
This change also creates a copy of the objects so that we
don't couple ourselves to the message store.
2016-11-03 16:20:45 -07:00
Steve Howell
30e01306d9 Eliminate people.reify() and mostly ignore unknown users.
If I try to send a message to an unknown user (which is possible
for some types of realms), then I simply ignore them during the
send codepath, so that I don't later need to patch up their attributes.
2016-11-03 16:20:45 -07:00
Steve Howell
15d44f8d71 Encapsulate pm_recipient_count.
We no longer store pm_recipient_count on person objects, but we
instead use a Dict to store them.  Then the new API is this:

    people.get_recipient_count()
    people.incr_recipient_count()
2016-11-03 16:20:45 -07:00
sinwar
67d99c536a docs: change zulip.tabbott.net to chat.zulip.org 2016-11-03 16:07:59 -07:00
Rishi Gupta
4a74301a62 models.py: Replace resolve_subdomain_to_realm with get_realm_by_string_id.
No change in functionality.
2016-11-03 13:59:11 -07:00
Rishi Gupta
655940acaf create_realm.py: Add basic checks to name and subdomain.
Don't allow the empty string for organization name, and don't pass
do_create_realm a subdomain that's already taken.
2016-11-03 13:59:11 -07:00
Tim Abbott
dd008ae559 realm creation flow: Allow signups from all emails.
This (1) removes the check on whether the domain of the email matches
the Realm.domain of an existing realm and (2) avoids setting `realm =
get_realm(domain)` in the realm creation flow, which would cause the
wrong code path to be followed in the event that the domain in a
user's email address happens to match a deactivated realm.
2016-11-03 13:58:52 -07:00
Rishi Gupta
1944ac844a RealmAlias: Drop uniqueness constraint when REALMS_HAVE_SUBDOMAINS.
Removes the uniqueness constraint on RealmAlias.domain, and adds a function
can_add_alias that checks for uniqueness conditional on
settings.REALMS_HAVE_SUBDOMAINS.
2016-11-03 13:53:01 -07:00
Rishi Gupta
e4334f4735 do_create_realm: Remove domain argument from do_create_realm.
The domain argument was being used in do_create_realm to create a
RealmAlias. Callers are now responsible for creating a RealmAlias
when desired.
2016-11-03 13:53:01 -07:00
Rishi Gupta
4b60e06991 realm creation flow: No longer create RealmAlias's during sign-up flow.
There are a number of situations in which we will want to automatically
create one, but we should be a bit thoughtful about when we do so.
2016-11-03 13:53:01 -07:00
Rishi Gupta
c0f1b5d9f6 Change Realm defaults to Community defaults.
Previously, we set restrict_to_domain and invite_required differently
depending on whether we were setting up a community or a corporate
realm. Setting restrict_to_domain requires validation on the domain of the
user's email, which is messy in the web realm creation flow, since we
validate the user's email before knowing whether the user intends to set up
a corporate or community realm. The simplest solution is to have the realm
creation flow impose as few restrictions as possible (community defaults),
and then worry about restrict_to_domain etc. after the user is already in.

We set the test suite to explictly use the old defaults, since several of
the tests depend on the old defaults.

This commit adds a database migration.
2016-11-03 13:53:01 -07:00
Tim Abbott
08ce391611 register: Fix using subdomains logic when subdomains is disabled. 2016-11-03 13:51:50 -07:00
Tim Abbott
fa6aafd0a5 test_signups: Fix test_completely_open_domain.
This test seems intended to verify registration in the case of a
unique completely open domain; but because of the mit.edu realm, it
instead tested that a logic bug in the non-subdomains case was
present.
2016-11-03 13:44:51 -07:00
Tim Abbott
9f86638ce5 test_signups: Cleanup open realm registration tests.
This removes some confusing comments and unnecessary use of subdomain
logic.
2016-11-03 13:44:43 -07:00
Tim Abbott
9b6c199538 tests: Fix need for Internet to run backend test suite.
A few places where we weren't using mock.patch to mock out Hesiod
(DNS) queries have crept in.
2016-11-03 13:41:54 -07:00
Tim Abbott
90f57c92d4 compute_mit_user_fullname: Fix result for Python 3.
DNS replies are bytes, and usernames are strings.
2016-11-03 13:40:43 -07:00
K.Kanakhin
c89a2ffe2f Add raised exception output to development tornado running.
Replaces the default tornado ioloop tracback exception handler in
debug mode to add output for exceptions to the logging.

Fixes #2150.
2016-11-03 11:16:12 -07:00
Tim Abbott
a93530e413 Remove unused route for development tornado proxy server.
This was a duplicate of the other sockjs line.
2016-11-03 10:46:18 -07:00
Tomasz Kolek
9026f56713 Improve English grammar in bitbucket integration modify comment message.
Add `a` between verb and comment word i.e. updated a [comment] instead of
updated [comment].
2016-11-03 10:18:46 -07:00
deekshaarul
3f5ef8df9e docs: Fix typos in git guide. 2016-11-03 10:12:03 -07:00
Umair Khan
4502872e8e subdomain: Test user registration through Google OAuth. 2016-11-03 10:09:24 -07:00
Steve Howell
9b04ec7472 Send dicts for cross realm users to JS.
We now send dictionaries for cross-realm bots.  This led to the
following changes:

* Create get_cross_realm_dicts() in actions.py.
* Rename the page_params field to cross_realm_bots.
* Fix some back end tests.
* Add cross_realm_dict to people.js.
* Call people.add for cross-realm bots (if they are not already part of the realm).
* Remove hack to add in feedback@zulip.com on the client side.
* Add people.is_cross_realm_email() and use it in compose.js.
* Remove util.string_in_list_case_insensitive().
2016-11-03 09:51:23 -07:00
Steve Howell
af6512e782 Add feedback bot to the test database. 2016-11-03 09:42:27 -07:00
Steve Howell
6324fe9ddf Rename get_cross_realm_users to get_cross_realm_emails. 2016-11-03 09:42:27 -07:00
Tim Abbott
50361ca980 test-run-dev: Fix buggy site argument.
This bug was exposed by 9578908601.
2016-11-03 09:34:56 -07:00
Tim Abbott
bfff9e1968 do_send_messages: Fix sending messages to feedback-bot.
This feature was broken in the message_to_dict refactoring.
2016-11-02 23:42:05 -07:00
Tim Abbott
ebe959f2b0 tutorial: Remove low-quality alert bar onboarding flow.
This alert bar thing was buggy and didn't look that good, so let's
just remove it.  We can always write a nicer thing advertising the
desktop app later.
2016-11-02 23:41:16 -07:00
Tim Abbott
2506c691b8 css: Fix alert-bar-container CSS blocking "Home" button.
Because the alert-bar-container had the full width of the page, it's
higher z-index caused it to break clicking on things.
2016-11-02 23:41:16 -07:00
Tim Abbott
2e65dc1206 puppet: make check_send_receive_time target host configurable. 2016-11-02 23:40:53 -07:00
Tim Abbott
9578908601 check_send_receive_time: Stop hardcoding EXTERNAL_API_URI. 2016-11-02 23:35:08 -07:00
Tim Abbott
8f779056e1 register: Improve password strength meter display.
This previously didn't handle the new grid layout particularly well.
2016-11-02 23:34:55 -07:00
Tim Abbott
c2b7e7e57c register: Move password form before team creation.
This makes the flow more intuitive, since the user sets a password
with the other parts of the form where they are configuring their own
account (as opposed to configuring the organization they are
creating).
2016-11-02 23:34:13 -07:00
Rishi Gupta
70c29d8f90 do_create_realm: Remove "(open realm)" indication in sign-up message.
In preparation for a change to do_create_realm where we will use the
database default for restricted_to_domain rather than computing it within
do_create_realm, and due to which do_create_realm will no longer know
whether we are creating an open realm or not.
2016-11-02 22:46:34 -07:00
Rishi Gupta
db0e509422 do_create_realm: Replace domain argument with string_id.
Turns string_id into a required argument, and domain into an optional
argument.
2016-11-02 22:46:34 -07:00
Rishi Gupta
c1bbd8d70d models.py: Add get_realm_by_string_id to assist with Realm.domain migration.
Step 0 of a two step process:

1. Replace all occurances of get_realm(domain) with
   get_realm_by_string_id(string_id)

2. Rename get_realm_by_string_id to get_realm.
2016-11-02 22:46:34 -07:00
Rishi Gupta
b3c018f55c register.html: Clean up spacing and a few long lines.
Also re-fills the two large paragraphs to a slightly larger width.
2016-11-02 22:46:34 -07:00
Rishi Gupta
9ef8536cc6 models.Realm: Require Realm.string_id to be non-NULL.
Adds a database migration, adds a new string_id argument to the management
realm creation command, and adds a short name field to the web realm
creation form when REALMS_HAVE_SUBDOMAINS is False.
2016-11-02 22:46:34 -07:00
Rishi Gupta
64bcd71d6e models.Realm: Rename subdomain to string_id.
Does a database migration to rename Realm.subdomain to
Realm.string_id, and makes Realm.subdomain a property.  Eventually,
Realm.string_id will replace Realm.domain as the handle by which we
retrieve Realm objects.
2016-11-02 22:46:34 -07:00
Tomasz Kolek
4dd8cd9879 Replace "Commit" to commits sha in commits comment events in git integrations. 2016-11-02 22:19:51 -07:00
Tomasz Kolek
ce5bb22ace Normalize comment commit event in github integration. 2016-11-02 22:19:51 -07:00
Tomasz Kolek
6ad4cce35c Add object number/id to mention about Issue, PR, etc. to all git integrations. 2016-11-02 22:19:51 -07:00
Tomasz Kolek
762b6b5817 Add on betwen comment action and noun in comments messages from git integrations.
Improve English grammar in comment messages in git integrations
by adding 'on' between comment action and noun (PR, Issue, Commit).
2016-11-02 22:19:51 -07:00
Tomasz Kolek
cbd05eb0b2 Normalize bitbucket commit, PR and issues comment event's subject and content. 2016-11-02 22:19:51 -07:00
Tomasz Kolek
ef6a1328ce Normalize gitlab snippet or commit comment event's subject and content. 2016-11-02 22:19:51 -07:00
Tomasz Kolek
4fc1488edc Normalize gitlab issue or MR comment event's subject and content. 2016-11-02 22:19:51 -07:00
Steve Howell
6659664e59 Simplify/fix cross-realm validation in recipient_for_emails().
We now simply exclude all cross-realm bots from the set of emails
under consideration, and then if the remaining emails are all in
the same realm, we're good.

This fix changes two behaviors:
* You can no longer send a PM to an ordinary user in another realm
  by piggy-backing a cross-realm bot on to the message.  (This was
  basically a bug, but it would never manifest under current
  configurations.)
* You will be able to send PMs to multiple cross-realm bots at once.
  (This was an arbitrary restriction.  We don't really care about this
  scenario much yet, and it fell out of the new implementation.)
2016-11-02 22:10:49 -07:00
Steve Howell
497b8e8bc4 Make tests explicit about cross-realm loophole.
We can currently send a PM to a user in another realm, as long
as we copy a cross-realm bot from the same realm.  This loophole
doesn't yet affect us in practice--all cross-realm bots are
generally configured for the "admin" realm like the old zulip.com--
but we should lock it down in a subsequent commit.
2016-11-02 22:10:49 -07:00
Steve Howell
7d50598454 Test that non-zulip.com users can't PM random zulip.com users. 2016-11-02 22:10:49 -07:00
Steve Howell
45f9a60bc0 Add test coverage for talking to two cross-realm bots. 2016-11-02 22:10:49 -07:00
Steve Howell
067090d93e Test that we can send PMs to non-zulip cross-realm bots. 2016-11-02 22:10:49 -07:00
Steve Howell
7724dba08b Explicitly use the "feedback" bot in test_realm_scenarios.
(I'm about to create a more abstract cross-realm bot, but I think
concretely referring to feedback bot is helpful here.)
2016-11-02 22:10:49 -07:00
Steve Howell
517f7f672f Clean comments/whitespace in test_realm_scenarios(). 2016-11-02 22:10:49 -07:00
Steve Howell
94f53543e6 Test that users can PM themselves in test_realm_scenarios.
(This is probably tested elsewhere too, but it's helpful in the
context of testing cross-realm stuff to assert basic rules like
this.)
2016-11-02 22:10:49 -07:00
Steve Howell
7a127148db Add assert_message_received() to test_realm_scenarios. 2016-11-02 22:10:49 -07:00
Steve Howell
b9bf74d54e Reorganize sections of test_realm_scenarios().
This change groups the positive scenarios together
and likewise for the negative scenarios.
2016-11-02 22:10:49 -07:00
Steve Howell
49c64bd7cb Consolidate cross-realm message tests.
Having each condition in a separate test was confusing to read,
especially since the tests were doing inconsistent setup, sometimes
calling user2 the user from 2.example.com realm and other times
calling user2 the cross-bot realm, etc.
2016-11-02 22:10:49 -07:00
Brock Whittaker
1432c6613b zjsunit: Remove manual need to call global.use_template.
When the render function is run now, it uses the partial_finder
function to search recursively through files for partials and add them
so that test writers don’t have to.

This means that we no longer have to do any manual work to maintain
the templates.js check that all handlebars templates are rendered by
the node tests.
2016-11-02 22:08:47 -07:00
Rishi Gupta
a3400a6862 casper tests: Keep var/casper/server.log till it has 100kb.
Previously, var/casper/server.log was overwritten before every run of
run-casper. This commit implements the simplest form of log rotation,
by overwriting server.log only if it has more than 100kb.
2016-11-02 22:04:16 -07:00
sonali0901
f9f0f29298 casper: Add support for passing just the test number to run a test.
Fixes #2178.
2016-11-02 21:38:42 -07:00
umkay
0e0a11bb5e Refactor GitHub authentication backend tests. 2016-11-02 21:06:17 -07:00
Rishi Gupta
a2b6793174 message_edit.js: Put cursor at end of input on initial focus. 2016-11-02 20:54:54 -07:00
Rishi Gupta
5251460eda message_edit.js: Remove edit_row from edit_message.
I believe row.find(..) and edit_row.find(..) are the same in all these
cases.
2016-11-02 20:54:54 -07:00
Rishi Gupta
8104485c41 message_edit.js: Refactor how edit_message accesses elements.
Currently, message_edit.edit_message accesses elements of
message_edit_form.handlebars by a number of different means, and in a number
of different places. This commit is the first of two that standardizes it.
2016-11-02 20:54:54 -07:00
Umair Khan
0eff88ec2d Test registration of mirror dummy user.
Tweaked by tabbott to do the from_confirmation=1 call.
2016-11-02 18:17:29 -07:00
Umair Khan
dd0c4ca0bc Test registration using POPULATE_PROFILE_VIA_LDAP. 2016-11-02 17:50:40 -07:00
Umair Khan
f300c12535 Accept from_confirmation kwarg in submit_reg_form_for_user. 2016-11-02 17:50:40 -07:00
Umair Khan
99f4174894 Test special registation link for completely open realms. 2016-11-02 17:50:39 -07:00
Umair Khan
8ff2cd3fd7 Only allow proper url for registration.
This commit fixes a bug which occurs when a user tries to bypass the
correct registration url for the completely open domains.
2016-11-02 17:49:30 -07:00
Rishi Gupta
9ed45eb4a1 message_edit.js: Change disabled fields to readonly to allow copying text.
Previously we disabled fields in message_edit_form.handlebars that you
couldn't edit. This meant you could see the content of the field, but not
copy it. This commit marks those fields as readonly instead.
2016-11-02 17:49:04 -07:00
deekshaarul
05d252da71 compose.js: Add translation tag to empty_topic_placeholder.
Moves the variable definition from the top of the file to inside the export
since i18n seems not be loaded at the time the file is parsed.
2016-11-02 17:46:32 -07:00
deekshaarul
6624d4e56e message_edit.js: Fix message editing behavior around empty topics.
Previously,
* We displayed "(no topic)" in .message_edit_topic when there was no
  topic;this commit changes that to a placeholder.

* We showed the .message_edit_topic_propagate dropdown when the user
  cleared .message_edit_topic, despite the fact that one cannot save
  or propagate an empty topic. This commit fixes the behavior.

Fixes #1273.
2016-11-02 17:45:23 -07:00
Tim Abbott
c8f80f6d53 gitignore: Ignore sublime text project files. 2016-11-01 23:23:16 -07:00
K.Kanakhin
b248a2c33e docs-test: Check only http 404 error for external links.
- Raise exception only for http 404 error rensponse, for other
  http error codes used logging to notify devs about wrong links.
2016-11-01 21:45:41 -07:00
Tim Abbott
9aa346db71 css: Remove unnecessary share-the-love-title class. 2016-11-01 21:32:57 -07:00
trueskawka
977339954c css: Create a separate file for left-sidebar CSS.
Create a new file left-sidebar.css.
Move all left-sidebar CSS from zulip.css to left-sidebar.css.
2016-11-01 21:32:57 -07:00
Tim Abbott
bf1a7a7f2d test_bugdown: Fix misplaced type annotation. 2016-11-01 20:40:22 -07:00
K.Kanakhin
870de03ede run-dev: Add websockets support to tornado dev proxy server.
Fixes #1036.
2016-11-01 20:35:31 -07:00
K.Kanakhin
09e17fbe17 run-dev: Use tornado for dev proxy server for HTTP requests.
- Use tornado as proxy server for development environment,
  replacing twisted (this doesn't support websockets).
- Upgrade tornado version to 4.4.1 (needs to be coupled to the
  above since neither change works without the other)
2016-11-01 20:35:31 -07:00
Tim Abbott
6a8f8c2abf run-dev: Fix minor whitespace issues. 2016-11-01 20:27:44 -07:00
paxapy
2f711a070d bugdown: Add autocomplete for #StreamName links.
Fixes #1858.
2016-11-01 20:19:44 -07:00
Tim Abbott
acf43f91fa composebox_typeahead: Improve whitespace. 2016-11-01 20:15:57 -07:00
Tim Abbott
6c96f3f2c7 composebox_typeahead: Refactor @mentions logic to not block #streams. 2016-11-01 20:15:57 -07:00
Tim Abbott
fe2aab7571 composebox_typeahead: Remove last_at variable. 2016-11-01 20:06:34 -07:00
Tim Abbott
ae336ce8b5 composebox_typeahead: Extract autocomplete_checks. 2016-11-01 20:06:03 -07:00
paxapy
1d1c41551b bugdown: Auto-linkify #StreamName. 2016-11-01 19:59:21 -07:00
paxapy
d965ff16fd bugdown: refactor AutoLink to use VerbosePattern.
This makes it possible to reuse the verbose pattern logic for other
regexs as well.
2016-11-01 19:50:59 -07:00
Steve Howell
a0dadfd40a Widgetize topic_list.set_count().
This change makes most of the logic on set_count() live
on our per-stream topic list widget.  We can find the
jQuery object directly now rather than using the
complicated iterate_to_find() method.
2016-11-01 19:30:41 -07:00
Steve Howell
b7b6fedf12 Widgetize activate_topic() in topic_list.js.
The activate_topic() function now lives on the object created
by build_widget().
2016-11-01 19:30:41 -07:00
Steve Howell
8c9488a904 Add topic_list.build_widget().
This gets us closer to a component model for topic lists.
2016-11-01 19:30:41 -07:00
Steve Howell
eacaa37754 Make update_count_in_dom() be private in topic_list.js.
I also moved the function in the file to be nearer to other
non-stream specific functions.
2016-11-01 19:30:41 -07:00
Steve Howell
aca6ba182e Render topic list items individually.
This is a precursor to being able to find topic list
items without the complexity of iterate_to_find().
2016-11-01 19:30:41 -07:00
umkay
5e5a0d4db9 analytics: Add user-level count query for messages sent to {PMs, streams}.
Adds a count_X_by_Y_query to counts.py, similar in spirit to a
count_recipient_by_user query, where we would join on the Message,
Recipient, and UserProfile table. Here, we also join on the Stream table in
order to distinguish private and public streams, and we merge the counts for
PM and Huddle type messages into a single subgroup.
2016-11-01 17:00:43 -07:00
umkay
a94599fca7 analytics/models.py: Add subgroup column to unique_together constraints. 2016-11-01 16:53:56 -07:00
Steve Howell
148e1e6add subs: Avoid duplicate prepend_subscriber() call.
We don't want to prepend new subscribers to our list of
subscribers in the settings page when they hit enter; we
want to wait till we get the event from the server.

This is a fairly new regression that was added when we
live-updated peer subscriber changes.
2016-11-01 14:01:29 -07:00
Steve Howell
a126be3db6 Call add_in_realm() when loading people from page_params. 2016-11-01 13:55:48 -07:00
Steve Howell
d70ac2fc0d Remove obsolete code for page_params.people_list.
The only module that uses people_list now is people.js, and that's
only during the page load process.
2016-11-01 13:55:48 -07:00
Steve Howell
758c040558 Make stream-invite typeahead more dynamic and accurate.
The typeahead for inviting users to an existing stream now
uses a function, not a static list, and it now only shows
users from your realm.
2016-11-01 13:55:48 -07:00
Steve Howell
aadc198510 Make PM typeaheads more dynamic.
We now set source as a function, not a static list, and we grab
persons from people.get_all_persons() instead of page_params.
2016-11-01 13:55:48 -07:00
Steve Howell
40ec0189e4 Use people.get_all_persons() in at-mention typeaheads.
This is more robust than using page_params.people_list.
2016-11-01 13:55:48 -07:00
Steve Howell
06d7012113 Use people.get_all_persons() for search_suggestion.js.
This is better than using page_params.people_list, which may
go out of sync when live updates happen.
2016-11-01 13:55:48 -07:00
Steve Howell
2d945d7296 Add people.get_realm_persons(). 2016-11-01 13:55:48 -07:00
Steve Howell
aa07b32d58 Add people.get_all_persons(). 2016-11-01 13:55:48 -07:00
Steve Howell
a9e851b646 Load people.js earlier during startup.
Lots of things depend on people.js, whereas people.js basically only
depends on page_params and core modules like dict.js.
2016-11-01 13:55:48 -07:00
Tim Abbott
d22a06ee90 docs: Fix a missing close paren. 2016-11-01 12:32:36 -07:00
Tim Abbott
1bae9d10e3 docs: Improve wording details in the new realm document. 2016-11-01 10:50:06 -07:00
hackerkid
1e409032bd docs: Add subsystem section discussing realms and subdomains. 2016-11-01 10:49:47 -07:00
Brock Whittaker
25b28bf82c Fix inline code lines that are too long in .message_content.
The issue is that if you post a very long line of code it will overflow
the .message_content div and force the width of the main message page
to be as long as the line of code.

Fixes: #2156
2016-10-31 17:17:17 -07:00
Brock Whittaker
9ad27b3e69 Reorder CSS Files to fix compose box issues.
The media queries should always be last in the pipeline to be delivered
so that other styles don’t override them.
2016-10-31 17:17:17 -07:00
Brock Whittaker
d49076d0d4 Add @media query for mobile muting UI.
This adds a media query so that the muting UI on mobile displays
correctly.

Fixes: #2149.
2016-10-31 17:17:17 -07:00
Tim Abbott
1bc9be7aed subs: Fix stream privacy changes not working after renaming.
This fixes and issue where the change_stream_privacy template had its
own duplicate copy of the data-stream-name attribute, which wasn't
updated when streams were renamed.

Fixes #2016.
2016-10-28 16:42:32 -07:00
Tim Abbott
6927a9bdc4 subs: Update subscription settings data when renaming streams. 2016-10-28 16:41:54 -07:00
Tim Abbott
0185764be7 subs: Fetch stream name from data-stream-name. 2016-10-28 16:12:50 -07:00
Tim Abbott
9507ed8a05 subs: Move show_settings_for earlier in file. 2016-10-28 16:10:59 -07:00
Tim Abbott
c10fd243f1 subs: Rename subscriber_count class to subscriber-count.
Also remove the unused subscriber-count-row class.
2016-10-28 16:07:28 -07:00
Tim Abbott
c0a774ef8c subs: Remove use of $-based variable names. 2016-10-28 16:07:02 -07:00
Tim Abbott
56c9be75ee subs: Add data-stream-name for stream settings. 2016-10-28 16:07:02 -07:00
Tim Abbott
76cd40eb9d subs: Remove now-unused subscription_{{stream_id}}. 2016-10-28 16:07:02 -07:00
Tim Abbott
b8304c3359 subs: Find elements using the new data-stream-id value.
This is preparation for no longer having the subscription inside the
subscription_row object.
2016-10-28 16:06:40 -07:00
Tim Abbott
3727ea6fb0 subs: rename .subscription_description to .description. 2016-10-28 14:47:23 -07:00
Tim Abbott
dd2fab9374 subs: Rename data-subscription-id to data-stream-id. 2016-10-28 14:47:23 -07:00
Tim Abbott
66e2632809 subs: Rename .subscription_name to .stream-name. 2016-10-28 14:47:22 -07:00
Tim Abbott
f18d53d46a subs: Rename .subscription_row to .stream_row.
The new name is clearer, since we show these rows for streams whether
or not you're subscribed.
2016-10-28 14:25:00 -07:00
Brock Whittaker
2bf2468ffe css: Namespace buttons in components.css.
This namespaces components.css to not conflict with the existing CSS of
the rest of the site.
2016-10-28 14:14:52 -07:00
Brock Whittaker
38f7349771 components: Add .tab-switcher component.
This adds the .tab-switcher component to components.css.
2016-10-28 14:04:38 -07:00
Brock Whittaker
1562f9fe76 lightbox: Fix Z-Index for Proper Ordering.
This fixes the z-index of the lightbox overlay, which previously
appeared behind the header, and the muting notification to be above
everything else on the page.
2016-10-28 13:57:37 -07:00
Steve Howell
eb64b32bc8 Fix "subjects" in JS comments. Say "topics" instead. 2016-10-28 13:52:25 -07:00
Steve Howell
5fd71a6381 Rename var in sidebar_subject_list.handlebars.
s/subjects/topics/
2016-10-28 13:52:25 -07:00
Steve Howell
dba3ed3d90 Rename variables in topic_list.build_list().
(s/subjects/topics/ in a couple places)
2016-10-28 13:52:25 -07:00
Steve Howell
78861d4e01 Rename recent_subjects to recent_topics. 2016-10-28 13:52:25 -07:00
Steve Howell
0a4579711d Add stream_data.get_recent_topics().
This removes the last remaining references to
stream_data.recent_subjects() outside of stream_data.js.
2016-10-28 13:52:25 -07:00
Steve Howell
6a54dfc127 Remove recent_subjects from node tests.
We now use stream_data.populate_stream_topics_for_tests(),
which hides some of the implementation details of initializing
the data structure.
2016-10-28 13:52:25 -07:00
Steve Howell
8acdf718bc Move process_message_for_recent_topics() to stream_data.js. 2016-10-28 13:52:25 -07:00
Steve Howell
c799ac3126 Extract stream_data.is_active(). 2016-10-28 13:51:21 -07:00
Steve Howell
ecbd77d8a5 Flip conditional in stream_list.add_sidebar_li(). 2016-10-28 13:51:21 -07:00
Steve Howell
403490a95b annotations: Fix to_non_negative_int(). 2016-10-28 13:48:44 -07:00
Steve Howell
7111bb1744 Deprecate /json/streams.
Note that we still need the equivalent function in our
user-facing API, so there is not much code removal yet.
(Also, we will probably always keep this in our API,
as bot authors will usually just want a simple endpoint
here, whereas our client code gets page_params and events.)
2016-10-28 13:44:46 -07:00
Steve Howell
15602ee6bb Stop using /json/streams on the client.
We no longer need to fetch streams from the server when
we render the settings page.

The name populate_and_fill() may not be a great name any
more.
2016-10-28 13:44:46 -07:00
Steve Howell
10bc093375 Stop using server data to draw "Manage Streams".
We have all the data we need on the client side.
2016-10-28 13:44:46 -07:00
Steve Howell
9d4debd1eb Live-update added/removed subscribers. 2016-10-28 13:43:09 -07:00
Steve Howell
768a04d2fa Send user_ids for update events.
Here we handle a few flavors of realm_bot/update
and realm_user/update.  (Different events send different
attributes.)
2016-10-28 13:40:14 -07:00
Steve Howell
3fd7ab950a Send user_id to the client when removing bots/users.
This touches these events:

    realm_bot/remove
    realm_user/remove
2016-10-28 13:40:14 -07:00
Steve Howell
7883cecf28 Send user_id to the client in more places.
This commit touches:

    realm_bot/add
    realm_user/add
    page_params.bot_list
    page_params.people_list
2016-10-28 13:40:14 -07:00
Tim Abbott
4fe5fc849e travis: Disable test-documentation temporarily. 2016-10-28 11:27:22 -07:00
Tim Abbott
eceaf36001 setup_disks: Fix postgres RAID setup to work correctly on Xenial.
Nobody's going to run this on Wheezy again.
2016-10-28 11:04:08 -07:00
Tim Abbott
1a88ca4da1 queue_processors: Fix feedback bot sender.
This fixes an issue where emails sent by feedback-bot had a forged
sender and thus sometimes had delivery issues.
2016-10-28 11:04:08 -07:00
Umair Khan
4cf7040100 subdomains: Use redirect_and_log_into_subdomain for registration.
This fixes a bug where the user who registered a new organization
wasn't correctly logged into that organization.
2016-10-28 11:04:08 -07:00
Umair Khan
2dabfc562c subdomains: Add tests for single domain OAuth2. 2016-10-28 11:04:08 -07:00
Umair Khan
26646abe8c Authenticate subdomains using single Google OAuth entry.
Previously, we used to create one Google OAuth callback url entry
per subdomain. This commit allows us to authenticate subdomain users
against a single Google OAuth callback url entry.
2016-10-28 11:04:08 -07:00
Tim Abbott
7a02ed42e7 requirements: Move fakeldap to dev.txt. 2016-10-28 11:04:08 -07:00
Umair Khan
d139c9cb71 Add tests for maybe_send_to_registration function. 2016-10-28 09:27:56 -07:00
Umair Khan
8064ed1c0b Add test for ZulipRemoteUserBackend. 2016-10-28 09:27:56 -07:00
Umair Khan
839cab3434 Add tests for GitHubAuthBackend. 2016-10-28 09:27:56 -07:00
Umair Khan
b6046bc77e Add tests for password_auth_enabled function. 2016-10-28 09:27:56 -07:00
Umair Khan
d9e1975d2c Add ZulipAuthMixin tests. 2016-10-28 09:27:56 -07:00
Umair Khan
6dbe425675 Add Google OAuth2 backend tests. 2016-10-28 09:27:56 -07:00
Umair Khan
088d8eebad Add ZulipLDAPUserPopulator test. 2016-10-28 09:27:56 -07:00
Umair Khan
50422e775b Add LDAP tests. 2016-10-28 09:27:55 -07:00
Umair Khan
ccc1f3861f Fix return value logic of ZulipLDAPAuthBackend.get_or_create_user.
The actual logic is that if the user already exists than the
function should return a False and if the user does not exist
the function should first create the user and return True.
2016-10-28 17:47:20 +05:00
K.Kanakhin
78b1b80987 caching: Add configuration class for post-migration cache flushing.
- To avoid redefining migrate manage command is added new application
  configuration class which emit post_migration signal. This signal
  require models module inside application and defined AppConfig
  Instance as signal sender.  Documentation here:
  https://docs.djangoproject.com/en/1.8/ref/signals/#post-migrate.
- Add AppConf subclass to __init__ zerver app file to make apllication
  load it by default.

Fixes #1084.
2016-10-27 23:26:34 -07:00
Tim Abbott
c6f7b786a6 css: Fix problems selecting the first item in gear menu.
Fixes a regression introduced in
08b61c1b3d, where .alert-bar-container
would be above the menu, and thus block highlighting of the top item
("Manage streams") in that menu.
2016-10-27 23:10:27 -07:00
Tim Abbott
01f0be27a7 subs: Combine another set of settings show handlers. 2016-10-27 22:24:40 -07:00
Tim Abbott
426f2b0405 subs: combine some settings show handlers. 2016-10-27 22:22:28 -07:00
Tim Abbott
3fd94cc58a subs: s/subrow/sub_row/ in variable names. 2016-10-27 22:19:30 -07:00
Tim Abbott
2834a2bbbb subs: Extract subscription_settings.handlebars.
This is an early step towards being able to decouple the subscription
settings section from the slideout behavior.
2016-10-27 22:07:42 -07:00
Tim Abbott
12331e2596 subs: Extract show_subscription_settings. 2016-10-27 22:06:56 -07:00
Brock Whittaker
000e41a397 Add new checkbox image.
This adds the checkbox image that is required for the streams row
subscribe indicator/button.
2016-10-27 22:06:56 -07:00
Tim Abbott
30c654f83f templates: Fix stack traces throwing handlebars errors.
This fixes the fact that we weren't using `throw` correctly, and also
the "handlerbars" typo.

Fixes #2143.
2016-10-27 22:06:56 -07:00
Tim Abbott
9b7a3f040c Remove now-unused /json/get_events endpoint. 2016-10-27 21:34:58 -07:00
Rishi Gupta
b3b85202bc register.html: Clean up translation tags.
Adds a translation tag where needed, and replaces a {% trans %} with
{{ _(" ") }} for consistency.
2016-10-27 16:57:06 -07:00
Rishi Gupta
dc2bdb2aad register.html: Fix styling of subdomains input field.
The subdomains input field was using an outdated version of our styling.
2016-10-27 16:57:06 -07:00
Rishi Gupta
f316f72c71 register.html: Change placeholder values.
Previously, we used "e.g." for some of them, but not others. Also changes
our example name from "John Doe" to "Wily E. Coyote".
2016-10-27 16:57:06 -07:00
Rishi Gupta
dee597cfc5 dev_settings.py: Set EXTERNAL_HOST when REALMS_HAVE_SUBDOMAINS.
Sets EXTERNAL_HOST to zulipdev.com:9991 when REALMS_HAVE_SUBDOMAINS, since
subdomains don't currently work with localhost anyway.
2016-10-27 16:57:06 -07:00
trueskawka
df7e430849 css: Create a separate file for compose CSS.
Create a new file compose.css.
Move all compose CSS from zulip.css to compose.css.
2016-10-27 16:45:32 -07:00
umkay
e92604ab78 analytics: Alter field length for property and interval in BaseCount. 2016-10-27 16:33:58 -07:00
umkay
610e92b94e analytics: Add subgroup column to analytics tables.
This is a major change to the analytics schema, and is the first step in a
number of refactorings and performance improvements. For instance, it allows

* Grouping sets of similar CountStats in the *Count tables. For instance,
  active{_humans,_bots} will now have the same property, but have different
  subgroup values.

* Combining queries that differ only in their value on 1 filter clause, so
  that we make fewer passes through the zerver tables. For instance, instead
  of running a query for each of messages_sent_to_public_streams and
  messages_sent_to_private_streams, we can now run a single query with a
  group by on Stream.invite_only, and store the group by value in the
  subgroup column.
2016-10-27 16:33:58 -07:00
Steve Howell
f98e605840 Extract topic_list.set_click_handlers(). 2016-10-27 15:49:25 -07:00
Steve Howell
8ebf48793c minor: Remove copy/pasted comment. 2016-10-27 15:49:25 -07:00
Steve Howell
9de7551f4f Extract topic_list.rebuild().
This was pulled from rebuild_recent_topics(), which still
exists to wrap passing in the stream_li parameter.
2016-10-27 15:49:25 -07:00
Steve Howell
f7e6cfc892 Extract topic_list.build_list().
This used to be stream_list._build_subject_list().  The code
didn't change except for one s/subject/topic fix.
2016-10-27 15:49:25 -07:00
Steve Howell
8783a0e51d Move remove_expanded_topics() to topic_list.js. 2016-10-27 15:49:25 -07:00
Steve Howell
9b6b743a1a Move get_topic_filter_li to topic_list.js.
This also brought along:
    iterate_to_find (copied, see large comment explaining why)
    activate_topic (extracted from a one-liner)
    set_count (formerly stream_list.set_subject_count)

For get_topic_filter_li, we now pass in stream_li instead of
stream to decouple parent/child responsibilities between the
components.

Also, I made some s/subject/topic/ fixes.
2016-10-27 15:49:25 -07:00
Steve Howell
4f38cfdc7f Extract topic_list.update_count_in_dom().
This creates the new topic_list.js module, and the first
function that we extract is topic_list.update_count_in_dom().

This function needed to be decoupled from some non-topic-list
stuff which was overly complicated.
2016-10-27 15:49:25 -07:00
Tim Abbott
86e933a4a1 process_queue: Suppress USING_RABBITMQ warnings in test suite. 2016-10-27 12:36:06 -07:00
Tim Abbott
5b35aada7c zulip_tools: Fix run to not eat error output.
We fix this by just using `subprocess.check_call`.
2016-10-27 12:26:01 -07:00
Tim Abbott
76fd7c0735 provision: Fix creation of cache directories. 2016-10-27 12:05:43 -07:00
Umair Khan
486774b28d Add tests for JWT based login. 2016-10-26 14:40:56 -07:00
Umair Khan
52acdd28bd Fix JWT code in the auth backend.
For some reason, we use 'load' function but it doesn't exist in the JWT
library code. This commit updates the code to use the correct interface
of the JWT library.

The signature verification is done by the decode function.
2016-10-26 14:40:56 -07:00
Arpith Siromoney
c5510599ef Typing backend: use dict instead of user profile for sender in event.
Fixes #2110.
2016-10-26 13:12:18 -07:00
Tim Abbott
88269c7228 settings: Only create staging Nagios bots in production.
In ce528c2b5f, we added these bots,
which were intended as a setup convenience in production, but ended up
breaking the test suite.
2016-10-26 09:23:41 -07:00
K.Kanakhin
63f0e04621 docs-test: Exclude remote servers internal response errors.
Sometimes remote servers are unavailable or on maintance
what is the cause of broken back-end tests. Such response errors
is excluded from raised exception cases and just notify about
wrong link in test log.
2016-10-26 01:00:33 -07:00
Tim Abbott
4fbe201187 puppet: Automate autossh process monitoring maintenance.
Previously, the Zulip Nagios configuration effectively hardcoded the
count for how many system should have autossh connections.
2016-10-26 00:49:03 -07:00
Tim Abbott
6bdb10b71b puppet: Update emacs dependency to emacs-nox metapackage.
This way, one doesn't need to keep updating the dependency every time
a new major emacs release comes out.
2016-10-26 00:42:22 -07:00
Tim Abbott
11b5d203f7 sshd_config: Increase MaxStartups.
This fixes connection problems when using the full Zulip recommended
Nagios configuration against a given server.
2016-10-26 00:41:03 -07:00
Tim Abbott
73f54dd0cb sshd_config: Add updates from Xenial upstream.
It seems worth updating this to match the Linux distro this
configuration targets.
2016-10-26 00:40:44 -07:00
Tim Abbott
0a5a2c4eda nagios: Automate authorized users list maintenance. 2016-10-26 00:37:29 -07:00
Tim Abbott
fa4998db59 puppet: Add zulip_zephyr_mirror plugins. 2016-10-26 00:35:57 -07:00
Tim Abbott
ac4f28050c zmirror: Remove unnecessary krb5-clients dependency.
I'm pretty sure krb5-clients isn't needed to run the Zephyr mirroring
service.
2016-10-26 00:35:11 -07:00
Tim Abbott
d490e83645 puppet: Upgrade nagios cgi.cfg with modern defaults. 2016-10-26 00:31:41 -07:00
Tim Abbott
1159ad4857 puppet: Upgrade nagios.cfg with modern defaults. 2016-10-26 00:31:41 -07:00
Tim Abbott
73178e5e5a puppet: Run check_send_receive_time via a cron job.
This allows the actual nagios work involved with
check_send_receive_time nagios checks to be done by an unprivileged
"nagios" user rather than the "zulip" user.
2016-10-26 00:26:52 -07:00
Tim Abbott
96cf330649 puppet: ssh as the nagios user instead of zulip user.
This is a follow-up to 4f58fef54b,
touching services.cfg instead of commands.cfg.
2016-10-26 00:23:47 -07:00
Tim Abbott
a350d43683 puppet: Add recovery.conf configuration to postgres_slave.pp.
This file is needed to run a valid postgres slave; it's not clear why
this wasn't installed in the original zulip.com configuration.
2016-10-26 00:22:57 -07:00
Tim Abbott
c3727c9886 nagios: Remove old zulip.com trac/git/replica servers.
These are unlikely to be relevant to anyone.
2016-10-26 00:21:53 -07:00
Tim Abbott
383f39b543 nagios: Enable allow_empty_hostgroup_assignment.
This fixes the configuration being broken when we remove some of the
old zulip.com hosts that are unlikely to be of interest to anyone.
2016-10-26 00:19:21 -07:00
Tim Abbott
4f58fef54b zulip_ops: Use nagios user for all Nagios checks.
There's no reason these Nagios checks needs to run as the
semi-priviliged Zulip user.
2016-10-26 00:17:26 -07:00
Tim Abbott
32d244dbe5 puppet: Add Nagios checks for other consumers. 2016-10-26 00:11:08 -07:00
Tim Abbott
f1fa4397f3 puppet: Fix package deps for zulip-ec2-configure-interfaces. 2016-10-26 00:11:08 -07:00
Tim Abbott
3448ab4c7a zulip-ec2-configure: Fix network IDs for Ubuntu Xenial. 2016-10-26 00:11:08 -07:00
Tim Abbott
ce528c2b5f settings: Add NAGIOS_STAGING_{SEND,RECEIVE}_BOT bots.
This makes it a bit more convenient to have multiple machines running
the Zulip `check_send_receive_time` Nagios checks, if desired.
2016-10-26 00:11:08 -07:00
Tim Abbott
91da4bd59b puppet: Add check_cron_file generic helper. 2016-10-26 00:11:08 -07:00
Tim Abbott
080dd8c987 nagios: Ignore kthreads in check_procs tests.
Modern Linux can have a lot of kernel threads not doing anything.
Since this isn't interesting from a monitoring perpsective, we ignore
these.
2016-10-26 00:10:40 -07:00
Tim Abbott
4c9a283542 puppet: Remove configuration for old builder host.
I don't think this configuration was ever even used; it's just
clutter.
2016-10-26 00:01:52 -07:00
Tim Abbott
f9ad75f58e puppet: Remove configuration for old zulip.com bots host.
This configuration didn't do anything anyway and just clutters the
repo.
2016-10-26 00:01:29 -07:00
Tim Abbott
9d4f3f1e1b puppet: Replace zulip_ops postgres configs with postgres_appdb_tuned.
There's no longer a reason to have copies of forked postgres
configuration files in our repository, since some time ago we merged
the features of these configuration files into the main
postgres_appdb_tuned.pp.
2016-10-25 23:58:53 -07:00
Tim Abbott
105ea972f6 puppet: Remove now-unncessary kernel.shm sysctl values.
With modern Linux and postgres, these settings are not required.
2016-10-25 23:58:33 -07:00
Tim Abbott
2227e77cce puppet: Remove Dropbox usernames from Nagios config. 2016-10-25 23:55:42 -07:00
Tim Abbott
8584c05d80 zulip_ops: Remove unnecessary loadbalancer stanzas. 2016-10-25 23:52:37 -07:00
Tim Abbott
624ee3989f puppet: Remove old Dropbox certificates. 2016-10-25 23:52:30 -07:00
Tim Abbott
f0bb78ba2d puppet: Fix iptables-persistent->netfilter-persistent rename. 2016-10-25 23:45:21 -07:00
Tim Abbott
c4ca7ee6e1 puppet: Move Apache sites files to correct paths.
Apache now actually requires its configuration files have names ending
with .conf.
2016-10-25 23:44:28 -07:00
Steve Howell
65a2f012d4 Simplify pin/unpin code path.
I make server_events slimmer by not handling a specific
property when subs.update_subscription_properties() should
do all the dispatching (and mostly did).

And then since update_subscription_properties() has
a "sub" already, I can call directly to stream_list code
and remove a function from subs.js.  Since I lose the
wrapper function in subs.js, I rename the stream_list
function as part of this commit.

The only code that gets slightly heavier here is that
we have two lines in the 'pin_to_top' case instead of one.
2016-10-25 23:29:15 -07:00
trueskawka
0b8a2a6449 css: Create a separate file for subscriptions CSS.
Moves all subscriptions page CSS from zulip.css to a new file,
subscriptions.css.
2016-10-25 22:57:50 -07:00
Tim Abbott
129f1472fb provision: Fix hardcoding of current user.
This fixes a regression in 8e82257444
and 2b8324b778.
2016-10-25 21:58:15 -07:00
Steve Howell
1a927a424f Avoid passing around full_name parameter in subs.js.
All of the eventual callers to prepend_subscribers()
and format_member_list_elem() call people.get_by_email()
anyway, so now we do it one place.  The one exception
was using page_params.fullname, which is awkwardly
different than what we call that variable elsewhere
(fullname vs. full_name).
2016-10-25 18:15:24 -07:00
Steve Howell
51f0f7c7c4 Simplify creating subscriber list.
We were awkwardly reversing a list to use a one-line
helper method that did exactly the opposite of what
we wanted. :)  Now we just append simply.
2016-10-25 18:15:24 -07:00
Steve Howell
89b17ec2a4 Extract prepend_subscriber().
This is a minor change to avoid some 2-line calls in our
code.  (We're about to introduce a third usage of this.)
2016-10-25 18:15:24 -07:00
reyha
68f2c66b12 API bindings: Raise error if site param not defined.
Stops defaulting the site parameter to the now-nonexistent
https://zulip.com, and ask the user to enter the site via --site or
~/.zuliprc if not provided.

Fixes #2039.
2016-10-25 18:08:46 -07:00
Tim Abbott
14dc98d8b9 server_events: Switch to using REST-style URLs.
This eliminates our use of /json/get_events; we'll remove that
endpoint in a future commit.
2016-10-25 18:02:16 -07:00
Tim Abbott
2b8324b778 emoji: Fix caching permissions issues.
Previously, you needed to be root to update the emoji cache, which
caused problems with how Zulip is upgraded in production.
2016-10-25 17:52:19 -07:00
Tim Abbott
8e82257444 Fix node_cache code to not require root.
The previous code caused problems using a system where the zulip user
doesn't have sudo rights.
2016-10-25 17:52:19 -07:00
Tim Abbott
41b0079ab2 node_cache: Fix success_stamp logic.
Previously, success_stamp was touched whenever we used a particular
node_modules version; it makes more sense to only touch it when the
node_modules directory has actually changed.
2016-10-25 17:52:17 -07:00
Brock Whittaker
fd9a3f4609 admin: Remove values from emoji form input on success.
This removes the values after successfully creating a new realm emoji.
2016-10-25 17:01:03 -07:00
Brock Whittaker
bdd20f6b8b settings: Fix Zulip Labs Spacing Issue.
This fixes a spacing issue with Zulip Labs not having a space before
the icon.
2016-10-25 16:59:08 -07:00
Tim Abbott
7ebfa25f5a message_edit: Make .save() automatically call .end() if no changes.
Previously, all of the callers of message_edit.save() would check if
it returned true, and if so, call message_edit.end().  This resulted
in various bugs in the past, so we switch to the much cleaner model of
just calling .end() inside .save().
2016-10-25 16:34:57 -07:00
Tim Abbott
05a2e57b14 message_edit: Make enter save when editing topics.
Fixes #1272.
2016-10-25 16:34:57 -07:00
Tim Abbott
ff575aed99 message_edit: Fix error handling if user has re-narrowed. 2016-10-25 16:34:57 -07:00
Tim Abbott
985b4072c0 message_edit: Show a success message briefly. 2016-10-25 16:34:56 -07:00
Rishi Gupta
d14f276322 topic_edit_form: Rename message_edit_topic to inline_topic_edit.
message_edit_form.handlebars already has a message_edit_topic that
refers to the topic edit section of message editing, and this made
things very confusing.
2016-10-25 16:33:20 -07:00
K.Kanakhin
39e0886361 retention-policy: Add tool to determine expired messages.
This is a first step towards implementing a message retention policy
feature.

- Add Realm model message_retention_days field to setup
  messages expired period for realm.
- Add migration.
- Add tool to get expired messages for each Realm.
- Add tests to cover tool for getting expired messages.
2016-10-25 15:38:08 -07:00
umkay
1d077d1a4f bugdown: Remove safe_mode dependencies.
Now that we have updated python-markdown, we remove the deprecated
safe_mode. We used safe_mode to escape raw html, so now instead we
pass in an EscapeHtml markdown extension to the markdown engine.

See https://pythonhosted.org/Markdown/release-2.6.html for details on
the deprecation.

Fixes: #2037 (also addresses the remaining piece of #2043).
2016-10-25 15:22:18 -07:00
umkay
5fe6e7c07c bugdown: Add tests for escaping raw html.
Adds additional tests in bugdown-data.json to check that we escape raw
html properly with script tags.

Many of these tests are based on the bleach "advanced" test suite.
2016-10-25 15:21:46 -07:00
Rishi Gupta
82a0fe0eca actions popover: Change "Topic Edit" to "View Source / Topic Edit".
Also edit the icon to show "View Source" as the primary feature.
2016-10-25 15:12:32 -07:00
Rishi Gupta
7c227d8bb2 message_edit: Set focus to cancel button in topic-edit-only case.
Because the user was most likely intending to use the "View Source"
functionality, this makes exiting more convenient.
2016-10-25 15:11:39 -07:00
reyha
d96d4e30ab Stream settings: sets zero margin for 'Streams Deletion' table.
This removes the extra space at the bottom of the 'Stream Deletion'
table, by setting the margin for the table to '0px'.

Fixes #2077.
2016-10-25 15:08:47 -07:00
Brock Whittaker
82b5ef34be lightbox: Close lightbox if use clicks anywhere on the background. 2016-10-25 14:51:55 -07:00
Brock Whittaker
2ce601ebd1 Fix Multiple Lightbox Issues.
This fixes the following issues:
1. Photos are no longer resized larger than their native resolution.
2. Photos with transparency now have a checkerboard behind them to
signal an alpha of less than one.
2016-10-25 14:51:35 -07:00
Brock Whittaker
bb23d6ed60 lightbox: Fix focus state when exiting lightbox.
Previously, exiting the lightbox and then hitting enter reopened the
lightbox with a null image.

Fixes #1982.
2016-10-25 14:48:34 -07:00
Tim Abbott
0f7c8c6d34 subs: Rerender subscriber counts from peer changes correctly.
This makes subscriber count management completely nice and real-time.
2016-10-25 14:40:24 -07:00
Steve Howell
de727245aa subs: Add subscriber counts to the /#subscriptions page.
This borrows some work from krtkmj in #525.

Fixes #483.
2016-10-25 14:40:00 -07:00
Steve Howell
029682ec41 Fix stream_data.remove_subscriber().
We get events to delete subscribers for streams we are not
necessarily subscribed to, and it is now important to
process those events to produce the correct UI for showing
the number of subscribers to streams.
2016-10-25 14:29:27 -07:00
Tim Abbott
7b9d1a7824 auth: Simplify REALMS_HAVE_SUBDOMAINS redirect code.
This logic was just a duplicate on realm.uri, except that in the case
that subdomains are disabled, it preserves the host in the request.
2016-10-25 13:55:17 -07:00
hackerkid
b5816bf99e Don't use zulipdev.com when subdomain support is disabled. 2016-10-25 13:52:13 -07:00
Rishi Gupta
54016e1096 analytics: Remove outdated comment in counts.py. 2016-10-25 13:42:55 -07:00
Arpith Siromoney
01665d9c3c Extract get_recipient_user_profiles.
This creates a common function for extracting recipients, which both
do_send_messages and do_send_typing_notifications can use.
2016-10-25 13:37:01 -07:00
Tim Abbott
442f3a91e5 test-documentation: Add pretty success/failure output. 2016-10-25 11:41:12 -07:00
K.Kanakhin
455301ca13 docs-test: Add documentation test scripts to backend test case.
- Add script to compile documentation build and start crawler
  to check documentation.
- Add documentation test script to backend travis test case.
- Add log level argument to test-documentation script.

Fixes #1492
2016-10-25 11:36:43 -07:00
K.Kanakhin
6b31fcd63a docs-test: Add scrapy crawler to check documentation not having broken links.
- Add scrapy project with rewrited 'crawl' command and spider to check documentation.
  Command was rewrited due to return exit status by the exception existing,
  it returns exit code 0 if exception happens inside spider in standard behavour.

- Add scrapy requirements to for dev environment. It was added to twisted requirements list.

Fixes #1492
2016-10-25 11:35:16 -07:00
K.Kanakhin
8dabc6d499 docs: Fix broken link in upgrading docs. 2016-10-25 11:35:14 -07:00
Tomasz Kolek
4790316b57 Add user setting option to always send push notifications.
Add option in user's settings for getting mobile push notifications
even if a Zulip browser is online.  Default is False.

Fixes: #1596.
2016-10-25 10:52:29 -07:00
Rishi Gupta
b6da450b96 admin.js: Use RealmAlias instead of Realm to show the restricted domains.
Passes the allowed domains for a realm to the frontend, via
page_params.domains. Groundwork for allowing users to add and
remove domains via the admin setting page, rather than via the
realm_alias.py management command.
2016-10-25 10:07:20 -07:00
Rishi Gupta
537ee75761 Create RealmAlias entries for Realm.domain.
This is a preliminary step towards eliminating the realm.domain field
in favor of realm.subdomain.  Includes a database migration to create
these for existing realms.
2016-10-25 10:06:39 -07:00
Brock Whittaker
fca61b2031 Add medium size avatars for use on the user's own settings page.
This adds a medium (500px) size avatar thumbnail, that can be
referenced as `{name}-medium.png`.  It is intended to be used on the
user's own settings page, though we may come up with other use cases
for high-resolution avatars in the future.

This will automatically generate and upload the medium avatar images
when a new avatar original is uploaded, and contains a migration
(contributed by Kirill Kanakhin) to ensure all pre-existing avatar
images have a medium avatar.

Note that this implementation does not provide an endpoint for
fetching the medium-size avatar for another user.

[substantially modified by tabbott]
2016-10-25 09:42:14 -07:00
Umair Khan
9b42b7fad3 Add tests for TestZulipRemoteUserBackend. 2016-10-25 08:13:35 -07:00
Umair Khan
9f37b9b386 Add tests for TestDevAuthBackend. 2016-10-25 17:57:33 +05:00
Tim Abbott
c970a87dfa code-style: Fix broken links to anti for-in styleguides.
These two pages were moved over the last few years.
2016-10-24 11:10:25 -07:00
Rishi Gupta
28dd7080c7 docs: Add message editing policy to prod security section.
Fixes #1214.
2016-10-23 20:20:34 -07:00
Tim Abbott
28cefc4996 hashchange: Fix buggy arguments to hashchanged causing scrolltop bug.
Because jQuery passes the actual hashchange event to an onhashchange
handler, the `if reload` checks in the `hashchanged` function were
always returning true, resulting in the wrong logic being used for
computing where to send the user in the event that they edited the
hash in the browser to change their narrow.
2016-10-23 20:07:12 -07:00
Tim Abbott
56c0b80067 nginx: Fix JavaScript not being compressed properly.
Apparently, we weren't actually compressing our JavaScript being sent
over the wire due to incorrect nginx configuration.
2016-10-23 20:06:02 -07:00
Tim Abbott
e714ddbfc8 gather_subscriptions_helper: Fix mypy error. 2016-10-22 22:37:05 -07:00
Tim Abbott
c59cdbb92d gather_subscriptions: Fix missing subscriber data in email_dict.
When we added data on never_subscribed streams to what
populate_subscribers is called on, we failed to add the corresponding
data on subscribers to email_dict, the mapping of user IDs to emails
for the subscribers.
2016-10-22 21:37:05 -07:00
Tim Abbott
14018353fc Fix never_subscribed streams being sent for Zephyr mirroring.
Because in the Zephyr world, stream names can be a secret, and also
Zephyr mirroring tends to involve many thousands of streams, we
shouldn't send this data.
2016-10-22 21:36:11 -07:00
Sumana Harihareswara
f86cd0aa26 docs: Fix style in authentication methods doc. 2016-10-22 20:14:56 -07:00
Sumana Harihareswara
04c8c9d5bd docs: Updates to production customization guide. 2016-10-22 20:13:37 -07:00
Sumana Harihareswara
dd3a19ab58 docs: Clarify export_single_user. 2016-10-22 20:13:06 -07:00
Sumana Harihareswara
facf0ac1f3 docs: Add psql instructions. 2016-10-22 20:13:06 -07:00
Tim Abbott
893679baff Add migration to remove system avatar source.
Fixes the last commit having broken master.
2016-10-22 20:07:21 -07:00
Tim Abbott
5bea2f5e20 Remove unused AVATAR_FROM_SYSTEM code.
This is some of the code we'd need if we wanted to have Zulip generate
avatars for things.  Since it is so little useful code, and it's not
clear we will need this feature ever, we can remove this code to make
the codebase less confusing.  It'd be easy to dig this out of history
if we ever want it.

Fixes #2101.
2016-10-22 19:48:50 -07:00
Tim Abbott
c20011ccd5 docs: Remove unnecessary and broken SSO breadcrumb link. 2016-10-22 19:30:24 -07:00
K.Kanakhin
9492bd37b4 docs-test: Fix documentation links.
- Fix internal documentation links and anchors according last project documentation version.

Fixes #1492
2016-10-22 19:30:24 -07:00
Tim Abbott
a32eaf28c0 docs: Remove broken indices and tables index section.
None of these links worked properly.
2016-10-22 19:23:11 -07:00
Tim Abbott
4352790795 docs: Fix broken link in node testing docs. 2016-10-22 19:21:19 -07:00
umkay
87d22c9e4d analytics: Fix count_stream_by_realm.
Add a join clause on zerver_message in count_stream_by_realm,
otherwise we only output the final total streamcount for a realm
for every time entry.
2016-10-22 19:10:36 -07:00
Rishi Gupta
49b23ea84a frontend: Allow users to see the source of messages they can't edit.
Previously we showed an "Edit" item in the actions popover menu when a user
could edit the content or topic of a message, and nothing otherwise. We now
show "Edit", "Edit Topic", or "View Source" in the popover menu for every
message, depending on the editability of the message, and present an
appropriate version of message_edit_form when the menu item is clicked.

Finishes #1604 and #1761.
2016-10-22 18:53:59 -07:00
Rishi Gupta
879f2a1e2e message editing: Refactor editability computation to use editability_types.
We compute the editability of messages in several places around the
frontend; standardize the definitions and store in
message_edit.get_editability. This commit should not change app behavior.
2016-10-22 18:52:49 -07:00
Rishi Gupta
c2c389e949 message_edit.js: Refactor edit_message.
Cleanup and re-organize edit_message in preparation for the view source
changes. There are no behavior or logic changes in this commit.
2016-10-22 18:52:49 -07:00
Tim Abbott
bd416c0425 message_edit: Cleanup unnecessary 2-layer nesting. 2016-10-22 18:52:49 -07:00
Tim Abbott
5b3caa4d18 message_edit: Fix tooltip with multiple messages being edited.
This fixes an issue where if there were multiple messages being
edited, all of them would have the same tooltip content.
2016-10-22 18:52:49 -07:00
Tim Abbott
5b656db303 message_edit: Clean up tooltip creation code.
This contains no functional changes.
2016-10-22 18:52:49 -07:00
Tim Abbott
0ccf8b162e message_edit: Move topic-editing-only warning.
This makes no functional change, because
`page_params.realm_message_content_edit_limit_seconds === 0` means
can_edit_content is always true.
2016-10-22 18:52:49 -07:00
Tim Abbott
d5c3ad8eb5 message_edit: Only initialize composebox_typeahead if needed. 2016-10-22 18:52:49 -07:00
Tim Abbott
76d49300b3 message_edit: Move original_topic variable to a better spot. 2016-10-22 18:52:49 -07:00
Tim Abbott
0acfcbe247 message_edit: Update currently_editing_messages in clearer place. 2016-10-22 18:52:49 -07:00
Tim Abbott
d2501396cf message_edit: Reindent form definition. 2016-10-22 18:52:45 -07:00
Tim Abbott
2b58fa0a19 message_edit: Move some setup code closer to where it's used.
This has no functional changes.
2016-10-22 18:40:44 -07:00
Rishi Gupta
ebc8bfa6ca javascript: Change all message.is_stream to (message.type === "stream").
We need message.is_stream for some handlebars template code, but
message.is_stream should be thought of as a private variable for that
template.
2016-10-22 18:11:08 -07:00
Steve Howell
c21fe60430 Add make_stream() to django testing docs. 2016-10-22 18:09:34 -07:00
Steve Howell
4d6af33bad Use make_stream() in test_subs.py. 2016-10-22 18:09:34 -07:00
Steve Howell
2a739318b9 Use make_stream() in test_signup.py. 2016-10-22 18:09:34 -07:00
Steve Howell
8410159af2 Use make_stream() in test_narrow.py. 2016-10-22 18:09:34 -07:00
Steve Howell
b1ebb09c96 Use make_stream() in test_messages.py. 2016-10-22 18:09:34 -07:00
Steve Howell
0861421912 Use make_stream() in test_events.py. 2016-10-22 18:09:34 -07:00
Steve Howell
79b6f3d39d Create ZulipTestCase.make_stream(). 2016-10-22 18:09:34 -07:00
deekshaarul
be903382f8 lint: Add rule to check for misspellings of 'GitHub'. 2016-10-22 17:09:55 -07:00
K.Kanakhin
16c3da6db5 tests: Add tests for SEND_MISSED_MESSAGE_EMAILS_AS_USER=False.
- Add tests for SEND_MISSED_MESSAGE_EMAILS_AS_USER is False (the
  default!).
- Reorganized test case code by removing repeated parts of code,
  improving code style and moving common parts to separate class
  methods.

Fixes #1697.
2016-10-21 08:47:24 -07:00
Umair Khan
8891731d7d is_template_database_current: Open file in write mode. 2016-10-21 08:35:30 -07:00
Umair Khan
b894135fae Check postgres-init-dev-db in is_template_database_current. 2016-10-21 08:35:30 -07:00
Umair Khan
176825d335 Refactor is_template_database_current.
Now all the files whose hash is to be checked are passed as a list
argument.
2016-10-21 08:35:30 -07:00
Umair Khan
bf4e0800e3 is_template_database_current: Create hashes in var/test_db_status. 2016-10-21 08:35:30 -07:00
Umair Khan
a2c57db630 Use argparse in provision.py 2016-10-21 08:35:30 -07:00
Umair Khan
8ade9e2408 Add tests to check subdomains with auth decorators.
Fixes: #1870
2016-10-21 12:21:47 +05:00
Tomasz Kolek
6e1674aca5 Normalize github issue or PR comment event's subject and content. 2016-10-20 23:15:51 -07:00
Tomasz Kolek
56dd1a9b90 Normalize gitlab issue event's subject and content. 2016-10-20 23:15:30 -07:00
Tomasz Kolek
a8da46db92 Normalize bitbucket issue event's subject and content. 2016-10-20 23:15:30 -07:00
Tomasz Kolek
171a4861cc Normalize github issue event's subject and content. 2016-10-20 23:15:30 -07:00
Tomasz Kolek
89d53a0640 Change name of PR subject template to be applicable for issues. 2016-10-20 23:15:30 -07:00
Tomasz Kolek
289f400c8c Add git integrations method to build message for issues events. 2016-10-20 23:15:30 -07:00
Arpith Siromoney
ee97ba04fe Add an API endpoint to send typing notification events.
POST to /typing creates a typing event
Required parameters are 'op' ('start' or 'stop') and 'to' (recipient
emails). If there are multiple recipients, the 'to' parameter
should be a JSON string of the list of recipient emails.
The event created looks like:
{
  'type': 'typing',
  'op': 'start',
  'sender': 'hamlet@zulip.com',
  'recipients': [{
    'id': 1,
    'email': 'othello@zulip.com'
  }]
}
2016-10-20 23:05:18 -07:00
Prabhakar Gupta
bc6421fbfb tools: Remove empty wrapper script build_emoji.
This renames the old `emoji_dump.py` to `build_emoji`, removing the
old shell essentially empty shell script.  `emoji_dump.py` was always
a weird name, and this makes it a bit easier to read the code for this
system.
2016-10-20 22:57:45 -07:00
Sumana Harihareswara
2083ffa7a6 docs: Improve export documentation.
Added user and realm export guidance in production maintenance docs,
linked to conversion guide, and revamped the introduction and styled
the text that Steve wrote.
2016-10-20 22:52:32 -07:00
Sumana Harihareswara
d9d389f64f docs: Add an initial code review document.
A first pass at a code review guide. Mostly Tim's draft; I added
polish and links.

Fixes: #758.
2016-10-20 22:41:38 -07:00
Tim Abbott
f9f8b18e2f lint: Ban use of json_success({}) instead of json_success(). 2016-10-20 22:34:04 -07:00
Amy Liu
3ee777a11a Add UI for deactivating your own Zulip account.
Fixes #1009.
2016-10-20 22:29:30 -07:00
Tim Abbott
3d183ffe23 text_fixtures: Fix case where source_hash_file doesn't exist.
We unfortunately just broke provisioning because we didn't correctly
handle the case where the source_hash_file didn't exist.
2016-10-20 22:21:45 -07:00
Steve Howell
409a84698c Handle peer_remove events correctly for subscriptions.
We now send peer_remove events to folks who have never subscribed
to the streams (except for private streams and zephyr).

We also use logic that is more similar to how
bulk_add_subscriptions() works.
2016-10-20 22:05:19 -07:00
Steve Howell
68ae4da626 Extract query_all_subs_by_stream().
This code was in bulk_add_subscriptions, but we want the same logic
to eventually happen in bulk_remove_subscriptions.
2016-10-20 22:05:19 -07:00
Steve Howell
d13b0554b3 Remove emails_by_stream in bulk_add_subscription().
There are so many collections in this function, it's hard to keep
them all straight.  This one is fairly redundant, so it was easy
to remove.
2016-10-20 22:05:19 -07:00
Steve Howell
d706bfa69f Move some code from notify_subscriptions_removed().
There are two reasons for this change.  First, we want to be
consistent with notify_subscriptions_added(), which doesn't
handle "peer" events.  Second, we want to fix this code in a
subsequent commit not to do one user at a time, which is
inefficient.
2016-10-20 22:05:19 -07:00
Steve Howell
dda4c61f2a Remove do_remove_subscription(). 2016-10-20 22:05:19 -07:00
Steve Howell
cba8be6bbb Use bulk_remove_subscriptions() in remove_users_from_stream.
We are deprecating do_remove_subscription.
2016-10-20 22:05:19 -07:00
Steve Howell
4ae117ed14 Use bulk_remove_subscriptions() in do_deactivate_stream().
We are deprecating do_remove_subscription().
2016-10-20 22:05:19 -07:00
Steve Howell
77c75df284 Remove do_remove_subscription() calls in test_events. 2016-10-20 22:05:19 -07:00
Steve Howell
44bbece5a6 Remove do_remove_subscription() calls in tests.py. 2016-10-20 22:05:19 -07:00
Steve Howell
b2d06fad42 Extract get_peer_user_ids_for_stream_change(). 2016-10-20 22:05:19 -07:00
Steve Howell
5eee77fe81 Remove do_add_subcription(). 2016-10-20 22:05:19 -07:00
Steve Howell
76acab36b2 Remove do_add_subscription from Django testing docs. 2016-10-20 22:05:19 -07:00
Steve Howell
98e4452e07 Replace do_add_subscription() in add_users_to_streams. 2016-10-20 22:05:19 -07:00
Steve Howell
bea8ba620b Replace do_add_subscription() in tests/tests.py. 2016-10-20 22:05:19 -07:00
Steve Howell
9408ba7ca8 Replace do_add_subscription() in test_subs. 2016-10-20 22:05:19 -07:00
Steve Howell
45790264c2 Replace do_add_subscription() in test_signup. 2016-10-20 22:05:19 -07:00
Steve Howell
f4fc8455de Replace do_add_subscription() in test_narrow. 2016-10-20 22:05:19 -07:00
Steve Howell
d18e286131 Replace do_add_subscription() in test_messages. 2016-10-20 22:05:19 -07:00
Steve Howell
78b73a0c91 Replace do_add_subscription() in test_helpers. 2016-10-20 22:05:19 -07:00
Umair Khan
041cd6c787 Add --force argument to provision.py.
Fixes: #2026
2016-10-20 22:04:52 -07:00
Umair Khan
35dea5246c Regenerate test DB only when template DB has changed. 2016-10-20 22:04:52 -07:00
Umair Khan
45166cb39c is_template_database_current: Check populate_db and postgres-init-test-db.
Compare the hash of 'zilencer/management/commands/populate_db' with
'var/populate_db_hash' and 'tools/setup/postgres-init-test-db' with
'var/postgres_init_test_db_hash' and if any comparison fails rebuild
the database.

With fixes from tabbott.
2016-10-20 22:04:47 -07:00
sonali0901
1bc7990327 Extract people.filter_people_by_search_terms()
This code used to be in subs.js, but now it's in people.js and has
some unit tests.

I did this w/showell as part of live coding on Zulip.
2016-10-20 21:44:26 -07:00
hackerkid
bca1953aa4 Add support for !gravatar syntax in echo.js. 2016-10-20 14:40:45 -07:00
hackerkid
95b5ac1d5d Add support for !avatar syntax in echo.js. 2016-10-20 14:40:33 -07:00
Tomasz Kolek
67adf570e7 Remove @-mentions from jira integration.
Because of a lot of annoying notifcations we decided to remove
all @-mentions in jira. We replaced it by just login (without @).
2016-10-20 11:55:12 -07:00
Sumana Harihareswara
c3d3288b63 docs: Style & link text in prod maintenance guide.
Also fix line wrapping and some capitalization.
2016-10-20 11:53:46 -07:00
Sumana Harihareswara
a4516bda7d docs: Fix security bug email address. 2016-10-20 11:53:46 -07:00
Tim Abbott
31b245eaea bugdown: Add tests for avatar/gravatar syntax. 2016-10-20 11:18:41 -07:00
K.Kanakhin
7bc0c7f0d5 bugdown: Fix patterns ordering in Markdown extension.
- Put 'modal_link' and 'link' inline patterns after avatar inline pattern
  to correct applying them to parsed text.

Fixes:  #1654
2016-10-20 11:18:41 -07:00
Tim Abbott
8f6a58f741 docs: Expand translating documentation a bit. 2016-10-19 15:34:31 -07:00
Tim Abbott
92b8ce32fc docs: Clean up translation resources discussion. 2016-10-19 15:32:28 -07:00
Sumana Harihareswara
8d4b32a13a Fix style and linewrapping & add links in translation doc. 2016-10-19 15:30:35 -07:00
Sumana Harihareswara
8d1e87cfff Add translations stream link to translation doc. 2016-10-19 15:30:35 -07:00
Brock Whittaker
e463577f30 Fix language alert to display language name.
If you chose the same language as was already selected, the alert would
say “is now the default language!” where it omits the language name.

This is the fix so that the language name appears all the time.
2016-10-19 15:17:16 -07:00
Tim Abbott
50356cc325 event_queue: Eliminate buggy need_timeout heartbeat code.
As best I can tell, this option was completely confused in two ways:
* The name is confusing; it actually controls whether we _clear_ the
  timeout associated with the current handler
* It's not clear why one would not want it to be unconditionally true.

From reading the history, I'm pretty sure I had just misread the code
when I created this.

And this caused a real bug; a later refactoring caused us to basically
never cancel the timeouts, which in turn resulted in 90% of all events
traffic being hearbeats with a much lower frequency (~5s) than the
intended 45s.  Removing this code fixes that nasty bug.
2016-10-19 14:32:49 -07:00
Tim Abbott
a6e779a56c events: Add event types to logging.
This should make it a lot easier to analyze our events traffic and
debug potential issues with it.
2016-10-19 14:32:16 -07:00
Sumana Harihareswara
fe711208fb docs: Capitalize GitHub properly. 2016-10-19 12:36:20 -07:00
Vikas Parashar
e962704c71 Add installation troubleshooting instructions in case of pip failure.
Add help for pip install failure during provisioning step of
initial vagrant up during developer environment installation.

Fixes: #1333.
2016-10-19 12:34:08 -07:00
Tim Abbott
08729d35ad README.md: Add mention of our blog and tweak intro. 2016-10-19 12:19:57 -07:00
Sumana Harihareswara
3b74ed20fa Add GSoC mailing list link to README.md. 2016-10-19 12:14:51 -07:00
Umair Khan
e428f3feda Run apt-get update only if sources.list has changed.
Fixes: #2025
2016-10-19 16:23:21 +05:00
Rishi Gupta
83f902953a newsletter signup: Update merge_vars.
merge_vars is the user meta data we store in mailchimp. This commit changes
what we store from realm.domain to realm.id, since realm.domain is being
deprecated, and changes the OPTIN_TIME to a nicer format.
2016-10-18 19:29:12 -07:00
Steve Howell
4073ae09a1 streams: Use page_params.neversubbed_info client-side. 2016-10-18 17:33:58 -07:00
Steve Howell
c4b2f6d816 docs: Say "Set up" instead of "Setup".
I think "setup" generally implies a noun.
2016-10-18 17:29:00 -07:00
Steve Howell
6a482a65d4 Document our "area:" labeling convention in README.md. 2016-10-18 17:12:06 -07:00
Steve Howell
9afc130f21 Use "area:<label>" for doc links in README.md. 2016-10-18 17:10:57 -07:00
Brock Whittaker
10f7146ddd Change Lightbox to Support YouTube Videos.
The lightbox will now distinguish between whether or not something is a
photo and a YouTube video by the class name of the message inline
preview. It embeds the YouTube video in the lightbox as an iFrame
rather than previewing the video screenshot.
2016-10-18 14:45:47 -07:00
Brock Whittaker
77233c7e3b bugdown: Distinguish between YouTube Videos and Image Previews.
This distinguishes between YouTube Videos and Image Previews by adding
a particular “youtube-video” class to the preview along with changing
the title to the video ID rather than the link. This serves to allow
the lightbox to ID when a lightbox preview should be treated like a
YouTube video rather than an image preview.

This also modifies the tests in bug down to expect a youtube-video class
along with the title to just be the video ID on YouTube rather than the
entire URL link.
2016-10-18 14:45:47 -07:00
Tim Abbott
0784c4b339 requirements: Install the Zulip API bindings by default.
Now that we're no longer using the --install-option feature of
requirements.txt, we can add this back in again.
2016-10-17 23:21:43 -07:00
Tim Abbott
497d1c1f4e twitter bots: Update to use current python-twitter.
It appears that twitter has changed several of its APIs.
2016-10-17 23:21:39 -07:00
Tim Abbott
56d0cc69e9 socket: Remove unused djsession_engine. 2016-10-17 23:19:28 -07:00
Mohsen Ibrahim
bfe5787197 Fix Django.utils.importlib deprecation warnings.
This changes `from django.utils.importlib import import_module` to
`from importlib import import_module`, as `django.utils.importlib` will
be removed in django version 1.9.
2016-10-17 23:19:28 -07:00
Mohsen Ibrahim
e9899e4dc9 bugdown: Fix some Python-Markdown deprecation warnings.
Python-Markdown changed how one is supposed to declare extensions
being used.
2016-10-17 23:13:41 -07:00
Christie Koehler
906587f474 Force LF line-endings except for binary file types. 2016-10-17 20:19:55 -07:00
Christie Koehler
2595b32165 Update with proper LF line-endings. 2016-10-17 20:19:55 -07:00
Steve Howell
7fd74c45d7 Clean up startup code for streams.
The startup code in subs.js used to intermingle data
stuff and UI stuff in a loop inside a called function,
which made the code hard to reason about.

Now there is a clear separation of concerns, with these methods
being called in succession:

    stream_data.initialize_from_page_params();
    stream_list.create_initial_sidebar_rows();

The first method was mostly extracted from subs.js, but I simplified
some things, like not needing to make a copy of the hashes
we were passed in, plus I now garbage collect email_dict.  Also,
the code path that initialize_from_page_params() mostly replaces
used to call create_sub(), which fired a trigger, but now it
just does data stuff.

Once the data structure is built up, it's a very simple matter
to build the initial sidebar rows, and that's what the second
method does.
2016-10-17 19:58:23 -07:00
Steve Howell
d26942e72d Extract stream_list.create_sidebar_row().
This replaces add_stream_to_sidebar(), which was kind of a misleading
name, and it also adds a couple lines of code that were always
called right after calling add_stream_to_sidebar().
2016-10-17 19:58:23 -07:00
Steve Howell
869a124d7d Extract stream_data.get_streams_for_settings_page().
This function will make it easier to unit test upcoming
changes related to stream counts.

This was mostly moving code, but one change is that we
don't call create_subs() in subs.js any more (which would
have been kind of circular dependency), since the only thing
that it did besides calling a more appropriate function
in stream_data.js was to generate a trigger that was
subsequently ignored and possibly a UI trap, as we don't
want to be messing with the stream sidebar when we go into
the stream settings page.

We now simply call exports.create_sub_from_server_data() for
newly encountered unsubscribed streams (which don't belong in
the sidebar anyway.)
2016-10-17 19:58:23 -07:00
Steve Howell
965c6047db Move add_admin_options() to stream_data.js.
This function used to live in subs.js.  It's mostly a code move,
but I simplified the logic to determine whether it's subscribed
not to do a lookup into the same data structure that the sub
already came from.

I also added some tests.
2016-10-17 19:58:23 -07:00
Steve Howell
cf08f04dbc Move receives_*_notifications() to stream_data.js.
This moves these functions from subs.js to stream_data.js:

    receives_desktop_notifications
    receives_audible_notifications

This makes notifications.js no longer dependent on the
bloated subs.js.
2016-10-17 19:58:23 -07:00
Steve Howell
e25b67af26 Remove subs.sub_pinned_or_unpinned(). 2016-10-17 19:58:23 -07:00
Steve Howell
5dd1c2d55f Remove subs.stream_id(). 2016-10-17 19:58:23 -07:00
Steve Howell
2676083b94 Add introduction to docs on node tests.
Also, de-emphasize the process for creating new test modules,
as this is an advanced task that we can further document later
and generally handle as part of code review.
2016-10-17 19:46:17 -07:00
Tim Abbott
63a49be09e event_queue: Import tornado.ioloop correctly.
We actually use tornado.ioloop, not the root tornado module, and while
the current code does work, it causes mypy errors with the incremental
cache.
2016-10-17 17:57:46 -07:00
Sumana Harihareswara
6323494f37 docs: Properly capitalize GitHub. 2016-10-17 19:31:50 -04:00
Christie Koehler
23df7913d5 docs: Add Git and GitHub Guide.
Fixes #783, #1754.
2016-10-17 16:18:16 -07:00
Steve Howell
ff6404cb3c Add comment about /json/subscriptions/exists endpoint.
We should remove this endpoint.  For now I'm just adding
the comment to the code explaining why we should do that.
2016-10-17 16:11:04 -07:00
umkay
906a4e3b26 analytics: Add performance and transaction logging to counts.py.
For each database query made by an analytics function, log time spent and
the number of rows changed to var/logs/analytics.log.
In the spirit of write ahead logging, for each (stat, end_time)
update, log the start and end of the "transaction", as well as time
spent.
2016-10-17 16:10:03 -07:00
Tim Abbott
4a4664d268 mypy: Remove a bunch of now-unnecessary type: ignore annotations.
Since mypy and typeshed have advanced a lot over the last several
months, we no longer need these `type: ignore` annotations.
2016-10-17 11:48:34 -07:00
Tim Abbott
3b0b65c2d0 management: Fix recent argument parsing regressions.
Fixes a regression introduced in
fbdf539bf2.
2016-10-16 20:36:33 -07:00
Tim Abbott
a5a03c2e0b zulip_ops: Include zulip::apt_repository.
This replaces the old wheezy configuration.
2016-10-16 20:13:35 -07:00
Tim Abbott
8c68c6f09b zulip_ops: Remove wheezy apt repo.
Nobody uses wheezy anymore, and the configuration wasn't even
conditional on the OS version.
2016-10-16 20:13:35 -07:00
Tim Abbott
5210b0a6a4 zulip_ops: Cleanup old redis configuration.
One can now just use the improved configuration we've merged into the
main Zulip repo.
2016-10-16 20:13:35 -07:00
Tim Abbott
869f0724ce zulip_ops: Remove humbughq.com nginx configuration.
The humbughq.com name hasn't been the product's name since 2013, and
it's nice to finish clearing it out of the repository.
2016-10-16 20:13:29 -07:00
Tim Abbott
29448fb47b zulip_ops: Remove old Zulip, Inc. trac configuration.
This isn't useful to anyone.
2016-10-16 19:23:47 -07:00
Tim Abbott
771e03cfa7 zulip_ops: Remove old Zulip, Inc. mediawiki configuration.
This isn't useful to anyone.
2016-10-16 19:23:47 -07:00
Tim Abbott
36e336edc3 puppet: Rename zulip_internal to zulip_ops.
The old "zulip_internal" name was from back when Zulip, Inc. had two
distributions of Zulip, the enterprise distribution in puppet/zulip/
and the "internal" SAAS distribution in puppet/zulip_internal.  I
think the name is a bit confusing in the new fully open-source Zulip
work, so we're replacing it with "zulip_ops".  I don't think the new
name is perfect, but it's better.

In the following commits, we'll delete a bunch of pieces of Zulip,
Inc.'s infrastructure that don't exist anymore and thus are no longer
useful (e.g. the old Trac configuration), with the goal of cleaning
the repository of as much unnecessary content as possible.
2016-10-16 19:23:27 -07:00
Laura Hampton
fbdf539bf2 Replace optparse with argparse in the several management commands.
Specifically:
* fill_memcached_caches.py
* initialize_voyager_db.py
* logout_all_users.py
2016-10-16 17:08:35 -07:00
Brock Whittaker
7984c5af68 Add data-name groups to templates.
The data-name attribute in this case allows for a particular settings
section element to show up when the appropriate sidebar category is
clicked (which will have the same value in the data-section key).
2016-10-16 16:37:21 -07:00
reyha
537c9755bf search: Fix searching for URLs.
Previously, URLs were being incorrectly treated as unknown search
operators (since they had exactly one ":" in them, just like foo:bar
for an invalid choice of foo).

Fixes #1743.
2016-10-16 15:25:46 -07:00
Steve Howell
241b03e427 Add --force option to run-casper. 2016-10-16 14:52:15 -07:00
Steve Howell
6e628e23aa Add --force option to test-backend. 2016-10-16 14:52:14 -07:00
Steve Howell
f48c5e55dc Check provisioning status in run-casper. 2016-10-16 14:52:14 -07:00
Steve Howell
10667b3cdb Check provisioning status in tools/test-backend. 2016-10-16 14:52:14 -07:00
Steve Howell
8bc027e71b Add tools/lib/test_script.py w/get_provisioning_status(). 2016-10-16 14:52:13 -07:00
Steve Howell
37842d5d15 Have provision.py write to var/provision_version. 2016-10-16 14:44:45 -07:00
Steve Howell
e25f93fa8a Add PROVISION_VERSION to version.py. 2016-10-16 14:44:45 -07:00
Steve Howell
f0b8f741b9 contrib_bots: Simulate a file system with a bot. 2016-10-16 14:41:24 -07:00
Steve Howell
ff5a2b21d0 Add StateHandler to contrib_bots/run.py.
This allows bots to be stateful.  It doesn't handle persistence
after the bot shuts down, but it does store state between
invocations of handle_message.
2016-10-16 14:41:24 -07:00
Tim Abbott
258dd28fcc 03-narrow: Test the 'topic:' narrowing syntax.
This being a very old test, it had previously only really tested the
(deprecated) 'subject:' syntax.
2016-10-16 14:10:18 -07:00
Tim Abbott
8f71d3702b filter: Add missing canonicalization to operator_to_prefix.
This makes it possible to reuse this function for validating whether a
given search operator is valid.
2016-10-16 14:06:55 -07:00
Tim Abbott
a28a5bb977 docs: Update roadmap HTML with now-completed issues. 2016-10-16 13:09:28 -07:00
Tim Abbott
df617225fd lint-all: Check for untranslated placeholders in handlebars templates. 2016-10-16 12:59:41 -07:00
trueskawka
aa7fd9a07c stream_creation: Add a clear error message for duplicate streams.
User is now unable to create a stream with duplicate or empty name
through the create stream modal. An appropriate error message appears
on attempt.
2016-10-16 12:59:41 -07:00
trueskawka
9c8f4d9a1e stream_filtering: Filter streams on subscriptions page.
Filter behaves similarly to filter in left sidebar, see PR #684. Added
stream input field to the stream creation modal along with other settings,
for clarity.

Fixes #455, #563.
2016-10-16 12:59:41 -07:00
deekshaarul
357fbfcaa3 Zocial buttons: Fix overflow of text when internationalized.
Previously, the text in the Google/GitHub auth buttons would overflow
in languages like German where text is longer than in English.

Fixes #1876.
2016-10-16 12:35:43 -07:00
Sumana Harihareswara
a4ac09cb8f Clarify comment on empty json_rules list.
Fixes: #2030.
2016-10-16 12:28:16 -07:00
Sumana Harihareswara
bef73be824 lint: Improve documentation lint check for JavaScript capitalization.
Move JavaScript capitalization rule to new ruleset for HTML and
Markdown checkers to run, and add exclusion to avoid catching
URLs and divs/hrefs. Also fix affected HTML pages, and remove
now-obsolete exclusion for doc that no longer exists.

For exhaustive thought-process on this change see:
https://zulip.tabbott.net/#narrow/stream/test.20suites/topic/watch.20over.20my.20shoulder.20as.20I.20improve.20the.20linter
2016-10-16 12:28:16 -07:00
Tim Abbott
2bea0c46fe HomeTest: Add a basic test for desktop_home. 2016-10-16 11:39:08 -07:00
Tim Abbott
3ee9e2c45f tests: Add some basic i18n public URL tests. 2016-10-16 11:26:01 -07:00
Tim Abbott
122164fffb DocPageTest: add test for /about/ page. 2016-10-16 11:19:27 -07:00
Mohsen Ibrahim
ca1789892d api: Fix broken link to zulip-js github page. 2016-10-16 01:42:30 -07:00
Tim Abbott
fc20c86d8d install: Move apt-get update into setup-apt-repo. 2016-10-16 01:13:50 -07:00
Tim Abbott
cf6feac65f provision: Remove unnecessary second apt-get update.
Since we do this slightly later (after setting up our apt repository,
where it's actually required), there's no need to do this here.
2016-10-16 01:13:50 -07:00
Tim Abbott
e91f227c0b requirements: Update python-social dependency.
Also, fix the use of `>=` in the version declarations; we want to be
precise about what versions we're installing.
2016-10-16 01:13:50 -07:00
Tim Abbott
14e2540b2f requirements: Upgrade a bunch of dependencies.
These are all minor version upgrades that should be safe.
2016-10-16 01:13:50 -07:00
Tim Abbott
ec9dcd7fb4 Upgrade mypy to version 0.4.5.
Now that 0.4.5 is out, we no longer need to use a forked version of mypy.
2016-10-16 01:10:43 -07:00
Tim Abbott
fcde846b58 setup_venv: Fix handling of Git requirements.
get_package_names did not correctly strip the GitHub URLs from package
names, resulting in the "package names" for our dependencies installed
from Git being tracked with the complete sha1sum included in the name.
This meant that upgrading our virtualenvs incorrectly ended up
resorting to creating an entirely new virtualenv whenever we changed a
dependency that had previously been installed from GitHub URLs.
2016-10-16 01:10:43 -07:00
Tim Abbott
e37b6488b8 Bugdown: Remove checked-in CodeHilite extension.
The changes that required us to fork this extension had been merged
into upstream CodeHilite, so we can remove it and switch to using the
version that comes with python-markdown.
2016-10-16 00:40:08 -07:00
umkay
c028815385 bugdown: Update python-markdown to version 2.6.7.
This updates Bugdown to reflect the changes in the updated
markdown. In particular, we now pass a default config object in the
__init__ for the Bugdown extension, update the make_md_engine function
to take kwargs as opposed to a config list, and have UListProcessor
inherit from ulist as opposed to olist (which no longer works).

We update the (forked from upstream) fenced_code extension's
makeExtension to take args and kwargs, and update
FencedBlockPreprocessor __init__ method with updated Codehilite
arguments.

We update the (forked from upstream) Codehilite extension to
mirror the logic with the latest upstream Codehilite:
	Add parse_hl_lines function
	update makeExtension to take args and kwarfs instead of config
	list
	Add regex for highlight lines
	use linenums instead of linenos
	use get_formatter_by_name instead of HtmlFormatter
	user get_lexer_by_name instead of TextLexer
	add hl_lines and use_pygments arguments to the codehlite
	constructor
2016-10-15 23:38:32 -07:00
Tim Abbott
217212b773 run-mypy: Use the experimental new mypy cache.
This makes iteratively running mypy approximately 5x faster.

Fixes #1981.
2016-10-15 22:57:11 -07:00
Tim Abbott
9e503f2dcf run-mypy: Check scripts by default.
Previously, we checked scripts in a separate run to work around mypy
not supporting multiple scripts with the same name.  Since we have
fixed that issue, we can restore the original behavior.

We leave the --scripts-only option available, though I'm not sure it's
particularly useful and we'll probably eventually remove it.
2016-10-15 22:53:29 -07:00
Tim Abbott
4dbdf7e373 run-mypy: Consolidate exclude lists. 2016-10-15 22:53:29 -07:00
Tim Abbott
67e9f35f6f run-mypy: Use new --scripts-are-modules argument.
This allows us to check all the Zulip scripts in just 3s, rather than
inefficiently looping through all the Zulip scripts.
2016-10-15 22:53:29 -07:00
Tim Abbott
1a751af148 run-mypy: Exclude puppet/zulip_internal. 2016-10-15 22:53:29 -07:00
Tim Abbott
2e50dce9dd check_queue_worker_errors: Don't import zproject.settings directly. 2016-10-15 22:53:28 -07:00
Tim Abbott
7c16172f9e node_cache: Fix buggy annotations for stdout/stderr. 2016-10-15 22:53:28 -07:00
Tim Abbott
913d913c90 puppet: Annotate Nagios plugins. 2016-10-15 22:44:15 -07:00
Tim Abbott
458e455b75 Annotate process_fts_updates. 2016-10-15 22:44:15 -07:00
Tim Abbott
37722fa650 Annotate remaining scripts. 2016-10-15 22:36:10 -07:00
Tim Abbott
400e3b7dba Annotate API scripts. 2016-10-15 22:36:10 -07:00
Tim Abbott
172809d4e2 Annotate the rest of scripts in tools/. 2016-10-15 22:36:10 -07:00
Tim Abbott
75daba345a Finish annotating test-backend. 2016-10-15 22:36:10 -07:00
Tim Abbott
58a8934a86 tools: Remove unused post-receive script. 2016-10-15 22:36:10 -07:00
Tim Abbott
1a2b593a7c tools: Remove now-unused update-deployment symlink. 2016-10-15 22:36:10 -07:00
Tim Abbott
0c5f419be0 Annotate test-queue-worker-reload. 2016-10-15 22:36:10 -07:00
Steve Howell
a85f9a951a subscriptions: Remove spurious error handling.
Remove error handling in stream_data.add_subscriber() that no
longer makes sense in a world where we track streams that we
are not yet subscribed to.
2016-10-15 21:36:38 -07:00
Steve Howell
6a6f45f525 streams: Handle stream/create event. 2016-10-15 21:36:38 -07:00
Steve Howell
dca5a3354e Extract stream_data.create_sub_from_server_data(). 2016-10-15 21:36:38 -07:00
Brock Whittaker
baa5de5230 Increase default emoji box size.
Set the default emoji box size height to 140px rather than 60px, so
you can see more than one row of text.
2016-10-15 12:29:05 -07:00
Abhishek Kumar Singh
87c94a8697 docs/writing-views: Fix minor typo.
I found this typo while reading the blog written about
[mypy](http://blog.zulip.org/2016/10/13/static-types-in-python-oh-mypy/)
2016-10-15 12:26:40 -07:00
Tim Abbott
66df520cbe docs: Add a section on CalledProcessorError issues when provisioning.
Inspired by @deekshaarul's work on
https://github.com/zulip/zulip/pull/1939.
2016-10-14 21:29:27 -07:00
Brock Whittaker
33c6960980 New Emoji Popover Dragging Mechanism.
This is a new mechanism to replicate the behavior of Emoji Box
drag-to-resize without the adverse effects of the last iteration — such
as not being able to drag to select text in the compose box.
2016-10-14 21:29:03 -07:00
Tim Abbott
8821b269bf flush-memcached: Replace 'set -x' with more clear output.
Similar to `terminate-psql-sessions`, this was just unnecessary spam
output.
2016-10-14 17:10:06 -07:00
Tim Abbott
382c8853f3 terminate-psql-sessions: Remove set -x.
Now that we're no longer actively debugging this tool, there's no need
to have it print everything it's doing.

This will make `test-backend` a lot nicer to use.
2016-10-14 17:08:05 -07:00
Tomasz Kolek
92bfadcca4 Normalize github pull requests event message.
Add detailed info (description, source and target branch, assignee) to message.
Change subject to 'repo_name / PR #id title'.
Modify some test fixtures for better coverage.
2016-10-14 16:54:13 -07:00
Tomasz Kolek
ce9ac30fac Normalize bitbucket pull requests event message.
Add detailed info (description, source and target branch, assignee) to message.
Change subject to 'repo_name / PR #id title'.
Modify some test fixtures for better coverage.
2016-10-14 16:54:13 -07:00
Tomasz Kolek
421c51cc14 Normalize gitlab pull requests event message.
Add detailed info (description, source and target branch, assignee) to message.
Change subject to 'repo_name / MR #id title'.
Modify some test fixtures for better coverage.

Fixes: #1883.
2016-10-14 16:54:13 -07:00
Tomasz Kolek
2941c1f517 Move converting commits data to text to separate function.
Create get_commits_content function for converting
commits list to text.
2016-10-14 16:54:13 -07:00
Tomasz Kolek
d2cedd3667 Rename consts in lib/webhooks/git.py to make it more general.
Rename:
   PUSH_COMMITS_LIMIT to COMMITS_LIMIT
   PUSH_COMMIT_ROW_TEMPLATE to COMMIT_ROW_TEMPLATE
   PUSH_COMMITS_MORE_THAN_LIMIT_TEMPLATE to COMMITS_MORE_THAN_LIMIT_TEMPLATE
2016-10-14 16:54:13 -07:00
Tomasz Kolek
ee70cc5141 Add git integration method to build message for pull requests events. 2016-10-14 16:54:13 -07:00
Tomasz Kolek
0f01150449 Add bitbucket tests for push, push a lot of commits and force push events. 2016-10-14 16:54:13 -07:00
Tomasz Kolek
165cdb79d9 Rename bitbucket2 fixtures directory to bitbucket.
Rename all bitbucket fixtrues from bitbucket2.* to bitbucket_v2.*.
2016-10-14 16:54:13 -07:00
sonali0901
66a740b5c1 Architecture docs: Reposition backtick for address of Nagios plugin 2016-10-14 16:25:25 -07:00
umkay
bfbf07fde2 Update pinned SQLAlchemy requirement to latest upstream version.
The prerequisite to this change is
278574a6ec
2016-10-14 14:45:43 -07:00
umkay
278574a6ec Fix cursor() arguments for connection classes.
In order to use the latest version of psycopg2 with the latest version
of sqlalchemy we must integrate the changes made in the 2.4.6 release of
psycopg2. See
c86ca7687f
and the release notes for psycopg2 2.4.6.
2016-10-14 13:35:06 -07:00
Tim Abbott
0b7b15b361 subs: Reorganize encoding code a bit. 2016-10-14 12:34:01 -07:00
Tim Abbott
eb5ef03ec0 subs: Encode stream names before changing stream names. 2016-10-14 12:34:00 -07:00
Mohsen Ibrahim
74baee93fa subs: Encode stream names before updating stream descriptions.
The API uses this endpoint /json/streams/<stream_name> to update
stream information such as description, since the stream_name is
part of the URI it should be encoded to escape unsafe characters.

Fixes #1986.
2016-10-14 12:33:55 -07:00
Rishi Gupta
82b814a1cd analytics: Simplify frequency and measurement interval options.
Change the CountStat object to take an is_gauge variable instead of a
smallest_interval variable. Previously, (smallest_interval, frequency)
could be any of (hour, hour), (hour, day), (hour, gauge), (day, hour),
(day, day), or (day, gauge).
The current change is equivalent to excluding (hour, day) and (day, hour)
from the list above.

This change, along with other recent changes, allows us to simplify how we
handle time intervals. This commit also removes the TimeInterval object.
2016-10-14 10:18:37 -07:00
Rishi Gupta
807520411b analytics: Simplify logic in do_fill_count_stat_at_hour.
Adding FillState, removing do_aggregate_hour_to_day, and disallowing unused
(interval, frequency) pairs removes the need for the nested for loops in
do_fill_count_stat_at_hour. This commit replaces that control flow with a
simpler equivalent.
2016-10-14 10:18:37 -07:00
Rishi Gupta
27d1360e1d analytics: Remove do_aggregate_hour_to_day.
The functionality provided is more naturally done in the views code. It also
allows us to aggregate using day boundaries from the local timezone, rather
than UTC.
2016-10-14 10:18:37 -07:00
Rishi Gupta
655ee51e35 analytics: Add table to keep track of fill state.
Adds two simplifying assumptions to how we process analytics stats:
* Sets the atomic unit of work to: a stat processed at an hour boundary.
* For any given stat, only allows these atomic units of work to be processed
  in chronological order.

Adds a table FillState that, for each stat, keeps track of the last unit of
work that was processed.
2016-10-14 10:18:37 -07:00
umkay
721529b782 analytics: Remove HuddleCount for now.
Planned changes to the underlying analytics model will require potentially
complicated changes to huddle queries.
2016-10-14 10:18:37 -07:00
Umair Khan
7787b780bc Period should be part of the translation. 2016-10-13 15:07:37 -07:00
Umair Khan
f1007de0f4 Handle invite remaining translation in JS.
Since we use JavaScript to insert this text, sever side tags will not
be able to handle this translation correctly.
2016-10-13 15:07:37 -07:00
Umair Khan
ca0681a98b Use block translation tag where appropriate. 2016-10-13 15:07:37 -07:00
Vikas Parashar
08b61c1b3d Fix z-index of desktop app recommendation banner.
Change banner container's z-index so it's stay on top.

Fixes #1862.
2016-10-13 09:13:45 -07:00
Umair Khan
624f79a892 Use a version of Talon hardcoded to use the --no-ml argument.
This works around https://github.com/pypa/pip/issues/3845, where the
`--install-option` argument was incorrectly polluting other
dependencies).
2016-10-12 22:32:34 -07:00
Steve Howell
a845b15a54 casper: Remove then_log_out flakiness and sleep.
We were getting flakes from then_log_out() due to it
making an assert too early.  With this race condition removed,
I can run without the 0.3 sleep.
2016-10-12 22:03:55 -07:00
Tim Abbott
ea075dd043 Update translations from transifex. 2016-10-12 09:59:01 -07:00
Tim Abbott
14f6e4c740 scripts: Stop using apt-add-repository.
Unfortunately, apt-add-repository is highly unreliable and was causing
problems both in Travis CI and with developers provisioning their
environment.
2016-10-11 22:10:36 -07:00
Tim Abbott
e2810ca1be docs: Update path to update_realm code. 2016-10-11 21:28:14 -07:00
Tim Abbott
8f145e03cf views: split events_register.py from main views file. 2016-10-11 21:27:06 -07:00
Tim Abbott
0c02015541 views: Move one-click unsubscribe to its own file. 2016-10-11 21:27:06 -07:00
Tim Abbott
5b7dfafcac views: Move json_refer_friend to invite.py. 2016-10-11 21:27:06 -07:00
Tim Abbott
dd352dd456 views: Move invitation views to their own file. 2016-10-11 21:27:06 -07:00
Tim Abbott
67d9e19ccf views: Split views/auth.py out of core views file. 2016-10-11 21:27:06 -07:00
Tim Abbott
dd61f136a5 filter: Add is: to operator_to_prefix logic. 2016-10-11 21:01:01 -07:00
Tim Abbott
d2be9241f2 feature_flags: Eliminate always true negated_search feature. 2016-10-11 20:50:47 -07:00
umkay
7e2340155d analytics: Fix aggregation to RealmCount for realms with no users.
Previously, if a Realm had no users (or no streams),
do_aggregate_to_summary_table would fail to add a row with value 0. This
commit fixes the issue and also simplifies the do_aggregate_to_summary_table
logic.
2016-10-11 18:20:58 -07:00
Rishi Gupta
52b56cca65 analytics: Reorder arguments to assertCountEquals.
Require a table argument and change argument order around for clarity.
2016-10-11 18:20:58 -07:00
Kartik Maji
9807ec6539 Fix phrasing when re-subscribing user to a stream. 2016-10-11 18:19:57 -07:00
Kartik Maji
6d57e2a646 stream_data: Remove user from subscriber list on unsubscribe.
This fixes a bug where the .subscribers property of a subscription
object in stream_data wasn't being properly updated to remove the
current user when the current user unsubscribed from the stream.

Fixes #1667.
2016-10-11 18:19:03 -07:00
Tim Abbott
c886bd9065 do_update_message_flags: test starring historical messages. 2016-10-11 17:38:39 -07:00
Tim Abbott
0f1468e64f do_update_message_flags: Use access_message for check. 2016-10-11 17:20:15 -07:00
Tim Abbott
f1a399a4e1 message: Create new access_message library function.
With reactions and other upcoming features, we'll be adding several
places where we need to check whether a particular user can access a
particular message.  It's best to just have a single helper function
for this purpose that we can use everywhere.
2016-10-11 17:17:19 -07:00
Tim Abbott
d2e41ff48e json_fetch_raw_message: Allow fetching messages you received.
This also modifies the tests to verify that the user in question has
access to the relevant message.
2016-10-11 17:17:19 -07:00
Kartik Maji
b38b186aef timerender: Export render_now.
This makes it possible to use this logic for the message edit history
feature.
2016-10-11 16:48:05 -07:00
Tim Abbott
de5c1eb363 docs: Move glossary to bottom of architecture overview.
I think the old place where we had it broke up the flow.

Once this is about twice as long as it is currently, we should move it
to be its own document.
2016-10-11 16:44:39 -07:00
Sumana Harihareswara
7fee09458b Add starring to glossary. 2016-10-11 16:44:39 -07:00
Sumana Harihareswara
f1593b243c docs: Add chevron and message editing to glossary. 2016-10-11 16:44:39 -07:00
Sumana Harihareswara
d9c81dcfdd docs: Add recipient bar to usage assumptions/concepts.
Add start of glossary section.
2016-10-11 16:44:39 -07:00
Umair Khan
36c6a5d758 Add support for changing user's name by admin.
Fixes: #1553
2016-10-11 16:36:48 -07:00
Umair Khan
b886e38a58 Increase test quality for GitHubAuthBackendTest. 2016-10-11 16:19:55 -07:00
Umair Khan
4fcd36b124 Add negative tests for Social auth backend.
Fixes: #1948
2016-10-11 16:19:55 -07:00
Rishi Gupta
d75731f988 Realm creation flow: Remove invite page.
Previously, we sent users to an "invite your friends" page after they
created an organization. This commit removes that step in the flow and sends
users directly to the home page. We also remove the now-unused
initial_invite_page.html template, initial_invite.js (which pre-filled the
invite emails with characters from literature), and the /invite URL route.
2016-10-11 15:54:05 -07:00
Tim Abbott
d5f28abac7 casper: Use zulipdev.com rather than localhost consistently.
This fixes a problem where any absolute redirects in the routes
visited by the Casper tests will cause failures due to switching the
users to a "different" server where the cookies they'd received are no
longer valid.

Now, we at least consistently use the same hostname in the Casper
tests as EXTERNAL_HOST.
2016-10-11 15:54:05 -07:00
Brock Whittaker
3494fa0635 Add lightbox media queries.
Add media queries to hide the image actions if on mobile (probably
unnecessary to have), and make the image description (name, author)
close to full width.
2016-10-11 15:22:31 -07:00
Brock Whittaker
162ee29aee Lightbox Overlay Style Fixes.
This fixes two minor issues with the lightbox styling:

1. The width was not supposed to be calc(100% - 20px) anymore. It now
should just be full width.

2. The exit button was not vertically aligned exactly nor horizontally
centered between the edge of the nearest button and the edge of the
screen. Both are fixed with the new margin.
2016-10-11 15:22:14 -07:00
Christie Koehler
952d91f60a docs: Fix broken image links on prod install page. 2016-10-11 15:19:43 -07:00
K.Kanakhin
7c3ffa6790 travis-ci: add production Python 3 test suite.
- Add production testing to .travis.yml file for PY3 env

Fixes #1710.
2016-10-11 14:19:03 -07:00
K.Kanakhin
14545d1647 create-production-venv: Add PY3 support to production venv creation script.
Create production python virtual env based on system python version.
2016-10-11 14:19:00 -07:00
K.Kanakhin
e7642daa2a py3_prod: Add py3 production requirements file. 2016-10-11 14:19:00 -07:00
Supriya
598c7a506b docs/custom-apps: Fix spelling error. 2016-10-11 13:39:59 -07:00
Christie Koehler
24e2690ec2 tools: Improve git scripts.
Minor fixes that enable the ability to:

- Re-run fetch-rebase-pull-request.
- Specify the name of the remote repo as an optional second parameter.
  The default remains 'upstream'.
2016-10-11 13:38:38 -07:00
Eklavya Sharma
41587edd2e bugdown: Change parameter name.
Change the parameter name of some functions from 'md' to 'content',
since the name 'md' seems to be the reason why this parameter was
wrongly annotated.
2016-10-11 11:31:01 -07:00
Eklavya Sharma
f35d0f1c75 bugdown: Fix type annotations.
In some functions the first parameter was wrongly annotated as
`markdown.Markdown`. Change that to `text_type`.
2016-10-11 11:31:01 -07:00
Eklavya Sharma
81617fcdb0 Annotate zerver/tests/test_upload.py. 2016-10-11 11:29:14 -07:00
Eklavya Sharma
f7092b1a90 Annotate zerver/tests/test_email_mirror.py. 2016-10-11 11:28:52 -07:00
Eklavya Sharma
b741c7351d email_mirror: Use correct string types. 2016-10-11 11:27:35 -07:00
Eklavya Sharma
ccce3ec0be zerver/lib/digest.py: Fix a type annotation. 2016-10-11 11:27:35 -07:00
Eklavya Sharma
d92368e0f5 test_email_mirror: Add trivial annotations.
Add annotations of the form `type: () -> None` to test methods.
2016-10-11 11:27:35 -07:00
Eklavya Sharma
1dbabfe1ab Annotate zerver/tests/test_bugdown.py. 2016-10-11 11:27:35 -07:00
Eklavya Sharma
8e2f659f3d test_bugdown: Add trivial annotations.
Add annotations of the form `type: () -> None` to test methods.
2016-10-11 11:27:35 -07:00
Kouhei Sutou
c2b4fd86e4 settings: Combine split words for translators 2016-10-11 22:40:47 +09:00
Tim Abbott
7639dc87a8 Revert "requirements: Install the Zulip API bindings by default."
This reverts commit de5b6d9e37.

This change appears to have caused problems provisioning due to a
conflict with the `--install-option` feature used by talon.
2016-10-10 23:36:01 -07:00
Tim Abbott
de5b6d9e37 requirements: Install the Zulip API bindings by default.
Fixes: #1957.
2016-10-10 17:41:46 -07:00
Tomasz Kolek
8fa9ee1473 Add github tests for commits more than limit. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
ad5d5f2c99 Add beanstalk tests for commits more than limit. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
07003ca52d Add gitlab tests for commits more than limit. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
a3e4415614 Add bitbucket2 tests for commits more than limit. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
6fc1193743 Add to gitlab remove branch message handler. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
312905007e Add EMPTY_SHA const to zerver/lib/webhooks/git.py. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
89ef6c73d1 Normalize github and beanstalk remove branch event message. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
56208d7ea1 Add bitbucket2 remove branch message handler. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
b031d6b029 Add bitbucket2 force push event handler. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
b69b5e55ce Add git integration method to build message for remove branch events.
Add get_remove_branch_event_message method to zerver/lib/webhooks/git.py
for normalizing remove branch message in all git integrations.
2016-10-10 17:39:05 -07:00
Tomasz Kolek
f084dd05a8 Normalize github and beanstalk force push event message. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
5f7c1519d1 Add git integration method to build message for force push events.
Add get_force_push_commits_event_message method to zerver/lib/webhooks/git.py
for normalizing force push message in all git integrations.
2016-10-10 17:39:05 -07:00
Tomasz Kolek
e56e3f4aee Normalize bitbucket2 push event subject. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
741a91d249 Normalize bitbucket push event subject. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
1f0f197479 Normalize github and beanstalk push event subjects. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
32934a02e9 Add template for subject that contains repo name and branch name. 2016-10-10 17:39:05 -07:00
Tomasz Kolek
bc4ce7e781 Normalize gitlab push event message.
Fixes: #1884.
2016-10-10 17:39:05 -07:00
Tomasz Kolek
6a727bc476 Normalize bitbucket2 push event.
Normalize bitbukcet2 push event by creating it by
get_push_commits_event_message common function.
2016-10-10 17:39:05 -07:00
Tomasz Kolek
06ad0102a2 Remove now-unused build_commit_list_content. 2016-10-10 17:38:41 -07:00
Tomasz Kolek
809bc5f29b Normalize bitbucket push event.
Normalize bitbukcet push event by creating it by
get_push_commits_event_message common function.
2016-10-10 17:33:02 -07:00
Tomasz Kolek
1c1a003ba1 Normalize github push event.
Normalize github push event by creating it by
get_push_commits_event_message common function.
2016-10-10 17:33:02 -07:00
Tomasz Kolek
8697a1e5a2 Add common git integration method to build message for push events.
This adds get_push_commits_event_message method to
zerver/lib/webhooks/git.py for normalizing push messages in all git
integrations.
2016-10-10 17:32:41 -07:00
Tim Abbott
fec6527656 dev-overview: Document cloud server option. 2016-10-10 17:10:39 -07:00
zeddmaxx
1348b9dde3 dev-overview: Improve organization of installation overview page.
Fixes #1814.

[substantially tweaked by tabbott]
2016-10-10 17:06:59 -07:00
reyha
34766e38c3 irc-mirror: Update the installation link.
This updates the link to python-irc to its current URL.
2016-10-10 16:23:11 -07:00
Ilona Brand
4bf908c2d6 Add emoji map to the compose box.
- Expand a box full of emojis into the
compose window for users to graphically select emojis.

- Append an emoji to the end of the message when a user
clicks the emoji in the emoji box.

- Trap the escape key to always close the emoji box
before closing anything else if the box is open.

- Fixes: #147.
2016-10-10 16:12:25 -07:00
Umair Khan
da86429378 Create emoji name to css class mapping.
`glue` ingores the + sign in the name of the emoji and creates the css
class without it. This causes the emoji pallete to miss '+1'
emoji. This commit creates a translation map from emoji name to css
class that we can use for the emoji popover.
2016-10-10 16:09:23 -07:00
Umair Khan
e0c10ed1e8 Cache emoji dump output.
This saves a bunch of time building release tarballs, provisioning,
and upgrading Zulip from git that was spent regenerating the Zulip
emoji sprite sheet.

[commit message tweaked by tabbott]
2016-10-10 11:15:43 -07:00
Kartik Maji
e7f6f40100 Add test to check add peer event recipients. 2016-10-10 10:54:14 -07:00
K.Kanakhin
e104943e12 storage: Fix build-release-tarball py3 compatibility.
- Open files in storage.py with 'rb' mode
  which allow to use decode command in PY3.
2016-10-10 09:54:51 -07:00
Umair Khan
eb7ce73628 Move name_changes_disabled to zerver.models 2016-10-10 09:27:52 -07:00
Umair Khan
4fa427bc74 auth_backends: Add backend tests for subdomains logic.
Fixes: #1870
2016-10-10 08:55:39 -07:00
Umair Khan
a32cee4b10 Add test to show error msg for invalid subdomain. 2016-10-10 08:42:34 -07:00
Umair Khan
d0acda4635 Google: Show error on login page for wrong subdomain.
Takes care of Google OAuth.

Fixes: #1871
2016-10-10 08:42:34 -07:00
Umair Khan
c23aaa1785 GitHub: Show error on login page for wrong subdomain.
While logging in through GitHub, if the user tries to login
to the wrong subdomain then show an appropriate message.
2016-10-10 08:42:34 -07:00
Kouhei Sutou
aeb3d5e234 accounts_accept_terms: Use trans tag for translators.
It's based on "Backend Translations" policy:
https://zulip.readthedocs.io/en/latest/translating.html#backend-translations
2016-10-10 08:40:55 -07:00
Bertrand Croq
c705819f2d custom-apps docs: Fix stumulus typo. 2016-10-10 08:38:51 -07:00
Umair Khan
d7efdf050c Ignore docs directory while creating translation strings.
Fixes: #1941.
2016-10-10 08:23:56 -07:00
Umair Khan
a9343a65d5 Don't localize javascript comments.
Fixes: #1934.
2016-10-10 08:21:02 -07:00
Kouhei Sutou
d7bef86d26 settings: Add missing translation tag.
User list side name must be translatable.
2016-10-09 23:12:41 -07:00
Rishi Gupta
929b69397b analytics: Change string representation of BaseCount models.
Previously we showed both the value and the id of the BaseCount record,
which is confusing in a typical case where you only care about the value,
and both the value and id are smallish ints.
2016-10-09 16:09:04 -07:00
Rishi Gupta
c6b611c8b9 analytics: Re-organize tests into higher level TestClasses.
Refactor the current analytics tests into the following classes:
* TestUpdateAnalyticsCounts, which will eventually test the management
  command, backfilling, what happens when new tests are added, etc.
* TestProcessCountStat, which tests the ins and outs of propagating the
  value of a single stat up through the various *Count tables.
* TestAggregates, which tests the do_aggregate_* methods.
* TestXByYQueries, which tests the count_X_by_Y_query SQL snippets.
* TestCountStats, which has tests for individual CountStats.

This commit does not change the name or contents of any individual test.
2016-10-09 16:09:04 -07:00
Rishi Gupta
795d10b9ad analytics: Refactor tests to simplify asserts of count values.
Many tests are structured to run some process, and then check a count in a
BaseCount record using default values for realm, property, interval, and
end_time. This commit adds a new assertCountEquals method to
AnalyticsTestCase, and simplifies other assert calls as appropriate.
2016-10-09 16:09:04 -07:00
Rishi Gupta
35cf9092d5 analytics: Canonicalize creation of model objects in tests.
Add a default_realm object to AnalyticsTestCase, created 2 days before
AnalyticsTestCase.TIME_ZERO.

Add lightweight create_user, create_stream, and create_message methods to
AnalyticsTestCase, with sensible defaults. In particular, all objects are by
default created at AnalyticsTestCase.TIME_LAST_HOUR, so that they are
included when running AnalyticsTestCase.process_last_hour.
2016-10-09 16:09:04 -07:00
Rishi Gupta
6996b21480 analytics: Change tests to use a fixed TIME_ZERO.
Previously, analytics tests used timezone.now or custom datetime objects
when creating new realms, users, and streams.

This commit adds a fixed TIME_ZERO and a process_last_hour helper function
in a new AnalyticsTestCase class, and modifies the existing tests to use
them.
2016-10-09 16:09:04 -07:00
Kouhei Sutou
638d9ee262 markdown: Make subscribe notification translator friendly.
Some languages such as Japanese use different word order with
English. If the stream name must be the last word, translating to these
languages is difficult.
2016-10-09 11:19:19 -07:00
sonali0901
5623fa9994 request docs: Fix typo in spelling of "parameter". 2016-10-09 11:13:49 -07:00
Katy310
5d0960ae04 Change color of inline code from red to black.
This makes inline code blocks look nicer.

Fixes #1223.
2016-10-09 11:02:18 -07:00
Steve Howell
0bdc9fef5c Upgrade caspersjs to version 1.1.3. (w/acrefoot)
(Most of this work was done by acrefoot in an earlier branch.
I took over the branch to fix casper tests that were broken during
the upgrade (which were fixed in a different commit).  I also
made most of the changes to run-casper.)

This also upgrades phantomjs to 2.1.7.

The huge structural change here is that we no longer vendor casperjs
or download phantomjs with our own script.  Instead, we just use
casperjs and phantomjs from npm, via package.json.

Another thing that we do now is run casperjs tests individually, so
that we don't get strange test flakes from test interactions.  (Tests
can still influence each other in terms of changing data, since we
don't yet have code to clear the test database in between tests.)

A lot of this diff is just removing files and obsolete configurations.

The main new piece is in package.json, which causes npm to install the
new version.

Also, run-casper now runs files individually, as mentioned above.

We had vendored casperjs in the past.  I didn't bring over any of our
changes.  Some of the changes were performance-related (primarily
5fd58cf249), so the upgraded version may
be slower in some instances.  (I didn't do much measurement of that,
since most of our slowness when running tests is about the setup
environment, not casper itself.)  Any bug fixes that we may have
implemented in the past were either magically fixed by changes to
casper itself or by improvements we have made in the tests themselves
over the years.

Tim tested the Casper suite on his machine and running the full Casper
test suite is faster than it was before this change (1m30 vs. 1m50),
so we're at least not regressing overall performance.
2016-10-08 12:08:43 -07:00
Rishi Gupta
7707d2a005 test-backend: remove trailing forward slash from test suite names.
Previously, running `tools/test-backend analytics/` (or any other test suite
name ending with a '/') would give a cryptic error about modules not
importing properly. This commit rstrip's the trailing slash from test suite
names given on the command line.
2016-10-08 11:52:55 -07:00
Rishi Gupta
ea050d5fd8 test_runner: Fix error message for failed import.
Previously, we suggested running
`python -c import zerver.tests.test_mytest`
when importing test_mytest failed, which doesn't work.

This commit adds the missing quotes, making it
`python -c 'import zerver.tests.test_mytest'`
2016-10-08 11:51:53 -07:00
Eklavya Sharma
4b1a2adca5 provision.py: Don't create py2 venv in py3 mode.
When running tools/provision.py in python3 mode, we used to create
a python2 venv called zulip-py2-twisted-venv. This was needed because
Zulip couldn't run tools/run-dev.py in python3. So we switched to
this virtualenv when running tools/run-dev.py.

Now that Zulip can run tools/run-dev.py in python3, we don't need
to create this virtualenv anymore.
2016-10-07 13:39:37 -07:00
Steve Howell
4400cb3735 casper: Prepare 11-mention.js for upgrade.
Use common.turn_off_press_enter_to_send() and look at the
correct element for visibility.
2016-10-07 13:30:11 -07:00
Steve Howell
b5fed72dd7 casper: Use better messages in 10-admin.js. 2016-10-07 13:30:11 -07:00
Steve Howell
384dd23058 casper: Rewrite 09-navigation.js. 2016-10-07 13:30:11 -07:00
Steve Howell
52659ccae4 casper: Improve 06-settings.js.
Use higher level selectors to detect visibility of key components.

Also click through the menu more explicitly.
2016-10-07 13:30:11 -07:00
Steve Howell
a8821b3057 casper: Click through menu in 05-subscriptions.js. 2016-10-07 13:30:11 -07:00
Steve Howell
49724d1ac3 casper: Use better selectors in 04-compose.js. 2016-10-07 13:30:11 -07:00
Steve Howell
0ded74e9de casper: Use then_log_out() in 01-login.js 2016-10-07 13:30:11 -07:00
Steve Howell
69694b77fb casper: Improve common.js.
These changes prepare us for the casperjs upgrade:

    Extract init_viewport().
    Have then_log_out() do more explicit waiting.
    Add turn_off_press_enter_to_send().
2016-10-07 13:30:11 -07:00
Tim Abbott
a4b2a6b6d4 puppet: Fix missing dependency for supervisor enabling.
You can't run `systemctl enable` on a service before the package
containing the service is installed.
2016-10-06 21:44:10 -07:00
K.Kanakhin
06e70e1fbd run-dev-proxy: Fix twisted py3 compatibility.
- All necessary strings was converted to bytestring
 - Added twisted as py3 dependency
 - Change type annotation for method getchild of class Resource
 - Remove activating python2 env section from run-dev.py script

Fixes #1256
2016-10-06 20:21:25 -07:00
umkay
78477ea071 Reorder the columns in analytics tables inherited from BaseCount.
This is primarily implemented through altering the migration file in
order to move the columns, but also we try to make the defaults a
little better for future tables inherited from BaseCount.
2016-10-06 17:51:01 -07:00
Diptanshu8
d7253b144c generate-secrets: Refactor to make development/production explicit.
generate-secrets.py now requires --development for development environment
setup or --production for production environment setup (and one of these
options is mandatory).

This solves the problem that it was somewhat easy to accidentally run
generate-secrets.py without the `-d` option while doing manual development
environment setup.

Fixes: #1911.
2016-10-06 17:12:49 -07:00
umkay
01324f2afe Fix aggregation to analytics summary tables.
There are a number of different stats that need to be propagated from
UserCount and StreamCount to RealmCount, and from RealmCount to
InstallationCount. Stats with hour intervals also need to have their day
values propagated. This commit fixes a bug in the summary table aggregation
logic so that for a given interval on a CountStat object we pull the correct
counts for the interval as well as do the day aggregation if required. We Also
ensure that any aggregation then done from the realmcount
table to the installationcount table follows the same aggregation logic
for intervals.
2016-10-06 08:46:33 -07:00
Rishi Gupta
ff4d059595 Message editing: add explanation when past message edit deadline.
Adds "Topic editing only" along with the tooltip explanation to lower right
of message editing box when it's past the message content editing deadline.
2016-10-05 22:42:56 -07:00
Brock Whittaker
cc8b8c1614 Separate default streams list from admin_tab template.
This separates default streams list settings into its own template in
the templates/settings folder.
2016-10-05 22:27:15 -07:00
Brock Whittaker
7be19dd860 Separate streams list from admin_tab template.
This separates streams list settings into its own template in the
templates/settings folder.
2016-10-05 22:27:15 -07:00
Brock Whittaker
b196fb9798 Separate bot list from admin_tab template.
This separates bot list settings into its own template in the
templates/settings folder.
2016-10-05 22:27:15 -07:00
Brock Whittaker
a56379e4d7 Separate deactivated user list from admin_tab template.
This separates deactivated user list settings into its own template in
the
templates/settings folder.
2016-10-05 22:27:15 -07:00
Brock Whittaker
ecb6c7df40 Separate user list from admin_tab template.
This separates user list settings into its own template in the
templates/settings folder.
2016-10-05 22:27:15 -07:00
Brock Whittaker
d2f3e9eb7f Separate emoji settings from admin_tab template.
This separates emoji settings into its own template in the
templates/settings folder.
2016-10-05 22:27:15 -07:00
Brock Whittaker
403c6322ae Separate organization settings from admin_tab template.
This separates organization settings into its own template in the
templates/settings folder.
2016-10-05 22:27:15 -07:00
Brock Whittaker
b81967d6ef Separate account settings from settings_tab template.
This separates account settings into its own template in the
templates/settings folder.
2016-10-05 22:27:15 -07:00
Brock Whittaker
26fda72157 Separate UI settings from settings_tab template.
This separates UI settings into its own template in the
templates/settings folder.
2016-10-05 22:27:15 -07:00
Brock Whittaker
330edddeff Separate alert word settings from settings_tab template.
This separates alert word settings into its own template in the
templates/settings folder.
2016-10-05 22:27:15 -07:00
Brock Whittaker
68b8a7b40d Separate bot settings from settings_tab template.
This separates bot settings into its own template in the
templates/settings folder.
2016-10-05 22:27:14 -07:00
Brock Whittaker
aca78df56f Separate notification settings from settings_tab template.
This separates notification settings into its own template in the
templates/settings folder.
2016-10-05 22:27:14 -07:00
Brock Whittaker
ff3d5ca4db Separate display settings from settings_tab.handlebars.
This separates the display settings module from the
settings_table.handlebars template.

Additionally, it fixes the node tests to search in the
static/templates/settings directory and initialize any templates in there
while running tests on the settings templates.
2016-10-05 22:26:40 -07:00
Brock Whittaker
3efe3601b8 Allow for templates/settings to be read and compiled.
This allows for the handlebars templates in the template/settings
subdirectory to be found and compiled.
2016-10-05 22:24:22 -07:00
Tim Abbott
82764d0215 run-dev: Display the port 9991 warning in colored text. 2016-10-05 22:07:46 -07:00
Feorlen
e09c27f1ae run-dev.py: Log what service is being started on which port.
The new messages make it more obvious which services are started
from run-dev.py, and explicitly call out where to access the web
proxy to reach the Zulip web UI. This is a common confusion for
new administrators/developers. Messages are output before the
processes are launched, as run-dev.py does not currently have a
way to know if they started successfully.

Example output:

Starting Zulip services on ports:  web proxy: 9991, Django: 9992, Tornado: 9993, webpack: 9994
Note: only port 9991 is exposed to the host in a Vagrant environment.

Alternate behavior for automated testing:

If run-dev.py is invoked with --test, don't include the webpack
port as it isn't used.

Tested on Ubuntu 14.04, by running run-dev.py at a shell prompt and
via the test-all script.

Fixes #1861
2016-10-05 22:07:46 -07:00
Tim Abbott
d0f295c77f docs: Clarify commit message portion of version control docs. 2016-10-05 19:28:21 -07:00
Rishi Gupta
d387012bc6 Fix EXTERNAL_HOST computations in test_settings.py.
test_settings.py was setting EXTERNAL_HOST after importing settings.py,
which has several variables (like SERVER_URI) that are computed from
EXTERNAL_HOST.

[tweaked by tabbott to add comments explaining the story here].
2016-10-05 19:04:55 -07:00
Tim Abbott
5357b286b2 docs: Fix typo in spelling of generate_secrets. 2016-10-05 17:47:14 -07:00
Tim Abbott
273c17a072 update_analytics_counts: Add missing future imports. 2016-10-05 17:13:46 -07:00
umkay
5d0bed8673 Add script to clear analytics tables. 2016-10-05 17:11:13 -07:00
Rishi Gupta
777fcaa6a0 Add new organization type field to Realm objects.
Adds a new field org_type to Realm.  Defaults for restricted_to_domain
and invite_required are now controlled by org_type at time of realm
creation (see zerver.lib.actions.do_create_realm), rather than at the
database level.  Note that the backend defaults are all
org_type=corporate, since that matches the current assumptions in the
codebase, whereas the frontend default is org_type=community, since if
a user isn't sure they probably want community.

Since we will likely in the future enable/disable various
administrative features based on whether an organization is corporate
or community, we discuss those issues in the realm creation form.
Before we actually implement any such features, we'll want to make
sure users understand what type of organization they are a member of.

Choice of org_type (via radio button) has been added to the realm
creation flow and the realm creation management command, and the
open-realm option removed.

The database defaults have not been changed, which allows our testing code
to work unchanged.

[includes some HTML/CSS work by Brock Whittaker to make it look nice]
2016-10-05 17:01:46 -07:00
Tomasz Kolek
dbeab6aa6f Optimize checks of test database state by moving into Python.
Previously, the generate-fixtures shell script by called into Django
multiple times in order to check whether the database was in a
reasonable state.  Since there's a lot of overhead to starting up
Django, this resulted in `test-backend` and `test-js-with-casper`
being quite slow to run a single small test (2.8s or so) even on my
very fast laptop.

We fix this is by moving the checks into a new Python library, so that
we can avoid paying the Django startup overhead 3 times unnecessarily.
The result saves about 1.2s (~40%) from the time required to run a
single backend test.

Fixes #1221.
2016-10-05 10:40:19 -07:00
Tim Abbott
498317d533 Fix renaming streams on web to use new API.
In 142dce2cd4, we replaced the API for
renaming a stream, but failed to actually update the javascript to use
the new API.
2016-10-04 21:48:38 -07:00
Tim Abbott
3973ae5dbb update_analytics_counts: Fix buggy argument parsing. 2016-10-04 20:43:19 -07:00
Tim Abbott
a2b91221d0 upgrade-zulip: Only remove zproject/local_settings.py if symlink.
This fixes a problem where if we're deploying from git,
local_settings.py ends up part of the diff in the deployed git
repository.
2016-10-04 20:41:17 -07:00
Tomasz Kolek
7df50cee34 docs: Fix paths in webhooks part of integration-guide.
We forgot to update the documentation when we rearranged the webhooks
tests to be split across several files.

[mostly rewritten by tabbott]
2016-10-04 20:09:58 -07:00
Tim Abbott
49bea381b7 zjsunit: Fix running stream_data and node tests individually.
These tests failed if you ran them along with:
 `ReferenceError: $ is not defined` errors.

Fixes #1909.
2016-10-04 18:38:17 -07:00
umkay
b4108f7a5f Rerun add-apt-repository for ppa:groonga/ppa
On occasion, provisioning will fail because groonga is not added. Add a
check to see if the command fails and retry.
2016-10-04 18:21:36 -07:00
Tim Abbott
9b30594bb6 run-casper: Fix buggy comments about subdomains testing. 2016-10-04 18:16:53 -07:00
umkay
d260a22637 Add a new statistics/analytics framework.
This is a first pass at building a framework for collecting various
stats about realms, users, streams, etc. Includes:
* New analytics tables for storing counts data
* Raw SQL queries for pulling data from zerver/models.py tables
* Aggregation functions for aggregating hourly stats into daily stats, and
  aggregating user/stream level stats into realm level stats
* A management command for pulling the data

Note that counts.py was added to the linter exclude list due to errors
around %%s.
2016-10-04 17:18:54 -07:00
Steve Howell
43e21f6fb4 Remove unused bugdown global from models.py.
Fixes: #1379

(It was really a series of fixes leading up to this.)
2016-10-04 11:35:03 -07:00
Steve Howell
b2f84f0fa4 Move render_markdown() to lib/message.py.
This removes a bugdown circular dependency.
2016-10-04 11:34:53 -07:00
Steve Howell
b81a961fdd Remove Message.set_rendered_content(). 2016-10-04 11:31:21 -07:00
Steve Howell
d21d443d29 Deprecate render_old_messages command. 2016-10-04 11:31:21 -07:00
Steve Howell
7fb992dba3 Simplify and "fix" render_old_messages management command.
The command to render old messages now looks for all messages
not matching the bugdown version, and it no longer directly calls
into model code.  We should still be extremely cautious about
using this code.
2016-10-04 11:31:20 -07:00
Steve Howell
6b71f5bd5f Inline most calls to set_rendered_content().
This is part of breaking the circular dependency on
bugdown in models.py.  A subsequent commit will fully
kill off set_rendered_content().
2016-10-04 11:31:20 -07:00
Steve Howell
583a6bbadd Extract zerver/lib/message.py.
This pulls message-related code from models.py into a new
module called message.py, and it starts to break some bugdown
dependencies.  All the methods here are basically related to
serializing Message objects as dictionaries for caches and
events.

    extract_message_dict
    stringify_message_dict
    message_to_dict
    message_to_dict_json
    MessageDict.to_dict_uncached
    MessageDict.to_dict_uncached_helper
    MessageDict.build_dict_from_raw_db_row
    MessageDict.build_message_dict

This fix also removes a circular dependency related
to get_avatar_url.

Also, there was kind of a latent bug in Message.need_to_render_content
where it was depending on other calls to Message to import bugdown
and set it globally in the namespace.  We really need to just
eliminate the function, since it's so small and used by code that
may be doing very sketchy things, but for now I just fix it.  (The
bug would possibly be exposed by moving build_message_dict out to the
library.)
2016-10-04 11:31:20 -07:00
Steve Howell
ac994fdd51 Move three functions from models.py to lib/cache.py.
I move these three functions to lib/cache.py:

    to_dict_cache_key_id
    to_dict_cache_key
    flush_message

This will prepare us for a more significant refactoring that
eventually breaks down some circular dependencies with
Message and bugdown.
2016-10-04 11:31:20 -07:00
Tim Abbott
279f805448 run-dev: Automate passing --interface='' for vagrant environment.
Fixes #877.
2016-10-04 10:48:26 -07:00
Steve Howell
69fa60080c tests: Test get_prereg_user_by_email(). 2016-10-04 10:35:43 -07:00
Steve Howell
ad149141f3 tests: Test Subscription.__unicode__(). 2016-10-04 10:35:43 -07:00
Steve Howell
5ae8cff289 code cleanup: Remove unused Attachment methods.
This removes some unused code on Attachment.  Some of these
methods might be useful in a manage.py shell, but without tests,
they are not very trustworthy, and the Attachment model isn't that
complicated to write raw Django queries against.
2016-10-04 10:35:43 -07:00
Steve Howell
732bf5e6d0 tests: Test Attachment.__unicode__(). 2016-10-04 10:35:43 -07:00
Steve Howell
cfc4010667 Add test code for UserMesssage.__unicode__(). 2016-10-04 10:35:43 -07:00
Steve Howell
fc2329ccb7 tests: Add test_is_status_message(). 2016-10-04 10:35:43 -07:00
Umair Khan
06b8c76bda casper: Use local_id check to ensure messages are actually sent.
Previously, we only used this approach of waiting until the local echo
ID was cleared in the message edit tests.
2016-10-03 09:27:22 -07:00
Umair Khan
4fa9a786fc casper: Wait for logouts to complete. 2016-10-03 09:27:02 -07:00
Tim Abbott
ac2007dd9b resize_avatar: Add a size option. 2016-10-02 21:29:04 -07:00
Tim Abbott
87b9017845 upload: Extract get_avatar_url and add to UploadBackend. 2016-10-02 21:20:43 -07:00
Tim Abbott
22fd7ba02a avatar: Move avatar hash computations to their own file. 2016-10-02 21:19:10 -07:00
baali
142dce2cd4 Replace legacy endpoint for renaming a stream and add tests.
This moves the logic for renaming a stream to the REST API
update_stream_backend method, eliminating the legacy API endpoint for
doing so.

It also adds a nice test suite covering international stream names.
2016-10-02 20:33:49 -07:00
Rishi Gupta
48bec80c61 Fix test_signup.LoginTest.test_register.
The test currently expects 67 database queries during registration, but we
added two more (likely calls to resolve_subdomain_to_realm) in ea39fb2.
2016-10-02 19:16:24 -07:00
Tomasz Kolek
464ced2b48 Add Pipeline Hook event handling to gitlab integration. 2016-10-02 09:35:07 -07:00
Tomasz Kolek
36745a68cf Add Build Hook event handling to gitlab integration. 2016-10-02 09:35:07 -07:00
Brock Whittaker
a550399f7d lightbox: Change aesthetic to white-on-blue design.
No longer is there a white information bar at the bottom. Now it is all
aligned to the top.
2016-09-30 16:44:40 -07:00
Brock Whittaker
339249602f Remove Blur on lightbox background.
This removes the blur feature as the background of the info settings
container is now #FFF.
2016-09-30 16:42:26 -07:00
Brock Whittaker
6b3aded32d Aesthetic Changes for Overlay.
This includes reduced title font size to bring the total info bar
height to the same height as the buttons, and an image preview that
doesn’t hit the walls of the container.
2016-09-30 16:42:26 -07:00
Umair Khan
b6ad24b11b Fix names of sprite emojis. 2016-09-30 10:42:52 -07:00
Umair Khan
b4214ec8cb Fix formatting of print in run function. 2016-09-30 10:42:52 -07:00
Umair Khan
81174fa580 Change message contents to differentiate messages.
I have a hunch that the messages sent from different files
are interfering with each other as well. This commit will make
it clear if indeed this is the case.
2016-09-30 17:34:02 +05:00
Umair Khan
de905457ac Remove race condition while sending messages in casper.
Fixes: #1455
2016-09-30 16:49:29 +05:00
Umair Khan
406191cbe8 Upload test event log. 2016-09-30 16:49:26 +05:00
Brock Whittaker
70af5b49e0 On stream click, blur so key events unbind from sidebar.
Unblur the link that was clicked so that when a user presses up/down
buttons it will automatically go back over to the individual messages
rather than tabbing up and down the sidebar.

Fixes: #1875.
2016-09-29 16:01:29 -07:00
Brock Whittaker
64238f9426 hotkeys: Fix additional downloads of images.
This fixed additional downloads of a downloaded image by following the
keypress pattern of “Download” -> Esc -> Enter -> Enter -> … where
each enter downloads the image again.

It is necessary to blur the focus on the link when closing the overlay
to prevent this.
2016-09-29 14:08:10 -07:00
Brock Whittaker
f097581497 hotkeys: Fix escape key unnarrow/close lightbox interaction.
There is an issue where the unnarrow on escape was firing before the
overlay would escape. This shouldn’t happen because then when you try
to close out the overlay you also lose your spot on the page.

By changing the order, all is restored with the world.
2016-09-29 14:08:10 -07:00
Tim Abbott
c819a66e09 postgres-init-db: Use default bash to call flush-memcached. 2016-09-28 20:46:34 -07:00
Tim Abbott
66c63abfb9 hotkey: Prevent escape in lightbox from also unnarrowing. 2016-09-28 20:05:51 -07:00
Tim Abbott
5ed37beb02 test-backend: Simplify argument rewriting logic. 2016-09-28 11:52:05 -07:00
sonali0901
4869e1b0b2 test-backend: Add convenience arguments to run subsets of the tests.
This optimizes the process of running individual or small groups of
backend tests (./tools/test-backend
zerver.tests.test_bugdown.FencedBlockPreprocessorTest.test_simple_quoting)
to allow the following syntaxes:

    ./tools/test-backend zerver/tests/test_bugdown.py
    ./tools/test-backend zerver.tests.test_bugdown.py
    ./tools/test-backend zerver/tests/test_bugdown
    ./tools/test-backend zerver.tests.test_bugdown
    ./tools/test-backend test_bugdown.py
    ./tools/test-backend test_bugdown
    ./tools/test-backend FencedBlockPreprocessorTest
    ./tools/test-backend FencedBlockPreprocessorTest.test_simple_quoting

Fixes #1670.
2016-09-28 11:52:05 -07:00
Tim Abbott
cd5b38f5d8 provision: Fix node_modules being owned by root.
A bug in the node_cache.py code resulted in the node_modules symlink
in Zulip development environments being incorrectly owned by root.
This causes that bug to be fixed the next time a user provisions.
2016-09-28 00:36:48 -07:00
Tim Abbott
9c0c6c0c23 node_cache: Don't make node_modules symlinks as root. 2016-09-28 00:36:40 -07:00
Tim Abbott
cfaba35b9a hotkey: Fix tab_up_down detection of arrow keys.
The new code in 65ab368ff0 incorrectly
used the closest list as a bool, and thus broken using the normal
arrow key hotkeys.
2016-09-28 00:25:32 -07:00
Tim Abbott
c7b7893254 auth: Give nicer subdomain errors when using ZulipDummyBackend.
This improves Google and JWT auth as well as the registration
codepath to log something if the wrong subdomain is encountered.

Ideally, we'd have tests for these, and code to make the Google and JWT
auth cases show a clear error message.
2016-09-27 23:25:07 -07:00
Tim Abbott
b5b00e3a36 subdomains: Enforce subdomain checks on every API endpoint.
This ensures that everything is using the correct subdomain for
requests.  While it probably wouldn't be a real security problem for
the wrong subdomain to work, this enforcement is essential to catching
bugs in the product and users' API scripts.
2016-09-27 23:25:07 -07:00
Tim Abbott
a4e5450ace subdomains: Add support for aliases of the root subdomain.
We default to counting "www" as such an alias.
2016-09-27 23:25:07 -07:00
hackerkid
ea39fb2556 Add option for hosting each realm on its own subdomain.
This adds support for running a Zulip production server with each
realm on its own unique subdomain, e.g. https://realm_name.example.com.

This patch includes a ton of important features:
* Configuring the Zulip sesion middleware to issue cookier correctly
  for the subdomains case.
* Throwing an error if the user tries to visit an invalid subdomain.
* Runs a portion of the Casper tests with REALMS_HAVE_SUBDOMAINS
  enabled to test the subdomain signup process.
* Updating our integrations documentation to refer to the current subdomain.
* Enforces that users can only login to the subdomain of their realm
  (but does not restrict the API; that will be tightened in a future commit).

Note that toggling settings.REALMS_HAVE_SUBDOMAINS on a live server is
not supported without manual intervention (the main problem will be
adding "subdomain" values for all the existing realms).

[substantially modified by tabbott as part of merging]
2016-09-27 23:24:14 -07:00
Tim Abbott
15f6cc7c84 validate_api_key: Accept the request as an argument.
This is a prerequisite for checking the subdomain of the request.
2016-09-27 21:18:29 -07:00
Tim Abbott
bbab3cdc30 test_helpers: Add HostRequestMock helper class. 2016-09-27 21:18:29 -07:00
Tim Abbott
97a2e53992 post-receive: Revert buggy Python 3 import changes.
This reverts commit 0af154a301.
2016-09-27 21:18:29 -07:00
Tim Abbott
8442e9249c Reflow annotation for generic_bulk_cached_fetch.
This is a test of mypy's new support for annotating functions that
take lots of arguments.
2016-09-27 20:36:56 -07:00
Tim Abbott
a17a6a21c0 Upgrade Django to 1.8.15 with Zulip patches. 2016-09-27 20:29:08 -07:00
Tim Abbott
4aceb1cd6f search_operators: Document has: operators.
These useful operators for finding messages with
images/links/etc. have been available for a long time, but weren't
documented.
2016-09-27 20:27:54 -07:00
Tim Abbott
d25bbdf574 lint: Fix missing cast causing mypy errors. 2016-09-27 18:38:32 -07:00
Tim Abbott
aaa221233a lint: Ban 2-space indentation in our CSS.
Probably most properly we should check for any number of spaces that
isn't 4, but that's a bit more work to do with our linter framework,
and in practice basically every CSS whitespace error we see is 2-space.
2016-09-27 18:06:44 -07:00
Tim Abbott
855c306c01 Document components.css a little. 2016-09-27 17:56:14 -07:00
Brock Whittaker
87afe61860 Add overlay lightbox for displaying inline image previews.
This adds an event listener (by way of delegation) to the
.message_inline_image elements that pops up the overlay and hides it
when the overlay exit is clicked.

Fixes #654.
2016-09-27 17:50:51 -07:00
Tim Abbott
2ea7d2341e css: Move new-style buttons to new components.css and expand. 2016-09-27 17:48:24 -07:00
Tim Abbott
dd3553cc5b zulip.css: Fix some 2-space indentation errors. 2016-09-27 17:43:28 -07:00
Brock Whittaker
98937ac539 bugdown: Set "title" attribute to actual image title when available.
This sets the “title” attribute on the image to the actual title of
the image specified by the user in their markdown, rather than just
the URL of the full link to it.
2016-09-27 17:34:05 -07:00
Brock Whittaker
65ab368ff0 Add arrow tab sections to home page.
This lets you use up and down arrows in certain sections on the site to
navigate lists. It also prevents potentially unwanted actions caused by
using up/down arrows in those sections.

Fixes: #1696.
2016-09-27 16:57:31 -07:00
Tim Abbott
63f92adfbb RateLimitTests: Remove now-unnecessary API key logic. 2016-09-27 14:54:10 -07:00
Tim Abbott
03bf8893e2 Remove legacy /api/v1/send_message endpoint.
This was the original way to send messages via the Zulip API in the
very early days of Zulip, but was replaced by the REST API back in
2013.

Fixes: #730.
2016-09-27 14:51:54 -07:00
Steve Howell
edfa022bac Remove json/get_active_statuses endpoint. 2016-09-27 14:33:56 -07:00
Umair Khan
99dbd33488 Upload casper failure images to S3 in Travis.
You need to define the following settings in Travis:
- ARTIFACTS_KEY
- ARTIFACTS_SECRET
- ARTIFACTS_BUCKET
- ARTIFACTS_REGION (if it's other than standard)

Since we are uploading everything to S3 under `var/casper` this commit
will also upload the server.log to S3.

Fixes: #1263, Fixes: #1477
2016-09-27 09:30:18 -07:00
Umair Khan
0f01aeaec9 Create failure images for casper in var/casper. 2016-09-27 09:30:18 -07:00
Umair Khan
76c8830f4a Test unicode file name. 2016-09-26 21:13:34 -07:00
Umair Khan
fd9dd51d16 Url encoded name of the file should be an ascii.
The url encoded name of the file should not be a unicode. This
results in an error when we later try to unquote it.

Fixes: #1803
2016-09-26 21:13:34 -07:00
Sahil Dua
058587da77 Remove extra new lines at the ends of Zulip authoried files.
Fixes #1627.

[tweaked by tabbott to avoid patching third-party modules, for now]
2016-09-26 21:05:24 -07:00
hackerkid
9a2e24a458 Use spinner as message preview loader. 2016-09-26 21:00:28 -07:00
Brock Whittaker
c833265fae Add notification for muting with unmute option.
This adds a support a notification at the top of the screen that
alerts a user they’ve muted a stream and gives them the option to
unmute if it was an accident.

The notification disappears automatically after 4s, but if a user
moves their mouse over the notification, the timer resets to 2s after
the user moves their mouse off the notification, to make it easy for
users to read the full message and decide what to do.
2016-09-26 20:55:53 -07:00
Brock Whittaker
3a4fff837f Identify if an emoji URL is invalid and signal an error.
Previously, no error would display in the UI if the link to the emoji
image was invalid. This would happen for instance if you put in
“invalid” for the Emoji URL. No alerts would pop up but it would refuse
to add the emoji.

This catches the error and displays a notification that looks like
“Failed: Enter a valid URL.”

Fixes #1116.
2016-09-26 20:52:45 -07:00
Tim Abbott
49faad7bb1 GitLab: Fix minor bytes/text types issue. 2016-09-25 23:29:36 -07:00
Tim Abbott
a3eb0be52a GitLab: simplify topics in GitLab integration. 2016-09-25 23:12:24 -07:00
hackerkid
dc355fcf1e Use backend markdown processor in message preview.
[tweaked by tabbott to add comment and fetch the authoritative
rendering from the backend unconditionally]

Fixes #1834.
2016-09-25 22:17:40 -07:00
Supriya
4959e8d10a tests: Extract and use assert_max_length test helper.
This makes it much more explicit in which cases we're checking
equality or a maximum in our use of `assert_length`.

Fixes #1400.
2016-09-25 15:44:58 -07:00
Steve Howell
1672353558 comments: Add comment to Realm.deployment().
I refer to github issue 1845 here.
2016-09-24 16:56:34 -07:00
Steve Howell
bc9a75ab24 Remove unreachable remove_unreachable() method.
Sorry, couldn't resist wording the commit message like that. :)

The remove_unreachable() method on Message was no longer being
used, and the commit history made it fairly clear we won't need it
in the future.
2016-09-24 16:56:34 -07:00
Steve Howell
98a500d46f tests: Add test_stream_message_unicode(). 2016-09-24 16:56:34 -07:00
Steve Howell
5486e539fd tests: Test Message.__unicode__() for PMs. 2016-09-24 16:56:34 -07:00
Steve Howell
a79a627166 tests: Add more cases to test_terms_of_service().
This gives us more test coverage on UserProfile.major_tos_version().
2016-09-24 16:56:34 -07:00
Steve Howell
dfa416cfc8 Remove last_reminder_tzaware().
We can now rely on UserProfile.last_reminder being time zone
aware, or even if it isn't, it's a self-correcting problem the
first time a reminder is sent.  (It's a non-problem to be off
by a few timezones if somebody still has an old value there, because
they will still be outside the 1-minute nag window even with the
timezone disparity.)
2016-09-24 16:56:34 -07:00
Steve Howell
0dddb9c877 tests: Add test_flush_realm_filter(). 2016-09-24 16:56:34 -07:00
Steve Howell
6673b28cde Extract domain_in_local_realm_filters_cache().
This is partly a concession to testing; it's really hard to test
that we are flushing the cache properly if tests need to look
at a global variable in models.py that can be re-assigned on every
request.  Extracting this function makes it easy for tests to know
whether a domain is in the local cache.
2016-09-24 16:56:34 -07:00
Steve Howell
d28c3d08a8 tests: Add test_maybe_update_realm_filters(). 2016-09-24 16:56:34 -07:00
Steve Howell
e0dc6092d5 tests: Call flush_per_request_caches() in test_realm_patterns().
This is a slightly more realistic test, and it adds some test
coverage.
2016-09-24 16:56:34 -07:00
Rishi Gupta
03ce3e5fa4 test_signup.py: Refactor getting confirmation_urls to test_helpers.py
It is a bit of tricky / scary looking code that was repeated several times
in test_signup.
2016-09-23 15:44:28 -07:00
Rishi Gupta
4b62ee8f38 initial invite page: Fix email validation when not restricted_to_domain.
We currently do
  var invite_suffix = "{{invite_suffix}}";
in javascript in the initial_invite_page.html template.
This sets invite_suffix to "{{invite_suffix}}" when the template is rendered
without invite_suffix in the params, rather than to "" as intended. This
later causes problems in the invite_email validator in initial_invite.js.
2016-09-23 15:44:28 -07:00
Steve Howell
a04a095738 Speed up alert word detection during message sends.
We no longer use all the alert words for all the users in the
entire realm when we look for alert words in a newly sent/edited
message.  Now we limit the search to only all the alert words
for all the users who will get UserMessage records.  This will
hopefully make a big difference for big realms where most messages
are only sent to a small subset of users.
2016-09-23 15:24:55 -07:00
Steve Howell
40b18094ec alert words: Refactor alert word detection.
The bugdown parser no longer has a concept of which users need which
alert words, since it can't really do anything actionable with that info
from a rendering standpoint.

Instead, our calling code passes in a set of search words to the parser.
The parser returns the list of words it finds in the message.
Then the model method builds up the list of user ids that should be
flagged as having alert words in the message.

This refactoring is a little more involved than I'd like, but there are
still some circular dependency issues with rendering code, so I need to
pass in the rather complicated realm_alert_words data structure all the way
from the action through the model to the renderer.

This change shouldn't change the overall behavior of the system, except
that it does remove some duplicate regex checks that were occurring when
multiple users may have had the same alert word.
2016-09-23 15:21:17 -07:00
Steve Howell
cb0d75b23b rendering: Consolidate code to render new messages.
We now use render_incoming_message() to render all incoming
new messages (sends/edits), so that they will get the same treatment.

This change also establishes do_send_messages() as the code
path to get new messages rendered.  It removes some
logic from check_message() that only happened on certain code paths
for sending messages, and which would only detect failures by
expensively rendering messages, so it wasn't much of a guard.

This change also helps to phase out maybe_render_content(), which
deepens the call stack without providing much clarity to the reader,
since it's behavior is so variable.

Finally, this sets up to fix a flaw in the way we compute which
users have alert words in their messages (in a subsequent commit).
2016-09-23 15:21:17 -07:00
umkay
798e6faa9e provision: Use NVM to install node and npm.
NVM takes a specific node version and installs the node package and
a corresponding compatible npm package.

We use it in a somewhat hackish way to install node/npm globally with
a pinned version, since that's how we actually want to consume node in
our development environment.

Other details:
- Travis CI now is configured to use the version of node installed by
provision; the easiest way to do this was to sabotage the existing node
installation.
- jsdom is upgraded to a current version, which both requires recent
node and also is required for the tests to pass with recent node.
This fixes running the node tests on Xenial.

Fixes #1498.

[tweaked by tabbott]
2016-09-23 14:34:44 -07:00
Tim Abbott
14dc5a73f5 travis: Remove duplicate sudo: required. 2016-09-23 13:48:43 -07:00
hackerkid
2d31fbce05 Translate markdown Preview and Write title. 2016-09-23 11:01:52 -07:00
Arpith Siromoney
c7639c3510 Add zulip-js (link, installation, usage) to api page. 2016-09-23 10:46:19 -07:00
Arpith Siromoney
ddaf44e533 Add link to zulip-js in README. 2016-09-23 10:46:17 -07:00
Tomasz Kolek
95825973c7 Add branch name to topic in Gitlab integration.
Fixes: #1831.
2016-09-23 10:04:01 -07:00
Tomasz Kolek
8cdc5b7a02 Fix bug with wrong branch name in Gitlab integration.
Need to change lstrip to replace particular string with empty string.

Fixes: #1830.
2016-09-23 10:03:09 -07:00
Tomasz Kolek
d4da60fbe2 Split test_hooks file into one test file per hook. 2016-09-23 10:02:16 -07:00
Tomasz Kolek
9197c82d8f Move WebhookTestCase class from test_hooks.py to test_helpers.py. 2016-09-23 10:02:16 -07:00
Steve Howell
28bb9c883a css linter: Report empty declarations more clearly.
Raise a CssParserException when declarations are empty.
2016-09-23 09:13:43 -07:00
Steve Howell
f0eaee68e4 bug: Fix traceback in get_missed_message_token_from_address().
If you supplied an unrecognizable address to our email system,
or you had EMAIL_GATEWAY_PATTERN configured wrong,
the get_missed_message_token_from_address() used to crash
hard and cryptically with a traceback saying that you can't
call startswith() on a None object.

Now we throw a ZulipEmailForwardError exception.  This will
still lead to a traceback, but it should be easier to diagnose
the problem.
2016-09-22 13:41:26 -07:00
Steve Howell
dbbc64dbfe bug: Fix code that mis-identifies missed message formats.
In our email mirror, we have a special format for missed
message emails that uses a 32-bit randomly generated token
that we put into redis that is then prefixed with "mm" for
a total of 34 characters.

We had a bug where we would mis-classify emails like
mmcfoo@example.com as being these system-generated emails
that were part of the redis setup.

It's actually a little unclear how the bug in the library
function would have manifested from the user's point of view,
but it was definitely buggy code, and it's possibly related in
a subtle way to an error report we got from a customer where
only one of their users, who happened to have a name like
mmcfoo, was having problems with the mirror.
2016-09-22 13:41:26 -07:00
Steve Howell
0b7cac04d4 email mirror: Extract is_mm_32_format(). 2016-09-22 13:41:26 -07:00
hackerkid
0412e1e20b Add support for markdown preview in compose area.
This doesn't currently use the backend markdown processor, so the
previews are not completely faithful.

Fixes #217.
2016-09-21 22:33:35 -07:00
Umair Khan
94e0bb5abb Fix race conditions in 03-narrow casper tests.
Re-arranges code so that two waitFor functions that can have
a race condition are separated by a then function.

Fixes: #1455
2016-09-21 17:54:42 +05:00
Tim Abbott
535a40ded9 requirements: Add enum34 for ipython on python 2.
I guess we don't have anything that tests ipython in CI, so this was
missed when I upgraded ipython earlier this week.
2016-09-20 22:37:47 -07:00
Steve Howell
13d6f52203 provision: Handle VENV_CACHE_PATH not existing.
If VENV_CACHE_PATH does not exist (which can happen if you destroy
your vagrant environment), then do a short circuit return in
try_to_copy_venv().
2016-09-20 06:55:08 -07:00
Tim Abbott
59f3fd55c9 requirements: Upgrade moto and dependencies. 2016-09-19 22:55:05 -07:00
Umair Khan
e3078b226a Optimize incremental virtualenv creation.
This adds a new system for copying packages from old virtualenvs that
are sufficiently similar to the new virtualenv required.

In practice, this results in a huge performance improvement for
re-provisioning Zulip development environments when the requirements
files have changed (which is the dominant performance problem with
provision today).

Fixes: #1507.
2016-09-19 22:35:32 -07:00
Tim Abbott
27e4ed126f requirements: Upgrade various Python dependencies. 2016-09-19 22:32:02 -07:00
Tim Abbott
0cab02b58a Upgrade mypy to latest upstream git.
This new mypy version supports some performance improvements and
should also facilitate running mypy on our scripts more efficiently.
2016-09-19 22:19:38 -07:00
Brock Whittaker
f87c78d3f1 Add preview button to subscriptions page.
This adds a preview button to the subscriptions page to allow a user
to check out the stream without having to subscribe.

The button’s default state is hidden but on subscription row hover it
shows itself.

The preview button updates its text from "Narrow" to "Preview" and
back when a user subscribes and unsubscribes from a stream.

Fixes: #1519.
2016-09-19 22:13:47 -07:00
Tim Abbott
47045179fc Fix traceback rendering narrows to non-subscribed streams.
This fixes a bug where Zulip would throw a TypeError if the user were
to try to narrow to a stream they had never been subscribed to.  With
the new "preview" feature on the subscriptions page, this will now
happen much more often.
2016-09-19 22:10:52 -07:00
Brock Whittaker
706f422c3a Massively refactor settings page templates and styling.
This restructures the styling for the Zulip settings and
administration pages to minimize use of Bootstrap and use a consistent
styling library for similar elements.

While it is basically a wash in terms of the page's visuals, it will
make our life a lot easier for future work on improving the settings
pages section of the site.
2016-09-19 21:55:06 -07:00
Tim Abbott
68c51912c9 extract_recipients: Add a type: ignore for problematic arguments.
We'll want to redo this function to be less crazy, but this is a quick
fix to be able to upgrade mypy.
2016-09-19 21:48:12 -07:00
Tim Abbott
e488d4d6e8 log_event: Fix unicode handling of log writing. 2016-09-19 21:45:52 -07:00
Tim Abbott
939528303d upload: Add type: ignore for mimetypes.guess_type stubs issue. 2016-09-19 21:40:08 -07:00
Steve Howell
6b3f945a7e dead code: Remove linebreak(). 2016-09-19 18:25:03 -07:00
Steve Howell
c2277afd06 Simplify bulk_get_streams().
We can always expect a realm here.
2016-09-19 18:25:03 -07:00
Steve Howell
eb09dd217d Simplify get_stream_backend.
Assume that get_stream_backend() always receives a realm, not a
realm id.  We can be pretty confident of that now due to mypy.
2016-09-19 18:25:03 -07:00
Steve Howell
1dbc94bcd9 annotations: Require a Realm for get_stream(). 2016-09-19 18:25:02 -07:00
Steve Howell
feb94a90aa tests: Add ModelTest class for miscellaneous model tests. 2016-09-19 18:25:02 -07:00
Steve Howell
7d257b03fc test: Add coverage for Recipient.__unicode__(). 2016-09-19 18:25:02 -07:00
Steve Howell
e0d59d9386 dead code: Remove Stream.create(). 2016-09-19 18:25:02 -07:00
Steve Howell
a67d17b9f7 tests: Add coverage for RealmFilter.__unicode__(). 2016-09-19 14:57:53 -07:00
Steve Howell
5daa2b10d5 tests: Add coverage for RealmEmoji.__unicode__(). 2016-09-19 14:57:53 -07:00
Steve Howell
068a783d88 tests: Test creating user with aliased realm. 2016-09-19 14:57:53 -07:00
Steve Howell
2d0d823a59 tests: Add test_fetch_raw_message(). 2016-09-19 14:25:21 -07:00
Steve Howell
7d4995ded0 tests: Add test_render_message_api(). 2016-09-19 14:25:21 -07:00
Steve Howell
d0f9374b71 tests: Add test_messages_in_narrow(). 2016-09-19 14:25:21 -07:00
Steve Howell
318f8e86a1 tests: Extract _update_tsvector_index(). 2016-09-19 14:25:21 -07:00
Tim Abbott
9ed5ccd332 alert_words: Use the ID to reference create_alert_word_button. 2016-09-19 14:23:11 -07:00
Brock Whittaker
0274475e5e Fixes hash system for saving page state.
This changes the JavaScript to fix the hash system to correctly save
state to allow a user to deep link to a particular app platform.

The mechanism is handled by a click event on #apps-tabs [data-toggle]
that fires a hash setter which then fires a hash getter which loads the
correct tab if necessary.
2016-09-19 13:19:01 -07:00
sunnypalace
3b76a489c9 Remove humbug-user-uploads and related code.
Fixes: #1672.
2016-09-19 10:52:05 -07:00
Steve Howell
e2f7f7b672 tests: Add test_update_alert_words(). 2016-09-18 22:08:53 -07:00
Steve Howell
a58cad3093 tests: Extract test_alert_words.py 2016-09-18 22:08:53 -07:00
Tim Abbott
ec850e3053 Revert "tests: Skip test_get_old_messages_with_search_pgroonga."
This reverts commit 8ae7e7b451.

We believe this issue may have been fixed in
e80279c2e4.
2016-09-18 20:26:35 -07:00
Kouhei Sutou
e80279c2e4 test: Add a missing PGroonga configuration
Fix #1769
2016-09-19 01:06:52 +09:00
Tim Abbott
8ae7e7b451 tests: Skip test_get_old_messages_with_search_pgroonga.
This test fails nondeterministically, apparently due to a problem in
pgroonga itself.
2016-09-17 12:29:24 -07:00
Steve Howell
1c37c0e93f uploads: Remove redir=False codepath for serving S3 files.
It does not seem that we need to support this any more.  Eliminating
the code gets us to 100% line coverage with our tests on view/uploads.py.
2016-09-17 12:13:07 -07:00
Steve Howell
9c0282139a tests: Add test_serve_s3_error_handling(). 2016-09-17 12:13:07 -07:00
Steve Howell
934385a238 tests: Add test_download_non_existent_file(). 2016-09-17 12:13:07 -07:00
Steve Howell
5c54b53fc0 tests: Add test_file_too_big_failure(). 2016-09-17 12:13:07 -07:00
Steve Howell
a630bbf8b8 uploads: Remove dead code in serve_local(). 2016-09-17 12:13:07 -07:00
Steve Howell
ca18b631c5 tests: Add ZephyrTest. 2016-09-17 09:29:09 -07:00
Eklavya Sharma
2d3921e3e4 Add instructions for manually installing pgroonga. 2016-09-17 09:23:54 -07:00
Steve Howell
750720116f tests: Add test_update_realm_api(). 2016-09-17 08:31:23 -07:00
Umair Khan
ff0f413d26 Use npm caching in upgrade-zulip-stage-2. 2016-09-16 12:40:48 -07:00
Umair Khan
4301d11b4a Use npm caching in tools/update-prod-static. 2016-09-16 12:40:48 -07:00
Umair Khan
a82990f63c Use npm caching in tools/provision.py. 2016-09-16 12:40:48 -07:00
Umair Khan
ec74974de3 Create node_cache module for npm caching. 2016-09-16 12:40:48 -07:00
Tim Abbott
2c19719cee test_bugdown: Fix i18n test flakiness with markdown rendering tests.
It appears that the assertRaisesRegexp approach we had before didn't
work properly on some systems, likely due to a bad interact with a
i18n (we haven't definitively determined the cause).
2016-09-16 11:49:52 -07:00
Steve Howell
a036a72db6 bugdown: Raise BugdownRenderingException.
We now raise an exception in bugdown.do_convert() if rendering
fails, to avoid silent failures, and then calling code can convert
the exception to a JsonableError.
2016-09-16 10:01:55 -07:00
Steve Howell
de25f07961 tests: Add BugdownErrorTests. 2016-09-16 10:01:55 -07:00
Steve Howell
152cebf33d bugdown: Extract log_bugdown_error().
(It makes it easier to mock out the logging.)
2016-09-16 10:01:54 -07:00
Steve Howell
c4dd3ba0d3 tests: Add test_illegal_name_changes(). 2016-09-16 09:59:26 -07:00
Steve Howell
ac0a11f098 tests: Add test_report.py.
This is close to 100% coverage, but the js_source_map stuff will be
tricky, and we may just want to eliminate that soon.
2016-09-16 07:01:40 -07:00
Steve Howell
6ecee2ac4f streams: Simplify list_to_streams().
The list_to_streams() method now uses create_streams_if_needed() to
do its heavy lifting during the autocreate=True case.

This commit gets us to 100% coverage on the streams view.  (The
recently created action.create_streams_if_needed() was easy
to test in isolation, and it has 100% coverage as well, so we are
not cheating here.)

Fixes: #1005.
2016-09-15 10:18:10 -07:00
Steve Howell
8776cc0e35 Add create_streams_if_needed(). 2016-09-15 10:18:10 -07:00
Steve Howell
e8119b175d tests: Add test_tutorial.py. 2016-09-15 10:15:18 -07:00
Steve Howell
a9e2ceb4e9 push notifications: Fix very minor quirk when adding tokens.
When we push a device token, we want to clean out any other user's
tokens on the device, but not the current user's.  We were wiping
away our own token, if it existed, before creating it again.  This
was probably never a user-facing problem; it just made for dead code
and a little unnecessary DB churn.  By excluding the current user
from the delete() call, we exercise the update path in our tests now,
so we have 100% coverage.
2016-09-15 06:40:18 -07:00
Steve Howell
f9cdc63250 tests: Add test_push_api().
We now have 100% coverage on views/push_notifications.py, modulo
some dead code which will be addressed in the next commit.

There were some existing tests in text_external.py, but that
module is really intended for tests that hit external services.

The view is a really simple API that updates a DB table, and the
new test code focuses on error handling and idempotency as well
as the happy path.
2016-09-15 06:39:41 -07:00
Tim Abbott
5fcc8146c1 emoji_dump: Clean up spammy sprite creation output.
Glue apparently prints 1 line per file being processed.
2016-09-14 11:49:55 -07:00
sonali0901
15331ad9fa docs: Document invite-only streams are hidden from other users.
Fixes: #1756.
2016-09-14 10:06:10 -07:00
Tim Abbott
0f4bbc8617 portico: Add options to disable login and about links.
This gives us a great deal more flexibility for controlling the
context of the portico footer.
2016-09-13 22:59:09 -07:00
Rishi Gupta
de11e7c1b3 Add support for subdomain URIs to /api and /api/endpoints.
To the extent possible, we share code with the already-existing
IntegrationView code path.
2016-09-13 22:31:56 -07:00
Tim Abbott
bc827b2a6f integrations: Add test for integrations context. 2016-09-13 22:31:55 -07:00
Tim Abbott
f9e41b1387 integrations: Factor out ApiURLView base class. 2016-09-13 22:26:47 -07:00
Tim Abbott
b7ab83c6ec Move api_endpoint_docs to integrations views file. 2016-09-13 21:58:02 -07:00
Tomasz Kolek
acbfe7e624 Add Librato integration.
Fixes: #68.
2016-09-13 21:55:25 -07:00
umkay
6d4f86f951 Add explanation for test_mit_rendering. 2016-09-13 21:23:57 -07:00
umkay
7eb6924841 Wrap dict view object in list for python3 compatibility.
Deleting items from a dictionary being iterated through directly
doesn't work properly in Python 3.
2016-09-13 21:21:45 -07:00
Tim Abbott
6c617910c3 Add an app-internal about page for the project.
We will want to link to this from at least the portico.
2016-09-13 21:10:07 -07:00
umkay
cd1908d04d Add test for password reset flow. 2016-09-13 18:16:50 -07:00
Tim Abbott
e93a2e990f Fix nondeterministic parsing failures in GoogleLoginTest.
Apparently, in urllib.parse, one need to extract the query string from
the rest of the URL before parsing the query string, otherwise the
very first query parameter will have rest of the URL in its name.

This results in a nondeterministic failure that happens 1/N of the
time, where N is the number of fields marshalled from a dictionary
into the query string.
2016-09-13 18:13:28 -07:00
Tim Abbott
ca91605e85 Extract zerver/views/pointer.py. 2016-09-13 17:30:39 -07:00
Tim Abbott
29495b953a Add test for GET /json/users/me/pointer. 2016-09-13 17:30:39 -07:00
Tim Abbott
6d8af06e32 Fix Google oauth2 logging to use %s for strings.
This has more consistent results in Python 2 vs. Python 3.
2016-09-13 17:30:39 -07:00
Tim Abbott
95a348382b Fix nondeterministic failures in GoogleLoginTest. 2016-09-13 17:26:38 -07:00
Tim Abbott
8fe7488074 views: Remove extract_json_response hack for python-requests.
Now that we are using a virtualenv for dependencies, we can be
confident we will never be using an old system-installed version of
this library.
2016-09-13 17:08:14 -07:00
Tim Abbott
b8bdf1365b tests: Add a Google web authentication test suite. 2016-09-13 17:08:14 -07:00
Tim Abbott
97dbf1a8f9 Refactor Google auth error handling to be more testable. 2016-09-13 17:08:14 -07:00
Tim Abbott
9bfe879170 google auth: Fix py3 encoding issues for CSRF computations. 2016-09-13 17:08:14 -07:00
Tim Abbott
4a2282a837 tests.py: Fix missing import needed for mypy. 2016-09-13 17:08:14 -07:00
Steve Howell
51c78571cc tests: Add HomeTest.test_invites_by_admins_only(). 2016-09-13 16:46:05 -07:00
Steve Howell
7cb8f6421d tests: Add HomeTest.test_new_stream(). 2016-09-13 16:46:05 -07:00
Steve Howell
eced842f4d tests: Add HomeTest.test_notifications_stream(). 2016-09-13 16:46:05 -07:00
Steve Howell
cad12b077f tests: Extract HomeTest._get_page_params(). 2016-09-13 16:46:05 -07:00
Steve Howell
1091b51bb4 tests: Add HomeTest.test_bad_pointer(). 2016-09-13 16:46:05 -07:00
Steve Howell
7f771c64ae tests: Add HomeTest.test_bad_narrow(). 2016-09-13 16:46:05 -07:00
Steve Howell
2bf876d5bb tests: Add HomeTest._sanity_check(). 2016-09-13 16:46:05 -07:00
Steve Howell
dc2dde1509 tests: Add HomeTest.test_terms_of_service(). 2016-09-13 16:46:05 -07:00
Steve Howell
fa4110b1d9 tests: Extract HomeTest._get_home_page(). 2016-09-13 16:46:05 -07:00
Steve Howell
f5f7801302 tests: Extract test_presence.py 2016-09-13 14:51:36 -07:00
Steve Howell
2b4d59d6e8 Fix comment in update_active_status_backend(). 2016-09-13 14:45:27 -07:00
Steve Howell
329fa22f22 tests: Add test_mirror_presence(). 2016-09-13 14:42:18 -07:00
Steve Howell
7f94c74bf8 tests: Add test_invalid_presence(). 2016-09-13 14:36:47 -07:00
Steve Howell
edf7ea7f51 tests: Add make_client() test helper. 2016-09-13 14:32:59 -07:00
Tim Abbott
65321b77ac socket: Switch localhost to 127.0.0.1.
It does the same thing, but is a bit more robust to weird DNS
configurations.
2016-09-13 10:01:57 -07:00
Tim Abbott
9f41fc0882 zulip.js: Remove unused javascript variables. 2016-09-12 22:40:11 -07:00
Steve Howell
4c5eb3d06e Fix transaction behavior for update_subscriptions_backend().
This commit extracts compose_views() from update_subscriptions_backend(),
and it implements the correct behavior for forcing transactions to roll
back, which is to raise an exception.

There were really three steps in this commit:

- Extract buggy code to compose_views().
- Add tests on compose_views().
- Fix bugs exposed by the new tests by converting errors to exceptions.
2016-09-12 22:03:39 -07:00
umkay
82d03d603a Update Pygments to latest upstream version.
In HTML, the line break immediately following a start tag is ignored
(see: https://www.w3.org/TR/html4/appendix/notes.html#h-B.3.1). An
extra span tag has been introduced in the upstream Pygments
HtmlFormatter in order to preserve the first new line. The Bugdown
Tests as well as our fenced_code.js frontend markdown processor have
been updated to reflect this new behavior.
2016-09-12 21:58:25 -07:00
Tim Abbott
9bccd10582 check-mirroring: Fix unnecessary type: ignore. 2016-09-12 21:43:45 -07:00
Tim Abbott
cd0025f67f docs: Update roadmap with recently completed projects. 2016-09-12 14:56:08 -07:00
Tim Abbott
5c88fbdc6f mypy: Require new Python functions to have type annotations.
We're now at the point where 100% of functions checked by mypy is
fully annotated; to avoid regressions, we're enforcing the requirement
that it stay this way.  We still have a moderate amount of code that
is neither checked by mypy nor annotated, but it seems reasonable to
annotate that code at the same time as we get a chance to fix the mypy
issues in it.

This is implemented by using the --disallow-untyped-defs option in
mypy by default.
2016-09-12 14:56:08 -07:00
Gordon P. Hemsley
0f4148920a Switch tools/webpack from optparse to argparse. 2016-09-12 12:00:16 -07:00
Gordon P. Hemsley
aace1c5bc9 Switch tools/update-prod-static from optparse to argparse. 2016-09-12 12:00:16 -07:00
Gordon P. Hemsley
9755f3f302 Switch tools/test-tools from optparse to argparse. 2016-09-12 12:00:16 -07:00
Gordon P. Hemsley
9b47f4ab3a Switch tools/minify-js from optparse to argparse. 2016-09-12 12:00:16 -07:00
Gordon P. Hemsley
1e9a4b2bab Switch tools/check-templates from optparse to argparse. 2016-09-12 12:00:16 -07:00
Gordon P. Hemsley
fc6f72174b Switch tools/find-add-class from optparse to argparse. 2016-09-12 12:00:16 -07:00
Tim Abbott
9b867be075 mypy: Exclude api/zulip/__init__.py so we can start enforcing. 2016-09-12 09:03:50 -07:00
Tim Abbott
1eb16d03a2 Finish annotating template/css parsers and tests. 2016-09-12 09:03:50 -07:00
Tim Abbott
e580ed579b Finish annotating zerver/views/messages.py.
These annotations aren't perfect because the sqlalchemy stubs in
typeshed are broken (e.g. a `Select` doesn't have the ability to do
`.where()`, but we've at least used some typevars to make it easy to
address that when the sqlalchemy stubs are less broken).
2016-09-12 08:47:52 -07:00
Tim Abbott
e5b8ad6666 Fix teamcity.py annotations. 2016-09-12 08:30:42 -07:00
Tim Abbott
d964e5595a Finish annotating test_helpers.py. 2016-09-12 08:29:34 -07:00
Steve Howell
cdee3dfb53 Annotate test_helpers.instrument_url(). 2016-09-12 08:21:46 -07:00
Steve Howell
ffec98d85c Annotate zerver/lib/export.py.
This adds the remaining annotations to lib/export.py.
2016-09-12 08:21:46 -07:00
Steve Howell
62dd86bcce mypy: Set Path to str instead of text_type in export.py.
Using text_type for Path just breaks a lot of calls to
the core Python libraries that still want strings.
2016-09-12 08:21:46 -07:00
Steve Howell
b2ae2dc7cc Exclude contrib_bots from run-mypy. 2016-09-12 08:21:46 -07:00
Umair Khan
593779a3b0 Annotate zerver/tests/test_push_notifications.py. 2016-09-12 08:10:50 -07:00
Umair Khan
c231a440cd Annotate zerver/templatetags/minified_js.py. 2016-09-12 08:10:50 -07:00
Umair Khan
29c24d540f Annotate zerver/templatetags/app_filters.py. 2016-09-12 08:10:50 -07:00
Umair Khan
b4eb3a55be Annotate zerver/management/commands/realm_emoji.py. 2016-09-12 08:10:50 -07:00
Umair Khan
f8c904e611 Annotate zerver/management/commands/deliver_email.py. 2016-09-12 08:10:50 -07:00
Umair Khan
c096473e06 Annotate zerver/management/commands/check_redis.py. 2016-09-12 08:10:50 -07:00
Umair Khan
6c21d7a2c8 Annotate tools/setup/emoji_dump/emoji_dump.py. 2016-09-12 08:10:49 -07:00
Umair Khan
3f7f79f4b5 Annotate confirmation/models.py. 2016-09-12 08:10:48 -07:00
Umair Khan
e2f29054a4 Check type before sending confirmation email.
We can only send confirmation email with PreregistrationUser and
Confirmation objects.
2016-09-12 11:00:15 +05:00
Steve Howell
64cb5d0778 Annotate commands/export.py. 2016-09-11 17:15:35 -07:00
Steve Howell
52c6efa0a8 Annotate commands/export_single_user.py. 2016-09-11 17:15:35 -07:00
Steve Howell
bb6fcaa4e7 Annotate commands/export_usermessage_batch.py. 2016-09-11 17:15:35 -07:00
Steve Howell
85e30a6d35 Annotate commands/import.py. 2016-09-11 17:15:35 -07:00
Steve Howell
43572486b2 Annotate test_export.read_file(). 2016-09-11 17:15:35 -07:00
Steve Howell
30129f609b Annotate client_post() and client_get() in test_helpers. 2016-09-11 17:15:35 -07:00
Tomasz Kolek
8b9e9a386a Add mypy annotations to various integrations-related functions.
Added to:
zerver/lib/integrations.py
zerver/tests/test_integrations.py
zerver/tests/test_management_commands.py
zerver/views/integrations.py
zerver/views/webhooks/circleci.py
2016-09-11 17:11:25 -07:00
Umair Khan
d171e2c8d9 Remove race conditions in casper tests.
Chaining together `wait*` functions can create race conditions in the
frontend tests. To avoid race condition, we need to insert `then`
function between two `wait*` functions.
2016-09-11 17:10:15 -07:00
Tim Abbott
8fbbb3a471 Annotate send_password_reset_email.py. 2016-09-11 17:09:27 -07:00
Tim Abbott
06580ca76e Annotate confirmation/util.py. 2016-09-11 17:09:27 -07:00
Tim Abbott
54820de522 Annotate bots/summarize_stream.py. 2016-09-11 17:09:27 -07:00
Steve Howell
98ac51d07d Clean up imports in html_branches.py. 2016-09-11 15:30:10 -07:00
Steve Howell
071c957f14 tools: Simplify html_tag_tree().
Because of some recent changes to the tokenizer, we no longer
need to call is_special_html_tag() to filter out special tags.

I also tried to make the start/end logic for pushing/popping
the stack more obvious.
2016-09-11 13:36:55 -07:00
Gordon P. Hemsley
331617efab Factor out HtmlTreeBranch and related code from template parser.
This code is not directly related to the template parser, so it
can safely live in its own file.

The only significant change to the code is to the signature of
`html_branches` so that it can be called without requiring a file.
Since it's only used in html_grep, that has been updated to reflect
this change.

Fixes: #1774.
2016-09-11 14:57:17 -04:00
Gordon P. Hemsley
4d3350bd7b Improve branch test coverage for html_tag_tree() in template parser. 2016-09-11 09:59:13 -07:00
Gordon P. Hemsley
87b87621fe Reach 100% branch coverage for CSS parser. 2016-09-11 09:59:13 -07:00
Gordon P. Hemsley
911634d1d4 Analyze branch coverage in test-tools. 2016-09-11 09:59:13 -07:00
Tim Abbott
4f091fd844 Annotate irc-mirror.py. 2016-09-10 12:20:24 -07:00
Tim Abbott
4634aa638e Annotate zerver/lib/tornado_ioloop_logging.py. 2016-09-10 12:10:41 -07:00
Tim Abbott
799c78fbcf Annotate zerver/lib/sqlalchemy_utils.py. 2016-09-10 12:08:37 -07:00
Tim Abbott
2e6aad669c cache: Add a basic annotation for cache_with_key. 2016-09-10 11:57:08 -07:00
Tim Abbott
de3fe38e8a Annotate bots/zulip_git_config.py. 2016-09-10 11:57:08 -07:00
Tim Abbott
83ef7e72e6 models: Fix missing mypy annotations in subdomains code. 2016-09-10 11:57:07 -07:00
Tim Abbott
3a64074e8b test_signup: Annotate some recently added functions. 2016-09-10 11:57:07 -07:00
Tim Abbott
d32e691fe9 Annotate check-mirroring. 2016-09-10 11:57:01 -07:00
Tim Abbott
317e2a63b3 Remove tools/deprecated/review and associated files.
This hasn't been used since before Zulip was open source, and isn't
super reusable, so we can remove it.  It'll always be there in the
history if someone ends up wanting it.

While we're at it, we remove the GitPython dependency (only used for
this tool) and the example MSMTP config for the review tool.
2016-09-10 10:53:02 -07:00
Tim Abbott
e48cdb8d7e Fix python 3 compatibility in logging code.
Detected by mypy.
2016-09-09 15:36:29 -07:00
Rishi Gupta
bba2465f89 Change links to /api to be relative or with {{ realm_uri }}. 2016-09-08 17:05:34 -07:00
Tim Abbott
b41fc75767 notifications: Remove unused field from template context.
While one often might want to put the user's name in an email
template, `name` here was the user's full name, not their first name,
and thus reads as quite formal.
2016-09-08 17:03:00 -07:00
Tim Abbott
0d324d38b3 logging: Fix duplicate detection for email errors.
Our implementation of duplication detection in the Zulip email error
reporting system was buggy in two important ways:

* It did not look at the traceback, and thus considered all errors as
  the same.

* It reset the 10-minute duplicate timer every time an error happened,
  thus concealing situations where the same error was occuring more
  often than 1/10 minutes.
2016-09-08 16:55:36 -07:00
Tim Abbott
4423222d92 email_mirror: Add successful processing logging. 2016-09-08 16:54:10 -07:00
Tim Abbott
12ddb1a36f puppet: Fix buggy logrotate configuration. 2016-09-08 16:51:17 -07:00
Tim Abbott
a7fe22f4ec Add Zulip version number to page_params. 2016-09-08 15:29:24 -07:00
Tim Abbott
24906f7678 emoji_dump: Update SIZE to 136x136 to reflect new emoji set.
I'm not entirely sure that this is correct, but it suffices to make
the spritesheet emoji have the right size.
2016-09-08 15:18:04 -07:00
Tim Abbott
a4536cca1e emoji_dump: Generate a sprite sheet for the Zulip emoji. 2016-09-08 15:16:58 -07:00
Tim Abbott
abf85e7fbd emoji_dump: Add warning for fallback to black/white.
I don't think the black/white fallback code is actually used by
default, and thus when it is used, it's usually a sign that something
is broken.  We should throw an error, but at the very least it makes
sense to print a warning.
2016-09-08 15:05:38 -07:00
Tim Abbott
aca6636729 emoji_dump: Fix buggy path management.
In d583710f7c, I apparently broke the
color emoji handling, which was masked (for test purposes) by the fact
that we catch an expection if color doesn't work and in that case fall
back to black and white emoji.
2016-09-08 15:04:09 -07:00
Tim Abbott
a6fffe5120 emoji_dump: Move size constants to top of file. 2016-09-08 14:30:20 -07:00
Tim Abbott
d583710f7c emoji_dump: Refactor path code to be a bit cleaner. 2016-09-08 14:27:47 -07:00
Umair Khan
13159ab266 Provide versions through egg.
Giving version in the git urls will allow pip to compare the
installed version and skip the download if the installed
version is up to date.
2016-09-08 14:15:20 -07:00
Umair Khan
859b1fbb2c setup_venv.py: Remove comma from the end. 2016-09-08 14:14:28 -07:00
Tim Abbott
b744a3a4d7 docs: Update changelog since 1.4.0 release. 2016-09-07 19:51:14 -07:00
Tomasz Kolek
848635005f Add Sentry integration.
Fixes: #618.
2016-09-07 19:39:45 -07:00
Tim Abbott
3c34264559 run-dev: Automatically fixup missing handlebars binary. 2016-09-07 19:35:41 -07:00
Tim Abbott
c9f9fb265e Update provision.py and Vagrantfile to support VMWare.
This adds support for using VMWare Fusion as the Vagrant provider,
which has better performance than Virtualbox at the price of being
nonfree (in all senses of the term).

We haven't done solid benchmarking as to how much faster it is than
the Virtualbox provider.
2016-09-07 19:30:48 -07:00
Tim Abbott
c81b93249b Vagrantfile: Use 2 virtual CPUs with virtualbox.
This should improve performance of linting and other parallelizable
operations in the development environment on most laptops.
2016-09-07 19:25:18 -07:00
ashishk1994
329f52668d Add test_set_color_unsubscribed_stream_name.
Signed-off-by: ashishk1994 <ashishk.iiit@gmail.com>
2016-09-07 19:10:12 -07:00
Ashish Kumar
c9b81379b6 Add test_bot_add_subscriptions().
Signed-off-by: ashishk1994 <ashishk.iiit@gmail.com>
2016-09-07 19:10:12 -07:00
Steve Howell
ab0ee0b923 Upgrade: revert change to default LOCAL_UPLOADS_DIR in prod settings.
The main purpose of the "var" convention is to make it easy to write stuff
inside of our git repo when running a dev instance, and then "var" gets
excluded from checkins. For production, that's not as much of a concern.
For upgrades we don't want to be changing the directory around and confusing
matters, especially with the extra moving part of nginx configs (which have
their own issues in terms of being overwritten by accident when admins go to
S3).
2016-09-06 14:51:29 -07:00
Christie Koehler
586b236375 upgrade: Create prod_settings symlink in step 2 if it doesn't exist.
Between releases 1.3.13 and 1.4.0, local_settings.py was renamed to
prod_settings.py. The upgrade scripts were adjusted to reflect this name
change. But because the first part of the upgrade script is run with the
currently installed version's code, the symlink to /etc/zulip/settings.py is
created with the old name. This was causing upgrade-zulip-stage-2 to fail.

Now upgrade-zulip-stage-2 creates the symlink at zproject/prod_settings.py
if it doesn't already exist.

Fixes #1731.
2016-09-06 14:51:16 -07:00
Umair Khan
6a12ad7c33 Don't trust env while accessing Tornado.
This fixes a problem where the requests to Tornado would attempt to
use a configured outgoing HTTP proxy, when really we want to connect
directly to localhost.

Fixes: #468.
2016-09-06 14:17:50 -07:00
Umair Khan
a4466c93a3 Use connection pooling for Django -> Tornado reqs.
Fixes: #391.
2016-09-06 14:15:35 -07:00
Umair Khan
bc2069aec2 Suppress @-all mentions for muted streams.
Fixes: #1151
2016-08-31 19:34:53 -07:00
Gordon P. Hemsley
3ffc6b5a35 Clean up how missing end tags are handled in template parsing.
The null token was an artificial placeholder that wasn't making clear what
the problem was. Throwing an exception is bolder.
2016-08-30 19:24:17 -04:00
Gordon P. Hemsley
2e865f03bf Protect against nameless HTML tags in tools/lib/template_parser.py.
Fixed IndexError when there is only zero or more whitespace characters
between < and >. (str.split() will return an empty list in this case, which
means there is no index 0.)
2016-08-30 19:00:13 -04:00
Gordon P. Hemsley
c9d1a4247f Improve test coverage for tools.
* Replace generic Exception with TemplateParserException.
* Add tests to cover many of the uncovered lines in
  tools/lib/template_parser.py.
* Add an exclusion line to the naïve pattern for checking for missing
  tuples in format strings, to keep the linter happy.
2016-08-30 18:51:40 -04:00
Gordon P. Hemsley
7070e1ce7c Remove tools/tests/* from test-tools test coverage.
Testing the tests seems redundant.
2016-08-30 18:27:46 -04:00
neurodynamic
91a1e8aebc Add note about the email_password setting 2016-08-28 13:29:51 -07:00
Steve Howell
65b884f44d docs: Explain how to re-build the table of contents. 2016-08-27 11:30:57 -07:00
Steve Howell
c8e37f30d2 docs: Add "Custom Apps" to "Subsystem Documentation". 2016-08-27 11:30:57 -07:00
Steve Howell
f5a1923cbf docs: Create "Custom Apps" document. 2016-08-27 11:30:57 -07:00
Tim Abbott
0e5926ea02 tests: remove full database query pgroonga test.
This test seemed to be occasionally flaky (with the query changing by
1 character), and it's not clear it had a lot of value in the first
place.
2016-08-27 10:25:42 -07:00
Tomasz Kolek
0e192d6aff Add colors to streams in development server fixtures.
Fixes: #1454.
2016-08-26 22:38:14 -07:00
Tim Abbott
f443fcea48 README.md: Document Ubuntu 16.04 support. 2016-08-26 21:25:17 -07:00
Kouhei Sutou
683f49aa99 Support full text search for all languages using pgroonga.
This adds support for using PGroonga to back the Zulip full-text
search feature.  Because built-in PostgreSQL full text search doesn't
support languages that don't put space between terms such as Japanese,
Chinese and so on. PGroonga supports all languages including Japanese
and Chinese.

Developers will need to re-provision when rebasing past this patch for
the tests to pass, since provision is what installs the PGroonga
package and extension.

PGroonga is enabled by default in development but not in production;
the hope is that after the PGroonga support is tested further, we can
enable it by default.

Fixes #615.

[docs and tests tweaked by tabbott]
2016-08-26 21:04:03 -07:00
Steve Howell
51f35f2ff7 subject/topic: Rename empty_subject_placeholder. 2016-08-26 20:26:24 -07:00
Steve Howell
a929c6a8ba subject/topic: Rename process_message_for_recent_subjects(). 2016-08-26 20:26:24 -07:00
Steve Howell
0c8c1bb4ae subject/topic: Rename remove_expanded_subjects(). 2016-08-26 20:26:24 -07:00
Steve Howell
8216a42d85 subject/topic: Rename same_stream_and_subject(). 2016-08-26 20:26:24 -07:00
Steve Howell
93095eca85 subject/topic: Rename rebuild_recent_subjects(). 2016-08-26 20:26:24 -07:00
Steve Howell
e53b0f564f subject/topic: Rename unread_subjects to unread_topics. 2016-08-26 20:26:24 -07:00
Brock Whittaker
64079b382f Channel popup unsubscribe button.
From the popups that appear when clicking the down-arrow in the left
column's streams, you can now unsubscribe from that particular
channel. This runs on the same function that unsubscribes you from
streams in the "Subscriptions" tab.

Fixes: #1554.

[tweaked by tabbott to fix some errors]
2016-08-26 20:22:11 -07:00
saket14
83a05c2821 docs: Fix duplicate word in README.md. 2016-08-26 19:08:10 -07:00
Brock Whittaker
5840fef3b6 Text overflow for subscription description.
The text now overflows with an ellipsis and doesn’t break the page when
the page closes up.

Fixes: #1490.
2016-08-26 16:05:00 -07:00
Rishi Gupta
084bc63cad Change Day 2 email to be sent 24 hours after the user signs up.
Old behavior is to do something tricky that relies on the server being on
Pacific Time and the users being in the US. The goal is to have this message
appear during business hours, since click through rates are higher during
business hours. Our server is now on the East Coast though and our users are
in every timezone, so until we do something smarter this seems like a better
heuristic. We're also trying to cleanse our codebase of non-timezone-aware
datetime.datetime objects.
2016-08-26 15:59:30 -07:00
Brock Whittaker
64c48119de Fix message topic edit CSS.
This fixes the overflowing issues, the broken styling of the topic
edit input box, and makes it somewhat more responsive.

Fixes: #1270.
2016-08-26 15:22:39 -07:00
Brock Whittaker
5de33c94be Add padding to checkboxes and fix HTML.
The ‘for’ attribute is not valid HTML in the case of this because the
emails are invalid character sets and the input has no ID with the
email.

This changes it to a data-name which is still searchable but doesn’t
interfere with typical input behavior.

The checkboxes no longer float-left, fixing an issue with the
subscribe buttons leaning right in narrow windows.

Fixes: #1491.
2016-08-26 15:03:45 -07:00
Brock Whittaker
ce4ff5850c Add permanent scrollbar to code blocks.
This adds a permanent scrollbar to code blocks to get around some
Chrome on Mac issues where scrollbars won’t appear with particular
combinations of hardware.

Fixes: #1565.
2016-08-26 14:33:19 -07:00
Tim Abbott
1d0ae8b11c docs: Clarify that one should unpack in /root to install. 2016-08-26 11:56:12 -07:00
Tim Abbott
b200c6cdc0 Move assets/ to live under static/.
This decreases the clutter in the root directory of the Zulip
repository.
2016-08-26 10:23:38 -07:00
Brock Whittaker
d8aed0227a Put register template into centering containers.
This centers the content of the register container by putting it in
some flex box elements.
2016-08-25 20:55:55 -07:00
Brock Whittaker
b8a1dcdf0d Restyle registration pages.
The registration pages — both the landing page and the follow through
page after receiving an email have been restyled to be more linear in
nature and centered using flex box.
2016-08-25 20:55:55 -07:00
Tim Abbott
376e3736d3 templates: Reindent registration page. 2016-08-25 20:55:55 -07:00
Brock Whittaker
6f988b482a Move viewport meta-tag to base template.
The portico template inherits base but not index, but index inherits
base. Therefore the viewport meta-tag should be moved to base so that
the entire site can have the meta tag.
2016-08-25 20:26:06 -07:00
Tim Abbott
9001bebf2f Move THIRDPARTY to docs/ subdirectory. 2016-08-25 20:02:42 -07:00
Taranjeet Singh
db4e629d51 .gitignore: Remove errors and stats dir.
These directories are no longer used.
2016-08-25 19:58:53 -07:00
Taranjeet Singh
4350b6e0fb provision.py: Create dir var/node-coverage for js test coverage.
test-js-with-node: Move istanbul test coverage to var/node-coverage.

This commit moves js test coverage generated through istanbul to
var/node-coverage.
2016-08-25 19:58:30 -07:00
Taranjeet Singh
b36dfc0395 Store coverage data under var/ tree.
We set the COVERAGE_FILE environment variable which controls the
output file path for the .coverage file produced by python-coverage,
and also move the mypy coverage file to that location as well.
2016-08-25 19:51:53 -07:00
Tim Abbott
c454b180e0 zjsunit: Fix running coverage.
Previously, we would end up treating the command-line arguments to
"instanbul cover" as filenames.
2016-08-25 19:51:50 -07:00
Rag Sagar
ce1777b0cb Update update_realm view path and signature in the new feature tutorial. 2016-08-25 19:35:42 -07:00
Tim Abbott
546c23fd1f puppet: Activate pgroonga extension after installation.
The pgroonga extension needs to be activated using postgres root
access, so we make that happen from puppet.
2016-08-25 18:37:45 -07:00
Tim Abbott
9818a760b5 Install pgroonga in development and (optionally) in prod.
This is preliminary work towards being able to merge support for using
the pgroonga full-text search solution for all languages in Zulip.
2016-08-25 18:03:55 -07:00
Tim Abbott
5a065503cb docs: Update copyright license dates to include 2016. 2016-08-25 16:31:15 -07:00
Brock Whittaker
8f73701b96 Upgrade jQuery to 1.12.1 and fetch from node_modules.
Fixes: #1196.
2016-08-25 15:32:08 -07:00
Tim Abbott
3ba604cb47 Migrate jquery-validate to a current version installed via npm. 2016-08-25 15:32:08 -07:00
Tim Abbott
0644690602 Create static/node_modules symlink.
This will make it convenient to in the future install Zulip's
third-party dependencies via node without having to integrate them
with the webpack bundler.
2016-08-25 15:32:08 -07:00
Christie Koehler
7f48b3c137 tools: Update pre-commit hook so it works with vagrant dev setup.
Details:

Previously this hook required that you either be inside the vagrant
Zulip dev virtual machine when you ran git commit or that you had setup
your Zulip dev environment manually.

Now the script runs the linter via vagrant ssh if the following
conditions are met:

- VIRTUAL_ENV is not set
- vagrant is installed and a .vagrant directory exists in the repo

Otherwise the linter is run as it was before.

[tweaked to fix a few style things by tabbott]
2016-08-25 15:19:40 -07:00
Brock Whittaker
e52d618f1b Switching from $.parseJSON to JSON.parse.
There are no modern browsers that do not have built in JSON parsing
abilities. We do not need $.parseJSON as it now just serves as a call
to JSON.parse.
2016-08-25 14:22:48 -07:00
Brock Whittaker
636d2df868 Convert misuses of attr to properly use prop.
Attr now returns “checked” instead of true and “” instead of false in
higher versions. This fixes those issues.

The attr(“data-*”) have also been covered to data() as well.
2016-08-25 14:22:28 -07:00
Brock Whittaker
c16ab8d173 Set ajaxError to document, not body.
Body is deprecated and it should be bound to document instead.
2016-08-25 14:13:48 -07:00
Brock Whittaker
0ea770fc18 [spectrum.js] Patch invalid "!" color value with "#ffffff".
This code checks whether or not manual color inputs are supported in
the browser, but does so with an invalid property “!” which throws a
console.warn statement in jQuery. We change this test to a valid
“#ffffff” that works and does not throw warnings.
2016-08-25 14:13:48 -07:00
Brock Whittaker
d02414ee88 Switch from deprecated $.browser to userAgent test.
$.browser is not supported in higher versions of jQuery. The solution
is to instead use vanilla JavaScript to test the navigator.userAgent
property for the browser.

Fixes: #1033.
2016-08-25 14:12:58 -07:00
Steve Howell
4dbeb66a4c tests: Add render.init() to node tests.
This makes sure we are explicit about partials in
individual test modules.  Eventually, we should figure
out a way to make partials automatically compile as
part of the node tests.
2016-08-25 13:56:08 -07:00
Steve Howell
8e38503d8c tests: Add sidebar_private_message_list() template test. 2016-08-25 13:56:08 -07:00
Tomasz Kolek
69a9fece70 Add GitLab integration.
Fixes: #33.
2016-08-25 13:49:51 -07:00
1932 changed files with 119661 additions and 87294 deletions

19
.editorconfig Normal file
View File

@@ -0,0 +1,19 @@
root = true
[*]
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.{sh,py,js, json,yml,xml, css, md,markdown, handlebars,html}]
indent_style = space
indent_size = 4
[*.{svg,rb,pp,pl}]
indent_style = space
indent_size = 2
[*.{cfg}]
indent_style = space
indent_size = 8

3
.eslintignore Normal file
View File

@@ -0,0 +1,3 @@
static/js/bundle.js
static/js/blueslip.js
puppet/zulip_ops/files/statsd/local.js

246
.eslintrc.json Normal file
View File

@@ -0,0 +1,246 @@
{
"env": {
"node": true
},
"globals": {
"$": false,
"_": false,
"jQuery": false,
"Spinner": false,
"Handlebars": false,
"XDate": false,
"zxcvbn": false,
"LazyLoad": false,
"Dropbox": false,
"SockJS": false,
"marked": false,
"i18n": false,
"bridge": false,
"page_params": false,
"status_classes": false,
"password_quality": false,
"csrf_token": false,
"typeahead_helper": false,
"popovers": false,
"server_events": false,
"ui": false,
"stream_color": false,
"people": false,
"navigate": false,
"settings": false,
"resize": false,
"loading": false,
"compose": false,
"compose_fade": false,
"subs": false,
"timerender": false,
"message_live_update": false,
"message_edit": false,
"reload": false,
"composebox_typeahead": false,
"search": false,
"topic_list": false,
"gear_menu": false,
"hashchange": false,
"message_list": false,
"Filter": false,
"pointer": false,
"util": false,
"MessageListView": false,
"blueslip": false,
"rows": false,
"WinChan": false,
"muting_ui": false,
"Socket": false,
"channel": false,
"components": false,
"viewport": false,
"avatar": false,
"feature_flags": false,
"search_suggestion": false,
"referral": false,
"notifications": false,
"message_flags": false,
"bot_data": false,
"stream_list": false,
"narrow": false,
"admin": false,
"stream_data": false,
"muting": false,
"Dict": false,
"unread": false,
"alert_words_ui": false,
"message_store": false,
"favicon": false,
"condense": false,
"floating_recipient_bar": false,
"tab_bar": false,
"emoji": false,
"activity": false,
"invite": false,
"colorspace": false,
"reactions": false,
"tutorial": false,
"templates": false,
"alert_words": false,
"fenced_code": false,
"echo": false,
"localstorage": false,
"current_msg_list": true,
"home_msg_list": false,
"pm_list": false,
"unread_ui": false,
"user_events": false,
"Plotly": false,
"emoji_codes": false
},
"rules": {
"no-restricted-syntax": 0,
"no-nested-ternary": 0,
"spaced-comment": 0,
"space-infix-ops": 0,
"newline-per-chained-call": 0,
"no-whitespace-before-property": 0,
"padded-blocks": 0,
"space-in-parens": 0,
"eol-last": ["error", "always"],
"no-unneeded-ternary": ["error", { "defaultAssignment": false }],
"no-case-declarations": "error",
"eqeqeq": ["error", "allow-null"],
"no-duplicate-imports": "error",
"no-undef": "error",
"dot-notation": ["error", { "allowKeywords": true }],
"no-iterator": "error",
"no-dupe-class-members": "error",
"no-useless-constructor": "error",
"prefer-const": ["error", {
"destructuring": "any",
"ignoreReadBeforeAssign": true
}],
"no-const-assign": "error",
"no-new-object": 2,
"quote-props": ["error", "as-needed", {
"keywords": false,
"unnecessary": true,
"numbers": false
}],
"no-array-constructor": "error",
"array-callback-return": "error",
"template-curly-spacing": "error",
//The Zulip codebase complies partially with the "no-useless-escape" rule; only regex expressions haven't been updated yet.
//Updated regex expressions are currently being tested in casper files and will decide about a potential future enforcement of this rule.
"no-useless-escape": 0,
"func-style": ["off", "expression"],
"wrap-iife": ["error", "outside", { "functionPrototypeMethods": false }],
"no-new-func": "error",
"space-before-function-paren": ["error", { "anonymous": "always", "named": "never", "asyncArrow": "always" }],
"no-param-reassign": 0,
"prefer-spread": "error",
"arrow-spacing": ["error", { "before": true, "after": true }],
"no-alert": 2,
"no-array-constructor": 2,
"no-caller": 2,
"no-bitwise": 2,
"no-catch-shadow": 2,
"comma-dangle": ["error", {
"arrays": "always-multiline",
"objects": "always-multiline",
"imports": "always-multiline",
"exports": "always-multiline",
"functions": "never"
}],
"no-console": 0,
"no-control-regex": 2,
"no-debugger": 2,
"no-div-regex": 2,
"no-dupe-keys": 2,
"no-else-return": 2,
"no-empty": 2,
"no-empty-character-class": 2,
"no-eq-null": 2,
"no-eval": 2,
"no-ex-assign": 2,
"no-extra-semi": 2,
"no-func-assign": 2,
"no-floating-decimal": 2,
"no-implied-eval": 2,
"no-with": 2,
"no-fallthrough": 2,
"no-unreachable": 2,
"no-undef": 2,
"no-undef-init": 2,
"no-unused-expressions": 2,
"no-octal": 2,
"no-octal-escape": 2,
"no-obj-calls": 2,
"no-multi-str": 2,
"no-new-wrappers": 2,
"no-new": 2,
"no-new-func": 2,
"no-native-reassign": 2,
"no-plusplus": 2,
"no-delete-var": 2,
"no-return-assign": 2,
"no-new-object": 2,
"no-label-var": 2,
"no-ternary": 0,
"no-self-compare": 2,
"no-sync": 2,
"no-underscore-dangle": 0,
"no-loop-func": 2,
"no-labels": 2,
"no-unused-vars": ["error", { "vars": "local", "args": "after-used",
"varsIgnorePattern": "print_elapsed_time|check_duplicate_ids"
}],
"no-script-url": 2,
"no-proto": 2,
"no-iterator": 2,
"no-mixed-requires": [0, false],
"no-extra-parens": ["error", "functions"],
"no-shadow": 0,
"no-use-before-define": 2,
"no-redeclare": 2,
"no-regex-spaces": 2,
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
"block-scoped-var": 2,
"camelcase": 0,
"complexity": [0, 4],
"curly": 2,
"dot-notation": 2,
"guard-for-in": 2,
"max-depth": [0, 4],
"max-len": ["error", 100, 2, {
"ignoreUrls": true,
"ignoreComments": false,
"ignoreRegExpLiterals": true,
"ignoreStrings": true,
"ignoreTemplateLiterals": true
}],
"max-params": [0, 3],
"max-statements": [0, 10],
"new-cap": ["error", { "newIsCap": true, "capIsNew": false }],
"new-parens": 2,
"one-var": ["error", "never"],
"quotes": [0, "single"],
"quote-props": ["error", "as-needed", { "keywords": false, "unnecessary": true, "numbers": false }],
"radix": 2,
"semi": 2,
"keyword-spacing": ["error", {
"before": true,
"after": true,
"overrides": {
"return": { "after": true },
"throw": { "after": true },
"case": { "after": true }
}
}],
"space-before-blocks": 2,
"strict": 0,
"unnecessary-strict": 0,
"use-isnan": 2,
"valid-typeof": ["error", { "requireStringLiterals": true }],
"wrap-iife": 2,
"wrap-regex": 0,
"yoda": 2
}
}

14
.gitattributes vendored
View File

@@ -1,13 +1,21 @@
* text=auto eol=lf
*.gif binary
*.jpg binary
*.eot binary
*.woff binary
*.svg binary
*.ttf binary
*.png binary
*.otf binary
*.tif binary
.gitignore export-ignore
.gitattributes export-ignore
/analytics export-ignore
/assets export-ignore
/static/assets export-ignore
/bots export-ignore
/corporate export-ignore
/static export-ignore
/tools export-ignore
/zilencer export-ignore
/templates/analytics export-ignore
/templates/corporate export-ignore
/templates/zilencer export-ignore
/puppet/zulip_internal export-ignore

13
.gitignore vendored
View File

@@ -1,10 +1,8 @@
*.pyc
*~
/prod-static
/errors/*
*.sw[po]
*.DS_Store
stats/
.kdev4
.idea
zulip.kdev4
@@ -14,13 +12,18 @@ coverage/
.kateproject.d/
.kateproject
*.kate-swp
*.sublime-project
*.sublime-workspace
.vagrant
/zproject/dev-secrets.conf
static/js/bundle.js
static/third/gemoji/
static/third/zxcvbn/
static/generated/emoji
static/generated/github-contributors.json
static/locale/language_options.json
node_modules
/node_modules
/staticfiles.json
npm-debug.log
*.mo
var/*
.vscode/
tools/conf.ini

View File

@@ -2,18 +2,20 @@ dist: trusty
before_install:
- nvm install 0.10
install:
# Disable Travis CI's built-in NVM installation
- mv ~/.nvm ~/.travis-nvm-disabled
- pip install coveralls
- tools/travis/setup-$TEST_SUITE
- tools/clean-venv-cache --travis
cache:
- apt: false
- directories:
- $HOME/phantomjs
- $HOME/zulip-venv-cache
- node_modules
- $HOME/node
env:
global:
- COVERAGE_FILE=var/.coverage
- COVERALLS_PARALLEL=true
- COVERALLS_SERVICE_NAME=travis-pro
- COVERALLS_REPO_TOKEN=hnXUEBKsORKHc8xIENGs9JjktlTb2HKlG
@@ -29,9 +31,10 @@ matrix:
include:
- python: "3.4"
env: TEST_SUITE=static-analysis
- python: "3.4"
env: TEST_SUITE=production
- python: "2.7"
env: TEST_SUITE=production
sudo: required
# command to run tests
script:
- unset GEM_PATH
@@ -40,6 +43,10 @@ sudo: required
services:
- docker
addons:
artifacts:
paths:
- $(ls var/casper/* | tr "\n" ":")
- $(ls /tmp/zulip-test-event-log/* | tr "\n" ":")
postgresql: "9.3"
after_success:
coveralls

View File

@@ -6,12 +6,9 @@ source_file = static/locale/en/LC_MESSAGES/django.po
source_lang = en
type = PO
file_filter = static/locale/<lang>/LC_MESSAGES/django.po
lang_map = zh-Hans: zh_CN
[zulip.translationsjson]
source_file = static/locale/en/translations.json
source_lang = en
type = KEYVALUEJSON
file_filter = static/locale/<lang>/translations.json
lang_map = zh-Hans: zh-CN

View File

@@ -6,10 +6,14 @@ RUN apt-get update && apt-get install -y \
python-pbs \
wget
RUN locale-gen en_US.UTF-8
RUN useradd -d /home/zulip -m zulip && echo 'zulip ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
USER zulip
RUN ln -nsf /srv/zulip ~/zulip
RUN echo 'export LC_ALL="en_US.UTF-8" LANG="en_US.UTF-8" LANGUAGE="en_US.UTF-8"' >> ~zulip/.bashrc
WORKDIR /srv/zulip

View File

@@ -19,30 +19,44 @@ 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](https://travis-ci.org/zulip/zulip.svg?branch=master)](https://travis-ci.org/zulip/zulip) [![Coverage Status](https://coveralls.io/repos/github/zulip/zulip/badge.svg?branch=master)](https://coveralls.io/github/zulip/zulip?branch=master)
[![Build Status](https://travis-ci.org/zulip/zulip.svg?branch=master)](https://travis-ci.org/zulip/zulip) [![Coverage Status](https://coveralls.io/repos/github/zulip/zulip/badge.svg?branch=master)](https://coveralls.io/github/zulip/zulip?branch=master) [![docs](https://readthedocs.org/projects/zulip/badge/?version=latest)](http://zulip.readthedocs.io/en/latest/) [![Zulip chat](https://img.shields.io/badge/zulip-join_chat-brightgreen.svg)](https://chat.zulip.org)
## Community
There are several places online where folks discuss Zulip.
One of those places is our [public Zulip instance](https://zulip.tabbott.net/).
One of those places is our [public Zulip instance](https://chat.zulip.org/).
You can go through the simple signup process at that link, and then you
will soon be talking to core Zulip developers and other users. To get
help in real time, you will have the best luck finding core developers
roughly between 16:00 UTC and 23:59 UTC. Most questions get answered
within a day.
roughly between 16:00 UTC and 23:59 UTC. Most questions get a reply
within minutes to a few hours, depending on time of day.
We have a [Google mailing list](https://groups.google.com/forum/#!forum/zulip-devel)
that is currently pretty low traffic. It is where we do things like
announce public meetings or major releases. You can also use it to
ask questions about features or possible bugs.
For Google Summer of Code students and applicants, we have [a mailing
list](https://groups.google.com/forum/#!forum/zulip-gsoc) for help,
questions, and announcements.
We have
[a public mailing list](https://groups.google.com/forum/#!forum/zulip-devel)
that is currently pretty low traffic because most discussions happen
in our public Zulip instance. We use it to announce Zulip developer
community gatherings and ask for feedback on major technical or design
decisions. It has several hundred subscribers, so you can use it to
ask questions about features or possible bugs, but please don't use it
ask for generic help getting started as a contributor (e.g. because
you want to do Google Summer of Code). The rest of this page covers
how to get involved in the Zulip project in detail.
Zulip also has a [blog](https://blog.zulip.org/).
Last but not least, we use [GitHub](https://github.com/zulip/zulip) to
track Zulip-related issues (and store our code, of course).
Anybody with a Github account should be able to create Issues there
Anybody with a GitHub account should be able to create Issues there
pertaining to bugs or enhancement requests. We also use Pull
Requests as our primary mechanism to receive code contributions.
The Zulip community has a [Code of Conduct][code-of-conduct].
## Installing the Zulip Development environment
The Zulip development environment is the recommended option for folks
@@ -51,10 +65,10 @@ installation guide][dev-install].
## Running Zulip in production
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 at https://zulip.org/server.html and in more
detail in [the
Zulip in production supports Ubuntu 14.04 Trusty and Ubuntu 16.04
Xenial. Work is ongoing on adding support for additional
platforms. The installation process is documented at
https://zulip.org/server.html and in more detail in [the
documentation](https://zulip.readthedocs.io/en/latest/prod-install.html).
## Ways to contribute
@@ -63,7 +77,7 @@ 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,
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
@@ -80,7 +94,7 @@ and [new feature tutorial][doc-newfeat]. You can also improve
[Zulip.org][z-org].
* **Mailing lists and bug tracker**. Zulip has a [development
discussion mailing list][gg-devel] and uses [GitHub issues
discussion mailing list](#community) 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
@@ -95,8 +109,9 @@ app][electron].
* **Glue code**. We maintain a [Hubot adapter][hubot-adapter] and several
integrations ([Phabricator][phab], [Jenkins][], [Puppet][], [Redmine][],
and [Trello][]), plus [node.js API bindings][node], and a [full-text search
PostgreSQL extension][tsearch], as separate repos.
and [Trello][]), plus [node.js API bindings][node], an [isomorphic
JavaScript library][zulip-js], and a [full-text search PostgreSQL
extension][tsearch], as separate repos.
* **Translations**. Zulip is in the process of being translated into
10+ languages, and we love contributions to our translations. See our
@@ -104,14 +119,14 @@ PostgreSQL extension][tsearch], as separate repos.
contributing!
[cla]: https://opensource.dropbox.com/cla/
[code-of-conduct]: https://zulip.readthedocs.io/en/latest/code-of-conduct.html
[dev-install]: https://zulip.readthedocs.io/en/latest/dev-overview.html
[doc]: https://zulip.readthedocs.io/
[doc-commit-style]: http://zulip.readthedocs.io/en/latest/code-style.html#commit-messages
[doc-commit-style]: http://zulip.readthedocs.io/en/latest/version-control.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]: http://zulip.readthedocs.io/en/latest/testing.html
[electron]: https://github.com/zulip/zulip-electron
[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
@@ -122,6 +137,7 @@ contributing!
[hubot-adapter]: https://github.com/zulip/hubot-zulip
[jenkins]: https://github.com/zulip/zulip-jenkins-plugin
[node]: https://github.com/zulip/zulip-node
[zulip-js]: https://github.com/zulip/zulip-js
[phab]: https://github.com/zulip/phabricator-to-zulip
[puppet]: https://github.com/matthewbarr/puppet-zulip
[redmine]: https://github.com/zulip/zulip-redmine-plugin
@@ -130,10 +146,19 @@ contributing!
[transifex]: https://zulip.readthedocs.io/en/latest/translating.html#testing-translations
[z-org]: https://github.com/zulip/zulip.github.io
## Google Summer of Code
We participated in
[GSoC](https://developers.google.com/open-source/gsoc/) last year and
hope to do so again in 2017. For guidance, please read
[our GSoC instructions and ideas page](https://github.com/zulip/zulip.github.io/blob/master/gsoc-ideas.md)
and feel free to email
[our GSoC mailing list](https://groups.google.com/forum/#!forum/zulip-gsoc).
## How to get involved with contributing to Zulip
First, subscribe to the Zulip [development discussion mailing
list][gg-devel].
list](#community).
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
@@ -141,7 +166,7 @@ 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).
* [Integrations](https://github.com/zulip/zulip/labels/area%3A%20integrations).
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
@@ -151,7 +176,7 @@ mind:
* [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):
* [Documentation](https://github.com/zulip/zulip/labels/area%3A%20documentation):
The Zulip project loves contributions of new documentation.
* [Help Wanted](https://github.com/zulip/zulip/labels/help%20wanted):
@@ -167,8 +192,20 @@ mind:
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.
* [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.
Another way to find issues in Zulip is to take advantage of our
"area:<foo>" convention in separating out issues. We partition all of
our issues into areas like admin, compose, emoji, hotkeys, i18n,
onboarding, search, etc. You can see this here:
[https://github.com/zulip/zulip/labels]
Click on any of the "area:" labels and you will see all the tickets
related to your area of interest.
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
@@ -206,7 +243,7 @@ to the Zulip Developers list with your thoughts.
## License
Copyright 2011-2015 Dropbox, Inc.
Copyright 2011-2016 Dropbox, Inc. and contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -223,4 +260,4 @@ limitations under the License.
The software includes some works released by third parties under other
free and open source licenses. Those works are redistributed under the
license terms under which the works were received. For more details,
see the ``THIRDPARTY`` file included with this distribution.
see the ``docs/THIRDPARTY`` file included with this distribution.

32
Vagrantfile vendored
View File

@@ -7,6 +7,18 @@ def command?(name)
$?.success?
end
if Vagrant::VERSION == "1.8.7" then
path = `which curl`
if path.include?('/opt/vagrant/embedded/bin/curl') then
puts "In Vagrant 1.8.7, curl is broken. Please use Vagrant 1.8.6 "\
"or run 'sudo rm -f /opt/vagrant/embedded/bin/curl' to fix the "\
"issue before provisioning. See "\
"https://github.com/mitchellh/vagrant/issues/7997 "\
"for reference."
exit
end
end
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# For LXC. VirtualBox hosts use a different box, described below.
@@ -15,6 +27,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# The Zulip development environment runs on 9991 on the guest.
host_port = 9991
http_proxy = https_proxy = no_proxy = ""
host_ip_addr = "127.0.0.1"
config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.synced_folder ".", "/srv/zulip"
@@ -30,11 +43,12 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
when "HTTPS_PROXY"; https_proxy = value
when "NO_PROXY"; no_proxy = value
when "HOST_PORT"; host_port = value.to_i
when "HOST_IP_ADDR"; host_ip_addr = value
end
end
end
config.vm.network "forwarded_port", guest: 9991, host: host_port, host_ip: "127.0.0.1"
config.vm.network "forwarded_port", guest: 9991, host: host_port, host_ip: host_ip_addr
if Vagrant.has_plugin?("vagrant-proxyconf")
if http_proxy != ""
@@ -67,18 +81,30 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
override.vm.box = "ubuntu/trusty64"
# It's possible we can get away with just 1.5GB; more testing needed
vb.memory = 2048
vb.cpus = 2
end
config.vm.provider "vmware_fusion" do |vb, override|
override.vm.box = "puphpet/ubuntu1404-x64"
vb.vmx["memsize"] = "2048"
vb.vmx["numvcpus"] = "2"
end
$provision_script = <<SCRIPT
set -x
set -e
set -o pipefail
# If the host is running SELinux remount the /sys/fs/selinux directory as read only,
# needed for apt-get to work.
if [ -d "/sys/fs/selinux" ]; then
sudo mount -o remount,ro /sys/fs/selinux
fi
ln -nsf /srv/zulip ~/zulip
/usr/bin/python /srv/zulip/tools/provision.py | sudo tee -a /var/log/zulip_provision.log
/srv/zulip/tools/provision
SCRIPT
config.vm.provision "shell",
# We want provision.py to be run with the permissions of the vagrant user.
# We want provision to be run with the permissions of the vagrant user.
privileged: false,
inline: $provision_script
end

353
analytics/lib/counts.py Normal file
View File

@@ -0,0 +1,353 @@
from django.db import connection, models
from django.utils import timezone
from django.conf import settings
from datetime import timedelta, datetime
from analytics.models import InstallationCount, RealmCount, \
UserCount, StreamCount, BaseCount, FillState, installation_epoch
from zerver.models import Realm, UserProfile, Message, Stream, models
from zerver.lib.timestamp import floor_to_day
from typing import Any, Optional, Type, Tuple, Text
import logging
import time
## Logging setup ##
log_format = '%(asctime)s %(levelname)-8s %(message)s'
logging.basicConfig(format=log_format)
formatter = logging.Formatter(log_format)
file_handler = logging.FileHandler(settings.ANALYTICS_LOG_PATH)
file_handler.setFormatter(formatter)
logger = logging.getLogger("zulip.management")
logger.setLevel(logging.INFO)
logger.addHandler(file_handler)
# First post office in Boston
MIN_TIME = datetime(1639, 1, 1, 0, 0, 0, tzinfo=timezone.utc)
class CountStat(object):
HOUR = 'hour'
DAY = 'day'
FREQUENCIES = frozenset([HOUR, DAY])
# Allowed intervals are HOUR, DAY, and, GAUGE
GAUGE = 'gauge'
def __init__(self, property, zerver_count_query, filter_args, group_by, frequency, is_gauge):
# type: (str, ZerverCountQuery, Dict[str, bool], Optional[Tuple[models.Model, str]], str, bool) -> None
self.property = property
self.zerver_count_query = zerver_count_query
# might have to do something different for bitfields
self.filter_args = filter_args
self.group_by = group_by
if frequency not in self.FREQUENCIES:
raise ValueError("Unknown frequency: %s" % (frequency,))
self.frequency = frequency
self.interval = self.GAUGE if is_gauge else frequency
def __unicode__(self):
# type: () -> Text
return u"<CountStat: %s>" % (self.property,)
class ZerverCountQuery(object):
def __init__(self, zerver_table, analytics_table, query):
# type: (Type[models.Model], Type[BaseCount], Text) -> None
self.zerver_table = zerver_table
self.analytics_table = analytics_table
self.query = query
def do_update_fill_state(fill_state, end_time, state):
# type: (FillState, datetime, int) -> None
fill_state.end_time = end_time
fill_state.state = state
fill_state.save()
def process_count_stat(stat, fill_to_time):
# type: (CountStat, datetime) -> None
fill_state = FillState.objects.filter(property=stat.property).first()
if fill_state is None:
currently_filled = installation_epoch()
fill_state = FillState.objects.create(property=stat.property,
end_time=currently_filled,
state=FillState.DONE)
logger.info("INITIALIZED %s %s" % (stat.property, currently_filled))
elif fill_state.state == FillState.STARTED:
logger.info("UNDO START %s %s" % (stat.property, fill_state.end_time))
do_delete_count_stat_at_hour(stat, fill_state.end_time)
currently_filled = fill_state.end_time - timedelta(hours = 1)
do_update_fill_state(fill_state, currently_filled, FillState.DONE)
logger.info("UNDO DONE %s" % (stat.property,))
elif fill_state.state == FillState.DONE:
currently_filled = fill_state.end_time
else:
raise ValueError("Unknown value for FillState.state: %s." % (fill_state.state,))
currently_filled = currently_filled + timedelta(hours = 1)
while currently_filled <= fill_to_time:
logger.info("START %s %s %s" % (stat.property, stat.interval, currently_filled))
start = time.time()
do_update_fill_state(fill_state, currently_filled, FillState.STARTED)
do_fill_count_stat_at_hour(stat, currently_filled)
do_update_fill_state(fill_state, currently_filled, FillState.DONE)
end = time.time()
currently_filled = currently_filled + timedelta(hours = 1)
logger.info("DONE %s %s (%dms)" % (stat.property, stat.interval, (end-start)*1000))
# We assume end_time is on an hour boundary, and is timezone aware.
# It is the caller's responsibility to enforce this!
def do_fill_count_stat_at_hour(stat, end_time):
# type: (CountStat, datetime) -> None
if stat.frequency == CountStat.DAY and (end_time != floor_to_day(end_time)):
return
if stat.interval == CountStat.HOUR:
start_time = end_time - timedelta(hours = 1)
elif stat.interval == CountStat.DAY:
start_time = end_time - timedelta(days = 1)
else: # stat.interval == CountStat.GAUGE
start_time = MIN_TIME
do_pull_from_zerver(stat, start_time, end_time)
do_aggregate_to_summary_table(stat, end_time)
def do_delete_count_stat_at_hour(stat, end_time):
# type: (CountStat, datetime) -> None
UserCount.objects.filter(property = stat.property, end_time = end_time).delete()
StreamCount.objects.filter(property = stat.property, end_time = end_time).delete()
RealmCount.objects.filter(property = stat.property, end_time = end_time).delete()
InstallationCount.objects.filter(property = stat.property, end_time = end_time).delete()
def do_drop_all_analytics_tables():
# type: () -> None
UserCount.objects.all().delete()
StreamCount.objects.all().delete()
RealmCount.objects.all().delete()
InstallationCount.objects.all().delete()
FillState.objects.all().delete()
def do_aggregate_to_summary_table(stat, end_time):
# type: (CountStat, datetime) -> None
cursor = connection.cursor()
# Aggregate into RealmCount
analytics_table = stat.zerver_count_query.analytics_table
if analytics_table in (UserCount, StreamCount):
realmcount_query = """
INSERT INTO analytics_realmcount
(realm_id, value, property, subgroup, end_time)
SELECT
zerver_realm.id, COALESCE(sum(%(analytics_table)s.value), 0), '%(property)s',
%(analytics_table)s.subgroup, %%(end_time)s
FROM zerver_realm
JOIN %(analytics_table)s
ON
(
%(analytics_table)s.realm_id = zerver_realm.id AND
%(analytics_table)s.property = '%(property)s' AND
%(analytics_table)s.end_time = %%(end_time)s
)
GROUP BY zerver_realm.id, %(analytics_table)s.subgroup
""" % {'analytics_table': analytics_table._meta.db_table,
'property': stat.property}
start = time.time()
cursor.execute(realmcount_query, {'end_time': end_time})
end = time.time()
logger.info("%s RealmCount aggregation (%dms/%sr)" % (stat.property, (end-start)*1000, cursor.rowcount))
# Aggregate into InstallationCount
installationcount_query = """
INSERT INTO analytics_installationcount
(value, property, subgroup, end_time)
SELECT
sum(value), '%(property)s', analytics_realmcount.subgroup, %%(end_time)s
FROM analytics_realmcount
WHERE
(
property = '%(property)s' AND
end_time = %%(end_time)s
) GROUP BY analytics_realmcount.subgroup
""" % {'property': stat.property}
start = time.time()
cursor.execute(installationcount_query, {'end_time': end_time})
end = time.time()
logger.info("%s InstallationCount aggregation (%dms/%sr)" % (stat.property, (end-start)*1000, cursor.rowcount))
cursor.close()
# This is the only method that hits the prod databases directly.
def do_pull_from_zerver(stat, start_time, end_time):
# type: (CountStat, datetime, datetime) -> None
zerver_table = stat.zerver_count_query.zerver_table._meta.db_table # type: ignore
join_args = ' '.join('AND %s.%s = %s' % (zerver_table, key, value)
for key, value in stat.filter_args.items())
if stat.group_by is None:
subgroup = 'NULL'
group_by_clause = ''
else:
subgroup = '%s.%s' % (stat.group_by[0]._meta.db_table, stat.group_by[1])
group_by_clause = ', ' + subgroup
# We do string replacement here because passing join_args as a param
# may result in problems when running cursor.execute; we do
# the string formatting prior so that cursor.execute runs it as sql
query_ = stat.zerver_count_query.query % {'zerver_table': zerver_table,
'property': stat.property,
'join_args': join_args,
'subgroup': subgroup,
'group_by_clause': group_by_clause}
cursor = connection.cursor()
start = time.time()
cursor.execute(query_, {'time_start': start_time, 'time_end': end_time})
end = time.time()
logger.info("%s do_pull_from_zerver (%dms/%sr)" % (stat.property, (end-start)*1000, cursor.rowcount))
cursor.close()
count_user_by_realm_query = """
INSERT INTO analytics_realmcount
(realm_id, value, property, subgroup, end_time)
SELECT
zerver_realm.id, count(%(zerver_table)s),'%(property)s', %(subgroup)s, %%(time_end)s
FROM zerver_realm
JOIN zerver_userprofile
ON
(
zerver_userprofile.realm_id = zerver_realm.id AND
zerver_userprofile.date_joined >= %%(time_start)s AND
zerver_userprofile.date_joined < %%(time_end)s
%(join_args)s
)
WHERE
zerver_realm.date_created < %%(time_end)s
GROUP BY zerver_realm.id %(group_by_clause)s
"""
zerver_count_user_by_realm = ZerverCountQuery(UserProfile, RealmCount, count_user_by_realm_query)
# currently .sender_id is only Message specific thing
count_message_by_user_query = """
INSERT INTO analytics_usercount
(user_id, realm_id, value, property, subgroup, end_time)
SELECT
zerver_userprofile.id, zerver_userprofile.realm_id, count(*), '%(property)s', %(subgroup)s, %%(time_end)s
FROM zerver_userprofile
JOIN zerver_message
ON
(
zerver_message.sender_id = zerver_userprofile.id AND
zerver_message.pub_date >= %%(time_start)s AND
zerver_message.pub_date < %%(time_end)s
%(join_args)s
)
WHERE
zerver_userprofile.date_joined < %%(time_end)s
GROUP BY zerver_userprofile.id %(group_by_clause)s
"""
zerver_count_message_by_user = ZerverCountQuery(Message, UserCount, count_message_by_user_query)
# Currently unused and untested
count_stream_by_realm_query = """
INSERT INTO analytics_realmcount
(realm_id, value, property, subgroup, end_time)
SELECT
zerver_realm.id, count(*), '%(property)s', %(subgroup)s, %%(time_end)s
FROM zerver_realm
JOIN zerver_stream
ON
(
zerver_stream.realm_id = zerver_realm.id AND
zerver_stream.date_created >= %%(time_start)s AND
zerver_stream.date_created < %%(time_end)s
%(join_args)s
)
WHERE
zerver_realm.date_created < %%(time_end)s
GROUP BY zerver_realm.id %(group_by_clause)s
"""
zerver_count_stream_by_realm = ZerverCountQuery(Stream, RealmCount, count_stream_by_realm_query)
# This query violates the count_X_by_Y_query conventions in several ways. One,
# the X table is not specified by the query name; MessageType is not a zerver
# table. Two, it ignores the subgroup column in the CountStat object; instead,
# it uses 'message_type' from the subquery to fill in the subgroup column.
count_message_type_by_user_query = """
INSERT INTO analytics_usercount
(realm_id, user_id, value, property, subgroup, end_time)
SELECT realm_id, id, SUM(count) AS value, '%(property)s', message_type, %%(time_end)s
FROM
(
SELECT zerver_userprofile.realm_id, zerver_userprofile.id, count(*),
CASE WHEN
zerver_recipient.type != 2 THEN 'private_message'
WHEN
zerver_stream.invite_only = TRUE THEN 'private_stream'
ELSE 'public_stream'
END
message_type
FROM zerver_userprofile
JOIN zerver_message
ON
zerver_message.sender_id = zerver_userprofile.id AND
zerver_message.pub_date >= %%(time_start)s AND
zerver_message.pub_date < %%(time_end)s
%(join_args)s
JOIN zerver_recipient
ON
zerver_recipient.id = zerver_message.recipient_id
LEFT JOIN zerver_stream
ON
zerver_stream.id = zerver_recipient.type_id
GROUP BY zerver_userprofile.realm_id, zerver_userprofile.id, zerver_recipient.type, zerver_stream.invite_only
) AS subquery
GROUP BY realm_id, id, message_type
"""
zerver_count_message_type_by_user = ZerverCountQuery(Message, UserCount, count_message_type_by_user_query)
# Note that this query also joins to the UserProfile table, since all
# current queries that use this also subgroup on UserProfile.is_bot. If in
# the future there is a query that counts messages by stream and doesn't need
# the UserProfile table, consider writing a new query for efficiency.
count_message_by_stream_query = """
INSERT INTO analytics_streamcount
(stream_id, realm_id, value, property, subgroup, end_time)
SELECT
zerver_stream.id, zerver_stream.realm_id, count(*), '%(property)s', %(subgroup)s, %%(time_end)s
FROM zerver_stream
JOIN zerver_recipient
ON
(
zerver_recipient.type = 2 AND
zerver_stream.id = zerver_recipient.type_id
)
JOIN zerver_message
ON
(
zerver_message.recipient_id = zerver_recipient.id AND
zerver_message.pub_date >= %%(time_start)s AND
zerver_message.pub_date < %%(time_end)s AND
zerver_stream.date_created < %%(time_end)s
%(join_args)s
)
JOIN zerver_userprofile
ON zerver_userprofile.id = zerver_message.sender_id
GROUP BY zerver_stream.id %(group_by_clause)s
"""
zerver_count_message_by_stream = ZerverCountQuery(Message, StreamCount, count_message_by_stream_query)
COUNT_STATS = {
'active_users:is_bot:day': CountStat(
'active_users:is_bot:day', zerver_count_user_by_realm, {'is_active': True},
(UserProfile, 'is_bot'), CountStat.DAY, True),
'messages_sent:is_bot:hour': CountStat(
'messages_sent:is_bot:hour', zerver_count_message_by_user, {},
(UserProfile, 'is_bot'), CountStat.HOUR, False),
'messages_sent:message_type:day': CountStat(
'messages_sent:message_type:day', zerver_count_message_type_by_user, {},
None, CountStat.DAY, False),
'messages_sent:client:day': CountStat(
'messages_sent:client:day', zerver_count_message_by_user, {},
(Message, 'sending_client_id'), CountStat.DAY, False),
'messages_sent_to_stream:is_bot:hour': CountStat(
'messages_sent_to_stream:is_bot', zerver_count_message_by_stream, {},
(UserProfile, 'is_bot'), CountStat.HOUR, False)
}

69
analytics/lib/fixtures.py Normal file
View File

@@ -0,0 +1,69 @@
from __future__ import division, absolute_import
from zerver.models import Realm, UserProfile, Stream, Message
from analytics.models import InstallationCount, RealmCount, UserCount, StreamCount
from analytics.lib.counts import CountStat
from analytics.lib.time_utils import time_range
from datetime import datetime
from math import sqrt
from random import gauss, random, seed
from six.moves import range, zip
def generate_time_series_data(days=100, business_hours_base=10, non_business_hours_base=10,
growth=1, autocorrelation=0, spikiness=1, holiday_rate=0,
frequency=CountStat.DAY, is_gauge=False, random_seed=26):
# type: (int, float, float, float, float, float, float, str, bool, int) -> List[int]
"""
Generate semi-realistic looking time series data for testing analytics graphs.
days -- Number of days of data. Is the number of data points generated if
frequency is CountStat.DAY.
business_hours_base -- Average value during a business hour (or day) at beginning of
time series, if frequency is CountStat.HOUR (CountStat.DAY, respectively).
non_business_hours_base -- The above, for non-business hours/days.
growth -- Ratio between average values at end of time series and beginning of time series.
autocorrelation -- Makes neighboring data points look more like each other. At 0 each
point is unaffected by the previous point, and at 1 each point is a deterministic
function of the previous point.
spikiness -- 0 means no randomness (other than holiday_rate), higher values increase
the variance.
holiday_rate -- Fraction of days randomly set to 0, largely for testing how we handle 0s.
frequency -- Should be CountStat.HOUR or CountStat.DAY.
is_gauge -- If True, return partial sum of the series.
random_seed -- Seed for random number generator.
"""
if frequency == CountStat.HOUR:
length = days*24
seasonality = [non_business_hours_base] * 24 * 7
for day in range(5):
for hour in range(8):
seasonality[24*day + hour] = business_hours_base
holidays = []
for i in range(days):
holidays.extend([random() < holiday_rate] * 24)
elif frequency == CountStat.DAY:
length = days
seasonality = [8*business_hours_base + 16*non_business_hours_base] * 5 + \
[24*non_business_hours_base] * 2
holidays = [random() < holiday_rate for i in range(days)]
else:
raise ValueError("Unknown frequency: %s" % (frequency,))
if length < 2:
raise ValueError("Must be generating at least 2 data points. "
"Currently generating %s" % (length,))
growth_base = growth ** (1. / (length-1))
values_no_noise = [seasonality[i % len(seasonality)] * (growth_base**i) for i in range(length)]
seed(random_seed)
noise_scalars = [gauss(0, 1)]
for i in range(1, length):
noise_scalars.append(noise_scalars[-1]*autocorrelation + gauss(0, 1)*(1-autocorrelation))
values = [0 if holiday else int(v + sqrt(v)*noise_scalar*spikiness)
for v, noise_scalar, holiday in zip(values_no_noise, noise_scalars, holidays)]
if is_gauge:
for i in range(1, length):
values[i] = values[i-1] + values[i]
return [max(v, 0) for v in values]

View File

@@ -0,0 +1,29 @@
from zerver.lib.timestamp import floor_to_hour, floor_to_day, timestamp_to_datetime
from analytics.lib.counts import CountStat
from datetime import datetime, timedelta
from typing import List, Optional
# If min_length is None, returns end_times from ceiling(start) to floor(end), inclusive.
# If min_length is greater than 0, pads the list to the left.
# So informally, time_range(Sep 20, Sep 22, day, None) returns [Sep 20, Sep 21, Sep 22],
# and time_range(Sep 20, Sep 22, day, 5) returns [Sep 18, Sep 19, Sep 20, Sep 21, Sep 22]
def time_range(start, end, frequency, min_length):
# type: (datetime, datetime, str, Optional[int]) -> List[datetime]
if frequency == CountStat.HOUR:
end = floor_to_hour(end)
step = timedelta(hours=1)
elif frequency == CountStat.DAY:
end = floor_to_day(end)
step = timedelta(days=1)
else:
raise ValueError("Unknown frequency: %s" % (frequency,))
times = []
if min_length is not None:
start = min(start, end - (min_length-1)*step)
current = end
while current >= start:
times.append(current)
current -= step
return list(reversed(times))

View File

@@ -33,10 +33,10 @@ class Command(BaseCommand):
known_active = last_presence.timestamp
for bucket in hour_buckets:
if bucket not in user_info[last_presence.user_profile.realm.domain]:
user_info[last_presence.user_profile.realm.domain][bucket] = []
if bucket not in user_info[last_presence.user_profile.realm.string_id]:
user_info[last_presence.user_profile.realm.string_id][bucket] = []
if datetime.now(known_active.tzinfo) - known_active < timedelta(hours=bucket):
user_info[last_presence.user_profile.realm.domain][bucket].append(last_presence.user_profile.email)
user_info[last_presence.user_profile.realm.string_id][bucket].append(last_presence.user_profile.email)
for realm, buckets in user_info.items():
print("Realm %s" % (realm,))
@@ -49,10 +49,10 @@ class Command(BaseCommand):
user_info = defaultdict(dict)
for activity in users_reading:
for bucket in hour_buckets:
if bucket not in user_info[activity.user_profile.realm.domain]:
user_info[activity.user_profile.realm.domain][bucket] = []
if bucket not in user_info[activity.user_profile.realm.string_id]:
user_info[activity.user_profile.realm.string_id][bucket] = []
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)
user_info[activity.user_profile.realm.string_id][bucket].append(activity.user_profile.email)
for realm, buckets in user_info.items():
print("Realm %s" % (realm,))
for hr, users in sorted(buckets.items()):

View File

@@ -6,15 +6,16 @@ import pytz
from optparse import make_option
from typing import Any
from django.core.management.base import BaseCommand
from django.core.management.base import BaseCommand, CommandParser
from zerver.lib.statistics import activity_averages_during_day
class Command(BaseCommand):
help = "Generate statistics on user activity for a given day."
option_list = BaseCommand.option_list + \
(make_option('--date', default=None, action='store',
help="Day to query in format 2013-12-05. Default is yesterday"),)
def add_arguments(self, parser):
# type: (CommandParser) -> None
parser.add_argument('--date', default=None, action='store',
help="Day to query in format 2013-12-05. Default is yesterday")
def handle(self, *args, **options):
# type: (*Any, **Any) -> None

View File

@@ -4,7 +4,7 @@ from __future__ import print_function
from typing import Any
from optparse import make_option
from django.core.management.base import BaseCommand
from django.core.management.base import BaseCommand, CommandParser
from zerver.models import Recipient, Message
from zerver.lib.timestamp import timestamp_to_datetime
import datetime
@@ -17,7 +17,7 @@ def compute_stats(log_level):
logger.setLevel(log_level)
one_week_ago = timestamp_to_datetime(time.time()) - datetime.timedelta(weeks=1)
mit_query = Message.objects.filter(sender__realm__domain="mit.edu",
mit_query = Message.objects.filter(sender__realm__string_id="mit",
recipient__type=Recipient.STREAM,
pub_date__gt=one_week_ago)
for bot_sender_start in ["imap.", "rcmd.", "sys."]:
@@ -53,7 +53,7 @@ def compute_stats(log_level):
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. /
total_user_counts[email], 1)
total_user_counts[email], 1)
for size in top_percents.keys():
top_percents.setdefault(size, 0)
if i < size:
@@ -73,11 +73,12 @@ def compute_stats(log_level):
logging.info("%15s | %s%%" % (client, round(100. * total_counts[client] / grand_total, 1)))
class Command(BaseCommand):
option_list = BaseCommand.option_list + \
(make_option('--verbose', default=False, action='store_true'),)
help = "Compute statistics on MIT Zephyr usage."
def add_arguments(self, parser):
# type: (CommandParser) -> None
parser.add_argument('--verbose', default=False, action='store_true')
def handle(self, *args, **options):
# type: (*Any, **Any) -> None
level = logging.INFO

View File

@@ -7,7 +7,7 @@ from typing import Any, Dict
from zerver.lib.statistics import seconds_usage_between
from optparse import make_option
from django.core.management.base import BaseCommand
from django.core.management.base import BaseCommand, CommandParser
from zerver.models import UserProfile
import datetime
from django.utils.timezone import utc
@@ -19,7 +19,7 @@ def analyze_activity(options):
user_profile_query = UserProfile.objects.all()
if options["realm"]:
user_profile_query = user_profile_query.filter(realm__domain=options["realm"])
user_profile_query = user_profile_query.filter(realm__string_id=options["realm"])
print("Per-user online duration:\n")
total_duration = datetime.timedelta(0)
@@ -47,17 +47,17 @@ 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: ./manage.py analyze_user_activity [--realm=zulip] [--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"""
option_list = BaseCommand.option_list + (
make_option('--realm', action='store'),
make_option('--date', action='store', default="2013-09-06"),
make_option('--duration', action='store', default=1, type=int,
help="How many days to show usage information for"),
)
def add_arguments(self, parser):
# type: (CommandParser) -> None
parser.add_argument('--realm', action='store')
parser.add_argument('--date', action='store', default="2013-09-06")
parser.add_argument('--duration', action='store', default=1, type=int,
help="How many days to show usage information for")
def handle(self, *args, **options):
# type: (*Any, **Any) -> None

View File

@@ -0,0 +1,29 @@
from __future__ import absolute_import
from __future__ import print_function
import sys
from argparse import ArgumentParser
from django.db import connection
from django.core.management.base import BaseCommand
from analytics.lib.counts import do_drop_all_analytics_tables
from typing import Any
class Command(BaseCommand):
help = """Clear analytics tables."""
def add_arguments(self, parser):
# type: (ArgumentParser) -> None
parser.add_argument('--force',
action='store_true',
help="Clear analytics tables.")
def handle(self, *args, **options):
# type: (*Any, **Any) -> None
if options['force']:
do_drop_all_analytics_tables()
else:
print("Would delete all data from analytics tables (!); use --force to do so.")
sys.exit(1)

View File

@@ -17,9 +17,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"""
./manage.py client_activity
./manage.py client_activity zulip
./manage.py client_activity hamlet@zulip.com"""
def add_arguments(self, parser):
# type: (ArgumentParser) -> None
@@ -57,7 +57,6 @@ python manage.py client_activity jesstess@zulip.com"""
print("%25s %15d" % (count[1], count[0]))
print("Total:", total)
def handle(self, *args, **options):
# type: (*Any, **str) -> None
if options['arg'] is None:
@@ -69,13 +68,13 @@ python manage.py client_activity jesstess@zulip.com"""
# Report activity for a user.
user_profile = get_user_profile_by_email(arg)
self.compute_activity(UserActivity.objects.filter(
user_profile=user_profile))
user_profile=user_profile))
except UserProfile.DoesNotExist:
try:
# Report activity for a realm.
realm = get_realm(arg)
self.compute_activity(UserActivity.objects.filter(
user_profile__realm=realm))
user_profile__realm=realm))
except Realm.DoesNotExist:
print("Unknown user or domain %s" % (arg,))
print("Unknown user or realm %s" % (arg,))
exit(1)

View File

@@ -0,0 +1,123 @@
from __future__ import absolute_import, print_function
from argparse import ArgumentParser
from django.core.management.base import BaseCommand
from django.utils import timezone
from analytics.models import BaseCount, InstallationCount, RealmCount, \
UserCount, StreamCount
from analytics.lib.counts import COUNT_STATS, CountStat, do_drop_all_analytics_tables
from analytics.lib.fixtures import generate_time_series_data
from analytics.lib.time_utils import time_range
from zerver.lib.timestamp import floor_to_day
from zerver.models import Realm, UserProfile, Stream, Message, Client
from datetime import datetime, timedelta
from six.moves import zip
from typing import Any, List, Optional, Text, Type, Union
class Command(BaseCommand):
help = """Populates analytics tables with randomly generated data."""
DAYS_OF_DATA = 100
random_seed = 26
def create_user(self, email, full_name, is_staff, date_joined, realm):
# type: (Text, Text, Text, bool, datetime, Realm) -> UserProfile
return UserProfile.objects.create(
email=email, full_name=full_name, is_staff=is_staff,
realm=realm, short_name=full_name, pointer=-1, last_pointer_updater='none',
api_key='42', date_joined=date_joined)
def generate_fixture_data(self, stat, business_hours_base, non_business_hours_base,
growth, autocorrelation, spikiness, holiday_rate=0):
# type: (CountStat, float, float, float, float, float, float) -> List[int]
self.random_seed += 1
return generate_time_series_data(
days=self.DAYS_OF_DATA, business_hours_base=business_hours_base,
non_business_hours_base=non_business_hours_base, growth=growth,
autocorrelation=autocorrelation, spikiness=spikiness, holiday_rate=holiday_rate,
frequency=stat.frequency, is_gauge=(stat.interval == CountStat.GAUGE),
random_seed=self.random_seed)
def handle(self, *args, **options):
# type: (*Any, **Any) -> None
do_drop_all_analytics_tables()
# I believe this also deletes any objects with this realm as a foreign key
Realm.objects.filter(string_id='analytics').delete()
Client.objects.filter(name__endswith='_').delete()
installation_time = timezone.now() - timedelta(days=self.DAYS_OF_DATA)
last_end_time = floor_to_day(timezone.now())
realm = Realm.objects.create(
string_id='analytics', name='Analytics', domain='analytics.ds',
date_created=installation_time)
shylock = self.create_user('shylock@analytics.ds', 'Shylock', True, installation_time, realm)
def insert_fixture_data(stat, fixture_data, table):
# type: (CountStat, Dict[Optional[str], List[int]], Type[BaseCount]) -> None
end_times = time_range(last_end_time, last_end_time, stat.frequency,
len(list(fixture_data.values())[0]))
if table == RealmCount:
id_args = {'realm': realm}
if table == UserCount:
id_args = {'realm': realm, 'user': shylock}
for subgroup, values in fixture_data.items():
table.objects.bulk_create([
table(property=stat.property, subgroup=subgroup, end_time=end_time,
value=value, **id_args)
for end_time, value in zip(end_times, values) if value != 0])
stat = COUNT_STATS['active_users:is_bot:day']
realm_data = {
'false': self.generate_fixture_data(stat, .1, .03, 3, .5, 3),
'true': self.generate_fixture_data(stat, .01, 0, 1, 0, 1)
} # type: Dict[Optional[str], List[int]]
insert_fixture_data(stat, realm_data, RealmCount)
stat = COUNT_STATS['messages_sent:is_bot:hour']
user_data = {'false': self.generate_fixture_data(stat, 2, 1, 1.5, .6, 8, holiday_rate=.1)}
insert_fixture_data(stat, user_data, UserCount)
realm_data = {'false': self.generate_fixture_data(stat, 35, 15, 6, .6, 4),
'true': self.generate_fixture_data(stat, 15, 15, 3, .4, 2)}
insert_fixture_data(stat, realm_data, RealmCount)
stat = COUNT_STATS['messages_sent:message_type:day']
user_data = {
'public_stream': self.generate_fixture_data(stat, 1.5, 1, 3, .6, 8),
'private_message': self.generate_fixture_data(stat, .5, .3, 1, .6, 8)}
insert_fixture_data(stat, user_data, UserCount)
realm_data = {
'public_stream': self.generate_fixture_data(stat, 30, 8, 5, .6, 4),
'private_stream': self.generate_fixture_data(stat, 7, 7, 5, .6, 4),
'private_message': self.generate_fixture_data(stat, 13, 5, 5, .6, 4)}
insert_fixture_data(stat, realm_data, RealmCount)
website_ = Client.objects.create(name='website_')
API_ = Client.objects.create(name='API_')
android_ = Client.objects.create(name='android_')
iOS_ = Client.objects.create(name='iOS_')
react_native_ = Client.objects.create(name='react_native_')
electron_ = Client.objects.create(name='electron_')
barnowl_ = Client.objects.create(name='barnowl_')
plan9_ = Client.objects.create(name='plan9_')
stat = COUNT_STATS['messages_sent:client:day']
user_data = {
website_.id: self.generate_fixture_data(stat, 2, 1, 1.5, .6, 8),
barnowl_.id: self.generate_fixture_data(stat, 0, .3, 1.5, .6, 8)}
insert_fixture_data(stat, user_data, UserCount)
realm_data = {
website_.id: self.generate_fixture_data(stat, 30, 20, 5, .6, 3),
API_.id: self.generate_fixture_data(stat, 5, 5, 5, .6, 3),
android_.id: self.generate_fixture_data(stat, 5, 5, 2, .6, 3),
iOS_.id: self.generate_fixture_data(stat, 5, 5, 2, .6, 3),
react_native_.id: self.generate_fixture_data(stat, 5, 5, 10, .6, 3),
electron_.id: self.generate_fixture_data(stat, 5, 3, 8, .6, 3),
barnowl_.id: self.generate_fixture_data(stat, 1, 1, 3, .6, 3),
plan9_.id: self.generate_fixture_data(stat, 0, 0, 0, 0, 0, 0)}
insert_fixture_data(stat, realm_data, RealmCount)
# TODO: messages_sent_to_stream:is_bot

View File

@@ -30,12 +30,12 @@ class Command(BaseCommand):
# type: (Realm) -> List[UserProfile]
# Has been active (on the website, for now) in the last 7 days.
activity_cutoff = datetime.datetime.now(tz=pytz.utc) - datetime.timedelta(days=7)
return [activity.user_profile for activity in \
UserActivity.objects.filter(user_profile__realm=realm,
user_profile__is_active=True,
last_visit__gt=activity_cutoff,
query="/json/users/me/pointer",
client__name="website")]
return [activity.user_profile for activity in (
UserActivity.objects.filter(user_profile__realm=realm,
user_profile__is_active=True,
last_visit__gt=activity_cutoff,
query="/json/users/me/pointer",
client__name="website"))]
def messages_sent_by(self, user, days_ago):
# type: (UserProfile, int) -> int
@@ -86,7 +86,7 @@ class Command(BaseCommand):
# type: (*Any, **Any) -> None
if options['realms']:
try:
realms = [get_realm(domain) for domain in options['realms']]
realms = [get_realm(string_id) for string_id in options['realms']]
except Realm.DoesNotExist as e:
print(e)
exit(1)
@@ -94,7 +94,7 @@ class Command(BaseCommand):
realms = Realm.objects.all()
for realm in realms:
print(realm.domain)
print(realm.string_id)
user_profiles = UserProfile.objects.filter(realm=realm, is_active=True)
active_users = self.active_users(realm)
@@ -121,7 +121,7 @@ class Command(BaseCommand):
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([x for x in active_users if x.enable_desktop_notifications == True])
num_notifications_enabled = len([x for x in active_users if x.enable_desktop_notifications])
self.report_percentage(num_notifications_enabled, num_active,
"active users have desktop notifications enabled")

View File

@@ -20,7 +20,7 @@ class Command(BaseCommand):
# type: (*Any, **str) -> None
if options['realms']:
try:
realms = [get_realm(domain) for domain in options['realms']]
realms = [get_realm(string_id) for string_id in options['realms']]
except Realm.DoesNotExist as e:
print(e)
exit(1)
@@ -28,7 +28,7 @@ class Command(BaseCommand):
realms = Realm.objects.all()
for realm in realms:
print(realm.domain)
print(realm.string_id)
print("------------")
print("%25s %15s %10s" % ("stream", "subscribers", "messages"))
streams = Stream.objects.filter(realm=realm).exclude(Q(name__istartswith="tutorial-"))

View File

@@ -0,0 +1,75 @@
from __future__ import absolute_import
from __future__ import print_function
import os
import sys
from scripts.lib.zulip_tools import ENDC, WARNING
from argparse import ArgumentParser
from datetime import timedelta
from django.core.management.base import BaseCommand
from django.utils import timezone
from django.utils.dateparse import parse_datetime
from django.conf import settings
from analytics.models import RealmCount, UserCount
from analytics.lib.counts import COUNT_STATS, logger, process_count_stat
from zerver.lib.timestamp import datetime_to_string, is_timezone_aware
from zerver.models import UserProfile, Message
from typing import Any
class Command(BaseCommand):
help = """Fills Analytics tables.
Run as a cron job that runs every hour."""
def add_arguments(self, parser):
# type: (ArgumentParser) -> None
parser.add_argument('--time', '-t',
type=str,
help='Update stat tables from current state to --time. Defaults to the current time.',
default=datetime_to_string(timezone.now()))
parser.add_argument('--utc',
type=bool,
help="Interpret --time in UTC.",
default=False)
parser.add_argument('--stat', '-s',
type=str,
help="CountStat to process. If omitted, all stats are processed.")
parser.add_argument('--quiet', '-q',
type=str,
help="Suppress output to stdout.")
def handle(self, *args, **options):
# type: (*Any, **Any) -> None
try:
os.mkdir(settings.ANALYTICS_LOCK_DIR)
except OSError:
print(WARNING + "Analytics lock %s is unavailable; exiting... " + ENDC)
return
try:
self.run_update_analytics_counts(options)
finally:
os.rmdir(settings.ANALYTICS_LOCK_DIR)
def run_update_analytics_counts(self, options):
# type: (Dict[str, Any]) -> None
fill_to_time = parse_datetime(options['time'])
if options['utc']:
fill_to_time = fill_to_time.replace(tzinfo=timezone.utc)
if not (is_timezone_aware(fill_to_time)):
raise ValueError("--time must be timezone aware. Maybe you meant to use the --utc option?")
logger.info("Starting updating analytics counts through %s" % (fill_to_time,))
if options['stat'] is not None:
process_count_stat(COUNT_STATS[options['stat']], fill_to_time)
else:
for stat in COUNT_STATS.values():
process_count_stat(stat, fill_to_time)
logger.info("Finished updating analytics counts through %s" % (fill_to_time,))

View File

@@ -28,7 +28,7 @@ class Command(BaseCommand):
# type: (*Any, **Any) -> None
if options['realms']:
try:
realms = [get_realm(domain) for domain in options['realms']]
realms = [get_realm(string_id) for string_id in options['realms']]
except Realm.DoesNotExist as e:
print(e)
exit(1)
@@ -36,7 +36,7 @@ class Command(BaseCommand):
realms = Realm.objects.all()
for realm in realms:
print(realm.domain)
print(realm.string_id)
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)),))

View File

@@ -0,0 +1,113 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
import zerver.lib.str_utils
class Migration(migrations.Migration):
dependencies = [
('zerver', '0030_realm_org_type'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Anomaly',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('info', models.CharField(max_length=1000)),
],
bases=(zerver.lib.str_utils.ModelReprMixin, models.Model),
),
migrations.CreateModel(
name='HuddleCount',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('huddle', models.ForeignKey(to='zerver.Recipient')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('property', models.CharField(max_length=40)),
('end_time', models.DateTimeField()),
('interval', models.CharField(max_length=20)),
('value', models.BigIntegerField()),
('anomaly', models.ForeignKey(to='analytics.Anomaly', null=True)),
],
bases=(zerver.lib.str_utils.ModelReprMixin, models.Model),
),
migrations.CreateModel(
name='InstallationCount',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('property', models.CharField(max_length=40)),
('end_time', models.DateTimeField()),
('interval', models.CharField(max_length=20)),
('value', models.BigIntegerField()),
('anomaly', models.ForeignKey(to='analytics.Anomaly', null=True)),
],
bases=(zerver.lib.str_utils.ModelReprMixin, models.Model),
),
migrations.CreateModel(
name='RealmCount',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('realm', models.ForeignKey(to='zerver.Realm')),
('property', models.CharField(max_length=40)),
('end_time', models.DateTimeField()),
('interval', models.CharField(max_length=20)),
('value', models.BigIntegerField()),
('anomaly', models.ForeignKey(to='analytics.Anomaly', null=True)),
],
bases=(zerver.lib.str_utils.ModelReprMixin, models.Model),
),
migrations.CreateModel(
name='StreamCount',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('realm', models.ForeignKey(to='zerver.Realm')),
('stream', models.ForeignKey(to='zerver.Stream')),
('property', models.CharField(max_length=40)),
('end_time', models.DateTimeField()),
('interval', models.CharField(max_length=20)),
('value', models.BigIntegerField()),
('anomaly', models.ForeignKey(to='analytics.Anomaly', null=True)),
],
bases=(zerver.lib.str_utils.ModelReprMixin, models.Model),
),
migrations.CreateModel(
name='UserCount',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('realm', models.ForeignKey(to='zerver.Realm')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('property', models.CharField(max_length=40)),
('end_time', models.DateTimeField()),
('interval', models.CharField(max_length=20)),
('value', models.BigIntegerField()),
('anomaly', models.ForeignKey(to='analytics.Anomaly', null=True)),
],
bases=(zerver.lib.str_utils.ModelReprMixin, models.Model),
),
migrations.AlterUniqueTogether(
name='usercount',
unique_together=set([('user', 'property', 'end_time', 'interval')]),
),
migrations.AlterUniqueTogether(
name='streamcount',
unique_together=set([('stream', 'property', 'end_time', 'interval')]),
),
migrations.AlterUniqueTogether(
name='realmcount',
unique_together=set([('realm', 'property', 'end_time', 'interval')]),
),
migrations.AlterUniqueTogether(
name='installationcount',
unique_together=set([('property', 'end_time', 'interval')]),
),
migrations.AlterUniqueTogether(
name='huddlecount',
unique_together=set([('huddle', 'property', 'end_time', 'interval')]),
),
]

View File

@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('analytics', '0001_initial'),
]
operations = [
migrations.AlterUniqueTogether(
name='huddlecount',
unique_together=set([]),
),
migrations.RemoveField(
model_name='huddlecount',
name='anomaly',
),
migrations.RemoveField(
model_name='huddlecount',
name='huddle',
),
migrations.RemoveField(
model_name='huddlecount',
name='user',
),
migrations.DeleteModel(
name='HuddleCount',
),
]

View File

@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
import zerver.lib.str_utils
class Migration(migrations.Migration):
dependencies = [
('analytics', '0002_remove_huddlecount'),
]
operations = [
migrations.CreateModel(
name='FillState',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('property', models.CharField(unique=True, max_length=40)),
('end_time', models.DateTimeField()),
('state', models.PositiveSmallIntegerField()),
('last_modified', models.DateTimeField(auto_now=True)),
],
bases=(zerver.lib.str_utils.ModelReprMixin, models.Model),
),
]

View File

@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('analytics', '0003_fillstate'),
]
operations = [
migrations.AddField(
model_name='installationcount',
name='subgroup',
field=models.CharField(max_length=16, null=True),
),
migrations.AddField(
model_name='realmcount',
name='subgroup',
field=models.CharField(max_length=16, null=True),
),
migrations.AddField(
model_name='streamcount',
name='subgroup',
field=models.CharField(max_length=16, null=True),
),
migrations.AddField(
model_name='usercount',
name='subgroup',
field=models.CharField(max_length=16, null=True),
),
]

View File

@@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('analytics', '0004_add_subgroup'),
]
operations = [
migrations.AlterField(
model_name='installationcount',
name='interval',
field=models.CharField(max_length=8),
),
migrations.AlterField(
model_name='installationcount',
name='property',
field=models.CharField(max_length=32),
),
migrations.AlterField(
model_name='realmcount',
name='interval',
field=models.CharField(max_length=8),
),
migrations.AlterField(
model_name='realmcount',
name='property',
field=models.CharField(max_length=32),
),
migrations.AlterField(
model_name='streamcount',
name='interval',
field=models.CharField(max_length=8),
),
migrations.AlterField(
model_name='streamcount',
name='property',
field=models.CharField(max_length=32),
),
migrations.AlterField(
model_name='usercount',
name='interval',
field=models.CharField(max_length=8),
),
migrations.AlterField(
model_name='usercount',
name='property',
field=models.CharField(max_length=32),
),
]

View File

@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('analytics', '0005_alter_field_size'),
]
operations = [
migrations.AlterUniqueTogether(
name='installationcount',
unique_together=set([('property', 'subgroup', 'end_time', 'interval')]),
),
migrations.AlterUniqueTogether(
name='realmcount',
unique_together=set([('realm', 'property', 'subgroup', 'end_time', 'interval')]),
),
migrations.AlterUniqueTogether(
name='streamcount',
unique_together=set([('stream', 'property', 'subgroup', 'end_time', 'interval')]),
),
migrations.AlterUniqueTogether(
name='usercount',
unique_together=set([('user', 'property', 'subgroup', 'end_time', 'interval')]),
),
]

View File

@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2017-01-16 20:50
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('analytics', '0006_add_subgroup_to_unique_constraints'),
]
operations = [
migrations.AlterUniqueTogether(
name='installationcount',
unique_together=set([('property', 'subgroup', 'end_time')]),
),
migrations.RemoveField(
model_name='installationcount',
name='interval',
),
migrations.AlterUniqueTogether(
name='realmcount',
unique_together=set([('realm', 'property', 'subgroup', 'end_time')]),
),
migrations.RemoveField(
model_name='realmcount',
name='interval',
),
migrations.AlterUniqueTogether(
name='streamcount',
unique_together=set([('stream', 'property', 'subgroup', 'end_time')]),
),
migrations.RemoveField(
model_name='streamcount',
name='interval',
),
migrations.AlterUniqueTogether(
name='usercount',
unique_together=set([('user', 'property', 'subgroup', 'end_time')]),
),
migrations.RemoveField(
model_name='usercount',
name='interval',
),
]

View File

@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.5 on 2017-02-01 22:28
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('zerver', '0050_userprofile_avatar_version'),
('analytics', '0007_remove_interval'),
]
operations = [
migrations.AlterIndexTogether(
name='realmcount',
index_together=set([('property', 'end_time')]),
),
migrations.AlterIndexTogether(
name='streamcount',
index_together=set([('property', 'realm', 'end_time')]),
),
migrations.AlterIndexTogether(
name='usercount',
index_together=set([('property', 'realm', 'end_time')]),
),
]

151
analytics/models.py Normal file
View File

@@ -0,0 +1,151 @@
from django.db import models
from django.utils import timezone
from zerver.models import Realm, UserProfile, Stream, Recipient
from zerver.lib.str_utils import ModelReprMixin
from zerver.lib.timestamp import datetime_to_UTC, floor_to_day
import datetime
from typing import Optional, Tuple, Union, Dict, Any, Text
class FillState(ModelReprMixin, models.Model):
property = models.CharField(max_length=40, unique=True) # type: Text
end_time = models.DateTimeField() # type: datetime.datetime
# Valid states are {DONE, STARTED}
DONE = 1
STARTED = 2
state = models.PositiveSmallIntegerField() # type: int
last_modified = models.DateTimeField(auto_now=True) # type: datetime.datetime
def __unicode__(self):
# type: () -> Text
return u"<FillState: %s %s %s>" % (self.property, self.end_time, self.state)
# The earliest/starting end_time in FillState
# We assume there is at least one realm
def installation_epoch():
# type: () -> datetime.datetime
earliest_realm_creation = Realm.objects.aggregate(models.Min('date_created'))['date_created__min']
return floor_to_day(datetime_to_UTC(earliest_realm_creation))
# would only ever make entries here by hand
class Anomaly(ModelReprMixin, models.Model):
info = models.CharField(max_length=1000) # type: Text
def __unicode__(self):
# type: () -> Text
return u"<Anomaly: %s... %s>" % (self.info, self.id)
class BaseCount(ModelReprMixin, models.Model):
# Note: When inheriting from BaseCount, you may want to rearrange
# the order of the columns in the migration to make sure they
# match how you'd like the table to be arranged.
property = models.CharField(max_length=32) # type: Text
subgroup = models.CharField(max_length=16, null=True) # type: Text
end_time = models.DateTimeField() # type: datetime.datetime
value = models.BigIntegerField() # type: int
anomaly = models.ForeignKey(Anomaly, null=True) # type: Optional[Anomaly]
class Meta(object):
abstract = True
@staticmethod
def extended_id():
# type: () -> Tuple[str, ...]
raise NotImplementedError
@staticmethod
def key_model():
# type: () -> models.Model
raise NotImplementedError
class InstallationCount(BaseCount):
class Meta(object):
unique_together = ("property", "subgroup", "end_time")
@staticmethod
def extended_id():
# type: () -> Tuple[str, ...]
return ()
@staticmethod
def key_model():
# type: () -> models.Model
return None
def __unicode__(self):
# type: () -> Text
return u"<InstallationCount: %s %s %s>" % (self.property, self.subgroup, self.value)
class RealmCount(BaseCount):
realm = models.ForeignKey(Realm)
class Meta(object):
unique_together = ("realm", "property", "subgroup", "end_time")
index_together = ["property", "end_time"]
@staticmethod
def extended_id():
# type: () -> Tuple[str, ...]
return ('realm_id',)
@staticmethod
def key_model():
# type: () -> models.Model
return Realm
def __unicode__(self):
# type: () -> Text
return u"<RealmCount: %s %s %s %s>" % (self.realm, self.property, self.subgroup, self.value)
class UserCount(BaseCount):
user = models.ForeignKey(UserProfile)
realm = models.ForeignKey(Realm)
class Meta(object):
unique_together = ("user", "property", "subgroup", "end_time")
# This index dramatically improves the performance of
# aggregating from users to realms
index_together = ["property", "realm", "end_time"]
@staticmethod
def extended_id():
# type: () -> Tuple[str, ...]
return ('user_id', 'realm_id')
@staticmethod
def key_model():
# type: () -> models.Model
return UserProfile
def __unicode__(self):
# type: () -> Text
return u"<UserCount: %s %s %s %s>" % (self.user, self.property, self.subgroup, self.value)
class StreamCount(BaseCount):
stream = models.ForeignKey(Stream)
realm = models.ForeignKey(Realm)
class Meta(object):
unique_together = ("stream", "property", "subgroup", "end_time")
# This index dramatically improves the performance of
# aggregating from streams to realms
index_together = ["property", "realm", "end_time"]
@staticmethod
def extended_id():
# type: () -> Tuple[str, ...]
return ('stream_id', 'realm_id')
@staticmethod
def key_model():
# type: () -> models.Model
return Stream
def __unicode__(self):
# type: () -> Text
return u"<StreamCount: %s %s %s %s %s>" % (self.stream, self.property, self.subgroup, self.value, self.id)

View File

@@ -0,0 +1,428 @@
from __future__ import absolute_import
from django.db import models
from django.test import TestCase
from django.utils import timezone
from analytics.lib.counts import CountStat, COUNT_STATS, process_count_stat, \
zerver_count_user_by_realm, zerver_count_message_by_user, \
zerver_count_message_by_stream, zerver_count_stream_by_realm, \
do_fill_count_stat_at_hour, ZerverCountQuery
from analytics.models import BaseCount, InstallationCount, RealmCount, \
UserCount, StreamCount, FillState, installation_epoch
from zerver.models import Realm, UserProfile, Message, Stream, Recipient, \
Huddle, Client, get_user_profile_by_email, get_client
from datetime import datetime, timedelta
from six.moves import range
from typing import Any, Type, Optional, Text, Tuple, List, Union
class AnalyticsTestCase(TestCase):
MINUTE = timedelta(seconds = 60)
HOUR = MINUTE * 60
DAY = HOUR * 24
TIME_ZERO = datetime(1988, 3, 14).replace(tzinfo=timezone.utc)
TIME_LAST_HOUR = TIME_ZERO - HOUR
def setUp(self):
# type: () -> None
self.default_realm = Realm.objects.create(
string_id='realmtest', name='Realm Test',
domain='test.analytics', date_created=self.TIME_ZERO - 2*self.DAY)
# used to generate unique names in self.create_*
self.name_counter = 100
# used as defaults in self.assertCountEquals
self.current_property = None # type: Optional[str]
# Lightweight creation of users, streams, and messages
def create_user(self, **kwargs):
# type: (**Any) -> UserProfile
self.name_counter += 1
defaults = {
'email': 'user%s@domain.tld' % (self.name_counter,),
'date_joined': self.TIME_LAST_HOUR,
'full_name': 'full_name',
'short_name': 'short_name',
'pointer': -1,
'last_pointer_updater': 'seems unused?',
'realm': self.default_realm,
'api_key': '42'}
for key, value in defaults.items():
kwargs[key] = kwargs.get(key, value)
return UserProfile.objects.create(**kwargs)
def create_stream_with_recipient(self, **kwargs):
# type: (**Any) -> Tuple[Stream, Recipient]
self.name_counter += 1
defaults = {'name': 'stream name %s' % (self.name_counter,),
'realm': self.default_realm,
'date_created': self.TIME_LAST_HOUR}
for key, value in defaults.items():
kwargs[key] = kwargs.get(key, value)
stream = Stream.objects.create(**kwargs)
recipient = Recipient.objects.create(type_id=stream.id, type=Recipient.STREAM)
return stream, recipient
def create_huddle_with_recipient(self, **kwargs):
# type: (**Any) -> Tuple[Huddle, Recipient]
self.name_counter += 1
defaults = {'huddle_hash': 'hash%s' % (self.name_counter,)}
for key, value in defaults.items():
kwargs[key] = kwargs.get(key, value)
huddle = Huddle.objects.create(**kwargs)
recipient = Recipient.objects.create(type_id=huddle.id, type=Recipient.HUDDLE)
return huddle, recipient
def create_message(self, sender, recipient, **kwargs):
# type: (UserProfile, Recipient, **Any) -> Message
defaults = {
'sender': sender,
'recipient': recipient,
'subject': 'subject',
'content': 'hi',
'pub_date': self.TIME_LAST_HOUR,
'sending_client': get_client("website")}
for key, value in defaults.items():
kwargs[key] = kwargs.get(key, value)
return Message.objects.create(**kwargs)
# kwargs should only ever be a UserProfile or Stream.
def assertCountEquals(self, table, value, property=None, subgroup=None,
end_time=TIME_ZERO, realm=None, **kwargs):
# type: (Type[BaseCount], int, Optional[Text], Optional[Text], datetime, Optional[Realm], **models.Model) -> None
if property is None:
property = self.current_property
queryset = table.objects.filter(property=property, end_time=end_time).filter(**kwargs)
if table is not InstallationCount:
if realm is None:
realm = self.default_realm
queryset = queryset.filter(realm=realm)
if subgroup is not None:
queryset = queryset.filter(subgroup=subgroup)
self.assertEqual(queryset.values_list('value', flat=True)[0], value)
def assertTableState(self, table, arg_keys, arg_values):
# type: (Type[BaseCount], List[str], List[List[Union[int, str, Realm, UserProfile, Stream]]]) -> None
"""Assert that the state of a *Count table is what it should be.
Example usage:
self.assertTableState(RealmCount, ['property', 'subgroup', 'realm'],
[['p1', 4], ['p2', 10, self.alt_realm]])
table -- A *Count table.
arg_keys -- List of columns of <table>.
arg_values -- List of "rows" of <table>.
Each entry of arg_values (e.g. ['p1', 4]) represents a row of <table>.
The i'th value of the entry corresponds to the i'th arg_key, so e.g.
the first arg_values entry here corresponds to a row of RealmCount
with property='p1' and subgroup=10.
Any columns not specified (in this case, every column of RealmCount
other than property and subgroup) are either set to default values,
or are ignored.
The function checks that every entry of arg_values matches exactly one
row of <table>, and that no additional rows exist. Note that this means
checking a table with duplicate rows is not supported.
"""
defaults = {
'property': self.current_property,
'subgroup': None,
'end_time': self.TIME_ZERO}
for values in arg_values:
kwargs = {} # type: Dict[str, Any]
for i in range(len(values)):
kwargs[arg_keys[i]] = values[i]
for key, value in defaults.items():
kwargs[key] = kwargs.get(key, value)
if table is not InstallationCount:
if 'realm' not in kwargs:
if 'user' in kwargs:
kwargs['realm'] = kwargs['user'].realm
elif 'stream' in kwargs:
kwargs['realm'] = kwargs['stream'].realm
else:
kwargs['realm'] = self.default_realm
self.assertEqual(table.objects.filter(**kwargs).count(), 1)
self.assertEqual(table.objects.count(), len(arg_values))
class TestProcessCountStat(AnalyticsTestCase):
def make_dummy_count_stat(self, current_time):
# type: (datetime) -> CountStat
dummy_query = """INSERT INTO analytics_realmcount (realm_id, property, end_time, value)
VALUES (1, 'test stat', '%(end_time)s', 22)""" % {'end_time': current_time}
count_stat = CountStat('test stat', ZerverCountQuery(Recipient, UserCount, dummy_query),
{}, None, CountStat.HOUR, False)
return count_stat
def assertFillStateEquals(self, end_time, state = FillState.DONE, property = None):
# type: (datetime, int, Optional[Text]) -> None
count_stat = self.make_dummy_count_stat(end_time)
if property is None:
property = count_stat.property
fill_state = FillState.objects.filter(property=property).first()
self.assertEqual(fill_state.end_time, end_time)
self.assertEqual(fill_state.state, state)
def test_process_stat(self):
# type: () -> None
# process new stat
current_time = installation_epoch() + self.HOUR
count_stat = self.make_dummy_count_stat(current_time)
property = count_stat.property
process_count_stat(count_stat, current_time)
self.assertFillStateEquals(current_time)
self.assertEqual(InstallationCount.objects.filter(property=property).count(), 1)
# dirty stat
FillState.objects.filter(property=property).update(state=FillState.STARTED)
process_count_stat(count_stat, current_time)
self.assertFillStateEquals(current_time)
self.assertEqual(InstallationCount.objects.filter(property=property).count(), 1)
# clean stat, no update
process_count_stat(count_stat, current_time)
self.assertFillStateEquals(current_time)
self.assertEqual(InstallationCount.objects.filter(property=property).count(), 1)
# clean stat, with update
current_time = current_time + self.HOUR
count_stat = self.make_dummy_count_stat(current_time)
process_count_stat(count_stat, current_time)
self.assertFillStateEquals(current_time)
self.assertEqual(InstallationCount.objects.filter(property=property).count(), 2)
class TestCountStats(AnalyticsTestCase):
def setUp(self):
# type: () -> None
super(TestCountStats, self).setUp()
# This tests two things for each of the queries/CountStats: Handling
# more than 1 realm, and the time bounds (time_start and time_end in
# the queries).
self.second_realm = Realm.objects.create(
string_id='second-realm', name='Second Realm',
domain='second.analytics', date_created=self.TIME_ZERO-2*self.DAY)
for minutes_ago in [0, 1, 61, 60*24+1]:
creation_time = self.TIME_ZERO - minutes_ago*self.MINUTE
user = self.create_user(email='user-%s@second.analytics' % (minutes_ago,),
realm=self.second_realm, date_joined=creation_time)
recipient = self.create_stream_with_recipient(
name='stream %s' % (minutes_ago,), realm=self.second_realm,
date_created=creation_time)[1]
self.create_message(user, recipient, pub_date=creation_time)
self.hourly_user = UserProfile.objects.get(email='user-1@second.analytics')
self.daily_user = UserProfile.objects.get(email='user-61@second.analytics')
# This realm should not show up in the *Count tables for any of the
# messages_* CountStats
self.no_message_realm = Realm.objects.create(
string_id='no-message-realm', name='No Message Realm',
domain='no.message', date_created=self.TIME_ZERO-2*self.DAY)
self.create_user(realm=self.no_message_realm)
self.create_stream_with_recipient(realm=self.no_message_realm)
# This huddle should not show up anywhere
self.create_huddle_with_recipient()
def test_active_users_by_is_bot(self):
# type: () -> None
stat = COUNT_STATS['active_users:is_bot:day']
self.current_property = stat.property
# To be included
self.create_user(is_bot=True)
self.create_user(is_bot=True, date_joined=self.TIME_ZERO-25*self.HOUR)
self.create_user(is_bot=False)
# To be excluded
self.create_user(is_active=False)
do_fill_count_stat_at_hour(stat, self.TIME_ZERO)
self.assertTableState(RealmCount, ['value', 'subgroup', 'realm'],
[[2, 'true'], [1, 'false'],
[3, 'false', self.second_realm],
[1, 'false', self.no_message_realm]])
self.assertTableState(InstallationCount, ['value', 'subgroup'], [[2, 'true'], [5, 'false']])
self.assertTableState(UserCount, [], [])
self.assertTableState(StreamCount, [], [])
def test_messages_sent_by_is_bot(self):
# type: () -> None
stat = COUNT_STATS['messages_sent:is_bot:hour']
self.current_property = stat.property
bot = self.create_user(is_bot=True)
human1 = self.create_user()
human2 = self.create_user()
recipient_human1 = Recipient.objects.create(type_id=human1.id, type=Recipient.PERSONAL)
recipient_stream = self.create_stream_with_recipient()[1]
recipient_huddle = self.create_huddle_with_recipient()[1]
self.create_message(bot, recipient_human1)
self.create_message(bot, recipient_stream)
self.create_message(bot, recipient_huddle)
self.create_message(human1, recipient_human1)
self.create_message(human2, recipient_human1)
do_fill_count_stat_at_hour(stat, self.TIME_ZERO)
self.assertTableState(UserCount, ['value', 'subgroup', 'user'],
[[1, 'false', human1], [1, 'false', human2], [3, 'true', bot],
[1, 'false', self.hourly_user]])
self.assertTableState(RealmCount, ['value', 'subgroup', 'realm'],
[[2, 'false'], [3, 'true'], [1, 'false', self.second_realm]])
self.assertTableState(InstallationCount, ['value', 'subgroup'], [[3, 'false'], [3, 'true']])
self.assertTableState(StreamCount, [], [])
def test_messages_sent_by_message_type(self):
# type: () -> None
stat = COUNT_STATS['messages_sent:message_type:day']
self.current_property = stat.property
# Nothing currently in this stat that is bot related, but so many of
# the rest of our stats make the human/bot distinction that one can
# imagine a later refactoring that will intentionally or
# unintentionally change this. So make one of our users a bot.
user1 = self.create_user(is_bot=True)
user2 = self.create_user()
user3 = self.create_user()
# private streams
recipient_stream1 = self.create_stream_with_recipient(invite_only=True)[1]
recipient_stream2 = self.create_stream_with_recipient(invite_only=True)[1]
self.create_message(user1, recipient_stream1)
self.create_message(user2, recipient_stream1)
self.create_message(user2, recipient_stream2)
# public streams
recipient_stream3 = self.create_stream_with_recipient()[1]
recipient_stream4 = self.create_stream_with_recipient()[1]
self.create_message(user1, recipient_stream3)
self.create_message(user1, recipient_stream4)
self.create_message(user2, recipient_stream3)
# huddles
recipient_huddle1 = self.create_huddle_with_recipient()[1]
recipient_huddle2 = self.create_huddle_with_recipient()[1]
self.create_message(user1, recipient_huddle1)
self.create_message(user2, recipient_huddle2)
# private messages
recipient_user1 = Recipient.objects.create(type_id=user1.id, type=Recipient.PERSONAL)
recipient_user2 = Recipient.objects.create(type_id=user2.id, type=Recipient.PERSONAL)
recipient_user3 = Recipient.objects.create(type_id=user3.id, type=Recipient.PERSONAL)
self.create_message(user1, recipient_user2)
self.create_message(user2, recipient_user1)
self.create_message(user3, recipient_user3)
do_fill_count_stat_at_hour(stat, self.TIME_ZERO)
self.assertTableState(UserCount, ['value', 'subgroup', 'user'],
[[1, 'private_stream', user1],
[2, 'private_stream', user2],
[2, 'public_stream', user1],
[1, 'public_stream', user2],
[2, 'private_message', user1],
[2, 'private_message', user2],
[1, 'private_message', user3],
[1, 'public_stream', self.hourly_user],
[1, 'public_stream', self.daily_user]])
self.assertTableState(RealmCount, ['value', 'subgroup', 'realm'],
[[3, 'private_stream'], [3, 'public_stream'], [5, 'private_message'],
[2, 'public_stream', self.second_realm]])
self.assertTableState(InstallationCount, ['value', 'subgroup'],
[[3, 'private_stream'], [5, 'public_stream'], [5, 'private_message']])
self.assertTableState(StreamCount, [], [])
def test_messages_sent_to_recipients_with_same_id(self):
# type: () -> None
stat = COUNT_STATS['messages_sent:message_type:day']
self.current_property = stat.property
user = self.create_user(id=1000)
user_recipient = Recipient.objects.create(type_id=user.id, type=Recipient.PERSONAL)
stream_recipient = self.create_stream_with_recipient(id=1000)[1]
huddle_recipient = self.create_huddle_with_recipient(id=1000)[1]
self.create_message(user, user_recipient)
self.create_message(user, stream_recipient)
self.create_message(user, huddle_recipient)
do_fill_count_stat_at_hour(stat, self.TIME_ZERO)
self.assertCountEquals(UserCount, 2, subgroup='private_message')
self.assertCountEquals(UserCount, 1, subgroup='public_stream')
def test_messages_sent_by_client(self):
# type: () -> None
stat = COUNT_STATS['messages_sent:client:day']
self.current_property = stat.property
user1 = self.create_user(is_bot=True)
user2 = self.create_user()
recipient_user2 = Recipient.objects.create(type_id=user2.id, type=Recipient.PERSONAL)
recipient_stream = self.create_stream_with_recipient()[1]
recipient_huddle = self.create_huddle_with_recipient()[1]
client2 = Client.objects.create(name='client2')
self.create_message(user1, recipient_user2, sending_client=client2)
self.create_message(user1, recipient_stream)
self.create_message(user1, recipient_huddle)
self.create_message(user2, recipient_user2, sending_client=client2)
self.create_message(user2, recipient_user2, sending_client=client2)
do_fill_count_stat_at_hour(stat, self.TIME_ZERO)
client2_id = str(client2.id)
website_client_id = str(get_client('website').id) # default for self.create_message
self.assertTableState(UserCount, ['value', 'subgroup', 'user'],
[[2, website_client_id, user1],
[1, client2_id, user1], [2, client2_id, user2],
[1, website_client_id, self.hourly_user],
[1, website_client_id, self.daily_user]])
self.assertTableState(RealmCount, ['value', 'subgroup', 'realm'],
[[2, website_client_id], [3, client2_id],
[2, website_client_id, self.second_realm]])
self.assertTableState(InstallationCount, ['value', 'subgroup'],
[[4, website_client_id], [3, client2_id]])
self.assertTableState(StreamCount, [], [])
def test_messages_sent_to_stream_by_is_bot(self):
# type: () -> None
stat = COUNT_STATS['messages_sent_to_stream:is_bot:hour']
self.current_property = stat.property
bot = self.create_user(is_bot=True)
human1 = self.create_user()
human2 = self.create_user()
recipient_human1 = Recipient.objects.create(type_id=human1.id, type=Recipient.PERSONAL)
stream1, recipient_stream1 = self.create_stream_with_recipient()
stream2, recipient_stream2 = self.create_stream_with_recipient()
# To be included
self.create_message(human1, recipient_stream1)
self.create_message(human2, recipient_stream1)
self.create_message(human1, recipient_stream2)
self.create_message(bot, recipient_stream2)
self.create_message(bot, recipient_stream2)
# To be excluded
self.create_message(human2, recipient_human1)
self.create_message(bot, recipient_human1)
recipient_huddle = self.create_huddle_with_recipient()[1]
self.create_message(human1, recipient_huddle)
do_fill_count_stat_at_hour(stat, self.TIME_ZERO)
self.assertTableState(StreamCount, ['value', 'subgroup', 'stream'],
[[2, 'false', stream1], [1, 'false', stream2], [2, 'true', stream2],
# "hourly" stream, from TestCountStats.setUp
[1, 'false', Stream.objects.get(name='stream 1')]])
self.assertTableState(RealmCount, ['value', 'subgroup', 'realm'],
[[3, 'false'], [2, 'true'], [1, 'false', self.second_realm]])
self.assertTableState(InstallationCount, ['value', 'subgroup'], [[4, 'false'], [2, 'true']])
self.assertTableState(UserCount, [], [])

View File

@@ -0,0 +1,62 @@
from django.utils.timezone import get_fixed_timezone
from zerver.lib.test_classes import ZulipTestCase
from analytics.lib.counts import CountStat
from analytics.lib.time_utils import time_range
from analytics.views import rewrite_client_arrays
from datetime import datetime, timedelta
class TestTimeRange(ZulipTestCase):
def test_time_range(self):
# type: () -> None
HOUR = timedelta(hours=1)
DAY = timedelta(days=1)
TZINFO = get_fixed_timezone(-100) # 100 minutes west of UTC
# Using 22:59 so that converting to UTC and applying floor_to_{hour,day} do not commute
a_time = datetime(2016, 3, 14, 22, 59).replace(tzinfo=TZINFO)
floor_hour = datetime(2016, 3, 14, 22).replace(tzinfo=TZINFO)
floor_day = datetime(2016, 3, 14).replace(tzinfo=TZINFO)
# test start == end
self.assertEqual(time_range(a_time, a_time, CountStat.HOUR, None), [])
self.assertEqual(time_range(a_time, a_time, CountStat.DAY, None), [])
# test start == end == boundary, and min_length == 0
self.assertEqual(time_range(floor_hour, floor_hour, CountStat.HOUR, 0), [floor_hour])
self.assertEqual(time_range(floor_day, floor_day, CountStat.DAY, 0), [floor_day])
# test start and end on different boundaries
self.assertEqual(time_range(floor_hour, floor_hour+HOUR, CountStat.HOUR, None),
[floor_hour, floor_hour+HOUR])
self.assertEqual(time_range(floor_day, floor_day+DAY, CountStat.DAY, None),
[floor_day, floor_day+DAY])
# test min_length
self.assertEqual(time_range(floor_hour, floor_hour+HOUR, CountStat.HOUR, 4),
[floor_hour-2*HOUR, floor_hour-HOUR, floor_hour, floor_hour+HOUR])
self.assertEqual(time_range(floor_day, floor_day+DAY, CountStat.DAY, 4),
[floor_day-2*DAY, floor_day-DAY, floor_day, floor_day+DAY])
class TestMapArrays(ZulipTestCase):
def test_map_arrays(self):
# type: () -> None
a = {'desktop app 1.0': [1, 2, 3],
'desktop app 2.0': [10, 12, 13],
'desktop app 3.0': [21, 22, 23],
'website': [1, 2, 3],
'ZulipiOS': [1, 2, 3],
'ZulipMobile': [1, 5, 7],
'ZulipPython': [1, 2, 3],
'API: Python': [1, 2, 3],
'SomethingRandom': [4, 5, 6],
'ZulipGitHubWebhook': [7, 7, 9],
'ZulipAndroid': [64, 63, 65]}
result = rewrite_client_arrays(a)
self.assertEqual(result,
{'Old desktop app': [32, 36, 39],
'Old iOS app': [1, 2, 3],
'New iOS app': [1, 5, 7],
'Website': [1, 2, 3],
'Python API': [2, 4, 6],
'SomethingRandom': [4, 5, 6],
'GitHub webhook': [7, 7, 9],
'Android app': [64, 63, 65]})

View File

@@ -1,9 +1,39 @@
from django.conf.urls import patterns, url
from django.conf.urls import url, include
from zerver.lib.rest import rest_dispatch
import analytics.views
i18n_urlpatterns = [
url(r'^activity$', 'analytics.views.get_activity'),
url(r'^realm_activity/(?P<realm>[\S]+)/$', 'analytics.views.get_realm_activity'),
url(r'^user_activity/(?P<email>[\S]+)/$', 'analytics.views.get_user_activity'),
# Server admin (user_profile.is_staff) visible stats pages
url(r'^activity$', analytics.views.get_activity,
name='analytics.views.get_activity'),
url(r'^realm_activity/(?P<realm_str>[\S]+)/$', analytics.views.get_realm_activity,
name='analytics.views.get_realm_activity'),
url(r'^user_activity/(?P<email>[\S]+)/$', analytics.views.get_user_activity,
name='analytics.views.get_user_activity'),
# User-visible stats page
url(r'^stats$', analytics.views.stats,
name='analytics.views.stats'),
]
urlpatterns = patterns('', *i18n_urlpatterns)
# These endpoints are a part of the API (V1), which uses:
# * REST verbs
# * Basic auth (username:password is email:apiKey)
# * Takes and returns json-formatted data
#
# See rest_dispatch in zerver.lib.rest for an explanation of auth methods used
#
# All of these paths are accessed by either a /json or /api prefix
v1_api_and_json_patterns = [
# get data for the graphs at /stats
url(r'^analytics/chart_data$', rest_dispatch,
{'GET': 'analytics.views.get_chart_data'}),
]
i18n_urlpatterns += [
url(r'^api/v1/', include(v1_api_and_json_patterns)),
url(r'^json/', include(v1_api_and_json_patterns)),
]
urlpatterns = i18n_urlpatterns

View File

@@ -1,32 +1,169 @@
from __future__ import absolute_import
from __future__ import division
from six import text_type
from typing import Any, Dict, List, Tuple, Optional, Sequence, Callable, Union
from __future__ import absolute_import, division
from django.db import connection
from django.db.models.query import QuerySet
from django.template import RequestContext, loader
from django.core import urlresolvers
from django.db import connection
from django.db.models import Sum
from django.db.models.query import QuerySet
from django.http import HttpResponseNotFound, HttpRequest, HttpResponse
from django.template import RequestContext, loader
from django.utils import timezone
from django.utils.translation import ugettext as _
from jinja2 import Markup as mark_safe
from zerver.decorator import has_request_variables, REQ, zulip_internal
from zerver.models import get_realm, UserActivity, UserActivityInterval, Realm
from zerver.lib.timestamp import timestamp_to_datetime
from analytics.lib.counts import CountStat, process_count_stat, COUNT_STATS
from analytics.lib.time_utils import time_range
from analytics.models import BaseCount, InstallationCount, RealmCount, \
UserCount, StreamCount
from zerver.decorator import has_request_variables, REQ, zulip_internal, \
zulip_login_required, to_non_negative_int, to_utc_datetime
from zerver.lib.request import JsonableError
from zerver.lib.response import json_success
from zerver.lib.timestamp import ceiling_to_hour, ceiling_to_day, timestamp_to_datetime
from zerver.models import Realm, UserProfile, UserActivity, \
UserActivityInterval, Client
from zproject.jinja2 import render_to_response
from collections import defaultdict
from datetime import datetime, timedelta
import itertools
import time
import re
import json
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')
import re
import time
from zproject.jinja2 import render_to_response
from six.moves import filter, map, range, zip
from typing import Any, Dict, List, Tuple, Optional, Sequence, Callable, Type, \
Union, Text
@zulip_login_required
def stats(request):
# type: (HttpRequest) -> HttpResponse
return render_to_response('analytics/stats.html')
@has_request_variables
def get_chart_data(request, user_profile, chart_name=REQ(),
min_length=REQ(converter=to_non_negative_int, default=None),
start=REQ(converter=to_utc_datetime, default=None),
end=REQ(converter=to_utc_datetime, default=None)):
# type: (HttpRequest, UserProfile, Text, Optional[int], Optional[datetime], Optional[datetime]) -> HttpResponse
realm = user_profile.realm
# These are implicitly relying on realm.date_created and timezone.now being in UTC.
if start is None:
start = realm.date_created
if end is None:
end = timezone.now()
if start > end:
raise JsonableError(_("Start time is later than end time. Start: %(start)s, End: %(end)s") %
{'start': start, 'end': end})
if chart_name == 'number_of_humans':
stat = COUNT_STATS['active_users:is_bot:day']
tables = [RealmCount]
subgroups = ['false', 'true']
labels = ['human', 'bot']
include_empty_subgroups = True
elif chart_name == 'messages_sent_over_time':
stat = COUNT_STATS['messages_sent:is_bot:hour']
tables = [RealmCount]
subgroups = ['false', 'true']
labels = ['human', 'bot']
include_empty_subgroups = True
elif chart_name == 'messages_sent_by_message_type':
stat = COUNT_STATS['messages_sent:message_type:day']
tables = [RealmCount, UserCount]
subgroups = ['public_stream', 'private_stream', 'private_message']
labels = None
include_empty_subgroups = True
elif chart_name == 'messages_sent_by_client':
stat = COUNT_STATS['messages_sent:client:day']
tables = [RealmCount, UserCount]
subgroups = [str(x) for x in Client.objects.values_list('id', flat=True).order_by('id')]
labels = list(Client.objects.values_list('name', flat=True).order_by('id'))
include_empty_subgroups = False
else:
raise JsonableError(_("Unknown chart name: %s") % (chart_name,))
end_times = time_range(start, end, stat.frequency, min_length)
data = {'end_times': end_times, 'frequency': stat.frequency, 'interval': stat.interval}
for table in tables:
if table == RealmCount:
data['realm'] = get_time_series_by_subgroup(
stat, RealmCount, realm.id, end_times, subgroups, labels, include_empty_subgroups)
if table == UserCount:
data['user'] = get_time_series_by_subgroup(
stat, UserCount, user_profile.id, end_times, subgroups, labels, include_empty_subgroups)
return json_success(data=data)
def table_filtered_to_id(table, key_id):
# type: (Type[BaseCount], int) -> QuerySet
if table == RealmCount:
return RealmCount.objects.filter(realm_id=key_id)
elif table == UserCount:
return UserCount.objects.filter(user_id=key_id)
elif table == StreamCount:
return StreamCount.objects.filter(stream_id=key_id)
elif table == InstallationCount:
return InstallationCount.objects.all()
else:
raise ValueError("Unknown table: %s" % (table,))
def client_label_map(name):
# type: (str) -> str
if name == "website":
return "Website"
if name.startswith("desktop app"):
return "Old desktop app"
if name == "ZulipAndroid":
return "Android app"
if name == "ZulipiOS":
return "Old iOS app"
if name == "ZulipMobile":
return "New iOS app"
if name in ["ZulipPython", "API: Python"]:
return "Python API"
if name.startswith("Zulip") and name.endswith("Webhook"):
return name[len("Zulip"):-len("Webhook")] + " webhook"
return name
def rewrite_client_arrays(value_arrays):
# type: (Dict[str, List[int]]) -> Dict[str, List[int]]
mapped_arrays = {} # type: Dict[str, List[int]]
for label, array in value_arrays.items():
mapped_label = client_label_map(label)
if mapped_label in mapped_arrays:
for i in range(0, len(array)):
mapped_arrays[mapped_label][i] += value_arrays[label][i]
else:
mapped_arrays[mapped_label] = [value_arrays[label][i] for i in range(0, len(array))]
return mapped_arrays
def get_time_series_by_subgroup(stat, table, key_id, end_times, subgroups, labels, include_empty_subgroups):
# type: (CountStat, Type[BaseCount], Optional[int], List[datetime], List[str], Optional[List[str]], bool) -> Dict[str, List[int]]
if labels is None:
labels = subgroups
if len(subgroups) != len(labels):
raise ValueError("subgroups and labels have lengths %s and %s, which are different." %
(len(subgroups), len(labels)))
queryset = table_filtered_to_id(table, key_id).filter(property=stat.property) \
.values_list('subgroup', 'end_time', 'value')
value_dicts = defaultdict(lambda: defaultdict(int)) # type: Dict[Optional[str], Dict[datetime, int]]
for subgroup, end_time, value in queryset:
value_dicts[subgroup][end_time] = value
value_arrays = {}
for subgroup, label in zip(subgroups, labels):
if (subgroup in value_dicts) or include_empty_subgroups:
value_arrays[label] = [value_dicts[subgroup][end_time] for end_time in end_times]
if stat == COUNT_STATS['messages_sent:client:day']:
# HACK: We rewrite these arrays to collapse the Client objects
# with similar names into a single sum, and generally give
# them better names
return rewrite_client_arrays(value_arrays)
return value_arrays
eastern_tz = pytz.timezone('US/Eastern')
def make_table(title, cols, rows, has_row_class=False):
# type: (str, List[str], List[Any], bool) -> str
@@ -60,7 +197,7 @@ def get_realm_day_counts():
# type: () -> Dict[str, Dict[str, str]]
query = '''
select
r.domain,
r.string_id,
(now()::date - pub_date::date) age,
count(*) cnt
from zerver_message m
@@ -74,10 +211,10 @@ def get_realm_day_counts():
and
c.name not in ('zephyr_mirror', 'ZulipMonitoring')
group by
r.domain,
r.string_id,
age
order by
r.domain,
r.string_id,
age
'''
cursor = connection.cursor()
@@ -87,12 +224,11 @@ def get_realm_day_counts():
counts = defaultdict(dict) # type: Dict[str, Dict[int, int]]
for row in rows:
counts[row['domain']][row['age']] = row['cnt']
counts[row['string_id']][row['age']] = row['cnt']
result = {}
for domain in counts:
raw_cnts = [counts[domain].get(age, 0) for age in range(8)]
for string_id in counts:
raw_cnts = [counts[string_id].get(age, 0) for age in range(8)]
min_cnt = min(raw_cnts)
max_cnt = max(raw_cnts)
@@ -108,7 +244,7 @@ def get_realm_day_counts():
return '<td class="number %s">%s</td>' % (good_bad, cnt)
cnts = ''.join(map(format_count, raw_cnts))
result[domain] = dict(cnts=cnts)
result[string_id] = dict(cnts=cnts)
return result
@@ -116,7 +252,7 @@ def realm_summary_table(realm_minutes):
# type: (Dict[str, float]) -> str
query = '''
SELECT
realm.domain,
realm.string_id,
coalesce(user_counts.active_user_count, 0) active_user_count,
coalesce(at_risk_counts.at_risk_count, 0) at_risk_count,
(
@@ -209,7 +345,7 @@ def realm_summary_table(realm_minutes):
AND
last_visit > now() - interval '2 week'
)
ORDER BY active_user_count DESC, domain ASC
ORDER BY active_user_count DESC, string_id ASC
'''
cursor = connection.cursor()
@@ -221,26 +357,26 @@ def realm_summary_table(realm_minutes):
counts = get_realm_day_counts()
for row in rows:
try:
row['history'] = counts[row['domain']]['cnts']
except:
row['history'] = counts[row['string_id']]['cnts']
except Exception:
row['history'] = ''
# augment data with realm_minutes
total_hours = 0.0
for row in rows:
domain = row['domain']
minutes = realm_minutes.get(domain, 0.0)
string_id = row['string_id']
minutes = realm_minutes.get(string_id, 0.0)
hours = minutes / 60.0
total_hours += hours
row['hours'] = str(int(hours))
try:
row['hours_per_user'] = '%.1f' % (hours / row['active_user_count'],)
except:
except Exception:
pass
# formatting
for row in rows:
row['domain'] = realm_activity_link(row['domain'])
row['string_id'] = realm_activity_link(row['string_id'])
# Count active sites
def meets_goal(row):
@@ -260,9 +396,8 @@ def realm_summary_table(realm_minutes):
total_bot_count += int(row['bot_count'])
total_at_risk_count += int(row['at_risk_count'])
rows.append(dict(
domain='Total',
string_id='Total',
active_user_count=total_active_user_count,
user_profile_count=total_user_profile_count,
bot_count=total_bot_count,
@@ -295,20 +430,20 @@ def user_activity_intervals():
'start',
'end',
'user_profile__email',
'user_profile__realm__domain'
'user_profile__realm__string_id'
).order_by(
'user_profile__realm__domain',
'user_profile__realm__string_id',
'user_profile__email'
)
by_domain = lambda row: row.user_profile.realm.domain
by_string_id = lambda row: row.user_profile.realm.string_id
by_email = lambda row: row.user_profile.email
realm_minutes = {}
for domain, realm_intervals in itertools.groupby(all_intervals, by_domain):
for string_id, realm_intervals in itertools.groupby(all_intervals, by_string_id):
realm_duration = timedelta(0)
output += '<hr>%s\n' % (domain,)
output += '<hr>%s\n' % (string_id,)
for email, intervals in itertools.groupby(realm_intervals, by_email):
duration = timedelta(0)
for interval in intervals:
@@ -320,7 +455,7 @@ def user_activity_intervals():
realm_duration += duration
output += " %-*s%s\n" % (37, email, duration)
realm_minutes[domain] = realm_duration.total_seconds() / 60
realm_minutes[string_id] = realm_duration.total_seconds() / 60
output += "\nTotal Duration: %s\n" % (total_duration,)
output += "\nTotal Duration in minutes: %s\n" % (total_duration.total_seconds() / 60.,)
@@ -358,7 +493,7 @@ def sent_messages_report(realm):
join zerver_userprofile up on up.id = m.sender_id
join zerver_realm r on r.id = up.realm_id
where
r.domain = %s
r.string_id = %s
and
(not up.is_bot)
and
@@ -377,7 +512,7 @@ def sent_messages_report(realm):
join zerver_userprofile up on up.id = m.sender_id
join zerver_realm r on r.id = up.realm_id
where
r.domain = %s
r.string_id = %s
and
up.is_bot
and
@@ -412,7 +547,7 @@ def ad_hoc_queries():
row[i] = fixup_func(row[i])
for i, col in enumerate(cols):
if col == 'Domain':
if col == 'Realm':
fix_rows(i, realm_activity_link)
elif col in ['Last time', 'Last visit']:
fix_rows(i, format_date_for_activity_reports)
@@ -433,7 +568,7 @@ def ad_hoc_queries():
query = '''
select
realm.domain,
realm.string_id,
up.id user_id,
client.name,
sum(count) as hits,
@@ -444,13 +579,13 @@ def ad_hoc_queries():
join zerver_realm realm on realm.id = up.realm_id
where
client.name like '%s'
group by domain, up.id, client.name
group by string_id, up.id, client.name
having max(last_visit) > now() - interval '2 week'
order by domain, up.id, client.name
order by string_id, up.id, client.name
''' % (mobile_type,)
cols = [
'Domain',
'Realm',
'User id',
'Name',
'Hits',
@@ -465,7 +600,7 @@ def ad_hoc_queries():
query = '''
select
realm.domain,
realm.string_id,
client.name,
sum(count) as hits,
max(last_visit) as last_time
@@ -475,13 +610,13 @@ def ad_hoc_queries():
join zerver_realm realm on realm.id = up.realm_id
where
client.name like 'desktop%%'
group by domain, client.name
group by string_id, client.name
having max(last_visit) > now() - interval '2 week'
order by domain, client.name
order by string_id, client.name
'''
cols = [
'Domain',
'Realm',
'Client',
'Hits',
'Last time'
@@ -491,11 +626,11 @@ def ad_hoc_queries():
###
title = 'Integrations by domain'
title = 'Integrations by realm'
query = '''
select
realm.domain,
realm.string_id,
case
when query like '%%external%%' then split_part(query, '/', 5)
else client.name
@@ -513,13 +648,13 @@ def ad_hoc_queries():
)
or
query like '%%external%%'
group by domain, client_name
group by string_id, client_name
having max(last_visit) > now() - interval '2 week'
order by domain, client_name
order by string_id, client_name
'''
cols = [
'Domain',
'Realm',
'Client',
'Hits',
'Last time'
@@ -537,7 +672,7 @@ def ad_hoc_queries():
when query like '%%external%%' then split_part(query, '/', 5)
else client.name
end client_name,
realm.domain,
realm.string_id,
sum(count) as hits,
max(last_visit) as last_time
from zerver_useractivity ua
@@ -551,14 +686,14 @@ def ad_hoc_queries():
)
or
query like '%%external%%'
group by client_name, domain
group by client_name, string_id
having max(last_visit) > now() - interval '2 week'
order by client_name, domain
order by client_name, string_id
'''
cols = [
'Client',
'Domain',
'Realm',
'Hits',
'Last time'
]
@@ -600,9 +735,9 @@ def get_user_activity_records_for_realm(realm, is_bot):
]
records = UserActivity.objects.filter(
user_profile__realm__domain=realm,
user_profile__is_active=True,
user_profile__is_bot=is_bot
user_profile__realm__string_id=realm,
user_profile__is_active=True,
user_profile__is_bot=is_bot
)
records = records.order_by("user_profile__email", "-last_visit")
records = records.select_related('user_profile', 'client').only(*fields)
@@ -619,7 +754,7 @@ def get_user_activity_records_for_email(email):
]
records = UserActivity.objects.filter(
user_profile__email=email
user_profile__email=email
)
records = records.order_by("-last_visit")
records = records.select_related('user_profile', 'client').only(*fields)
@@ -637,10 +772,10 @@ def raw_user_activity_table(records):
def row(record):
# type: (QuerySet) -> List[Any]
return [
record.query,
record.client.name,
record.count,
format_date_for_activity_reports(record.last_visit)
record.query,
record.client.name,
record.count,
format_date_for_activity_reports(record.last_visit)
]
rows = list(map(row, records))
@@ -655,18 +790,19 @@ def get_user_activity_summary(records):
# `Union[Dict[str, Dict[str, int]], Dict[str, Dict[str, datetime]]]`
#: but that would require this long `Union` to carry on throughout inner functions.
summary = {} # type: Dict[str, Dict[str, Any]]
def update(action, record):
# type: (str, QuerySet) -> None
if action not in summary:
summary[action] = dict(
count=record.count,
last_visit=record.last_visit
count=record.count,
last_visit=record.last_visit
)
else:
summary[action]['count'] += record.count
summary[action]['last_visit'] = max(
summary[action]['last_visit'],
record.last_visit
summary[action]['last_visit'],
record.last_visit
)
if records:
@@ -694,7 +830,6 @@ def get_user_activity_summary(records):
update('pointer', record)
update(client, record)
return summary
def format_date_for_activity_reports(date):
@@ -711,23 +846,23 @@ def user_activity_link(email):
email_link = '<a href="%s">%s</a>' % (url, email)
return mark_safe(email_link)
def realm_activity_link(realm):
def realm_activity_link(realm_str):
# type: (str) -> mark_safe
url_name = 'analytics.views.get_realm_activity'
url = urlresolvers.reverse(url_name, kwargs=dict(realm=realm))
realm_link = '<a href="%s">%s</a>' % (url, realm)
url = urlresolvers.reverse(url_name, kwargs=dict(realm_str=realm_str))
realm_link = '<a href="%s">%s</a>' % (url, realm_str)
return mark_safe(realm_link)
def realm_client_table(user_summaries):
# type: (Dict[str, Dict[str, Dict[str, Any]]]) -> str
exclude_keys = [
'internal',
'name',
'use',
'send',
'pointer',
'website',
'desktop',
'internal',
'name',
'use',
'send',
'pointer',
'website',
'desktop',
]
rows = []
@@ -741,22 +876,22 @@ def realm_client_table(user_summaries):
count = v['count']
last_visit = v['last_visit']
row = [
format_date_for_activity_reports(last_visit),
client,
name,
email_link,
count,
format_date_for_activity_reports(last_visit),
client,
name,
email_link,
count,
]
rows.append(row)
rows = sorted(rows, key=lambda r: r[0], reverse=True)
cols = [
'Last visit',
'Client',
'Name',
'Email',
'Count',
'Last visit',
'Client',
'Name',
'Email',
'Count',
]
title = 'Clients'
@@ -773,25 +908,25 @@ def user_activity_summary_table(user_summary):
count = v['count']
last_visit = v['last_visit']
row = [
format_date_for_activity_reports(last_visit),
client,
count,
format_date_for_activity_reports(last_visit),
client,
count,
]
rows.append(row)
rows = sorted(rows, key=lambda r: r[0], reverse=True)
cols = [
'last_visit',
'client',
'count',
'last_visit',
'client',
'count',
]
title = 'User Activity'
return make_table(title, cols, rows)
def realm_user_summary_table(all_records, admin_emails):
# type: (List[QuerySet], Set[text_type]) -> Tuple[Dict[str, Dict[str, Any]], str]
# type: (List[QuerySet], Set[Text]) -> Tuple[Dict[str, Dict[str, Any]], str]
user_records = {}
def by_email(record):
@@ -817,7 +952,7 @@ def realm_user_summary_table(all_records, admin_emails):
def is_recent(val):
# type: (Optional[datetime]) -> bool
age = datetime.now(val.tzinfo) - val # type: ignore # datetie.now tzinfo bug.
age = datetime.now(val.tzinfo) - val
return age.total_seconds() < 5 * 60
rows = []
@@ -845,15 +980,15 @@ def realm_user_summary_table(all_records, admin_emails):
rows = sorted(rows, key=by_used_time, reverse=True)
cols = [
'Name',
'Email',
'Total sent',
'Heard from',
'Message sent',
'Pointer motion',
'Desktop',
'ZulipiOS',
'Android'
'Name',
'Email',
'Total sent',
'Heard from',
'Message sent',
'Pointer motion',
'Desktop',
'ZulipiOS',
'Android',
]
title = 'Summary'
@@ -862,20 +997,20 @@ def realm_user_summary_table(all_records, admin_emails):
return user_records, content
@zulip_internal
def get_realm_activity(request, realm):
def get_realm_activity(request, realm_str):
# type: (HttpRequest, str) -> HttpResponse
data = [] # type: List[Tuple[str, str]]
all_user_records = {} # type: Dict[str, Any]
try:
admins = get_realm(realm).get_admin_users()
admins = Realm.objects.get(string_id=realm_str).get_admin_users()
except Realm.DoesNotExist:
return HttpResponseNotFound("Realm %s does not exist" % (realm,))
return HttpResponseNotFound("Realm %s does not exist" % (realm_str,))
admin_emails = {admin.email for admin in admins}
for is_bot, page_title in [(False, 'Humans'), (True, 'Bots')]:
all_records = list(get_user_activity_records_for_realm(realm, is_bot))
for is_bot, page_title in [(False, 'Humans'), (True, 'Bots')]:
all_records = list(get_user_activity_records_for_realm(realm_str, is_bot))
user_records, content = realm_user_summary_table(all_records, admin_emails)
all_user_records.update(user_records)
@@ -886,17 +1021,14 @@ def get_realm_activity(request, realm):
content = realm_client_table(all_user_records)
data += [(page_title, content)]
page_title = 'History'
content = sent_messages_report(realm)
content = sent_messages_report(realm_str)
data += [(page_title, content)]
fix_name = lambda realm: realm.replace('.', '_')
realm_link = 'https://stats1.zulip.net:444/render/?from=-7days'
realm_link += '&target=stats.gauges.staging.users.active.%s.0_16hr' % (fix_name(realm),)
realm_link += '&target=stats.gauges.staging.users.active.%s.0_16hr' % (realm_str,)
title = realm
title = realm_str
return render_to_response(
'analytics/activity.html',
dict(data=data, realm_link=realm_link, title=title),

View File

@@ -1,11 +1,12 @@
#### Dependencies
The [Zulip API](https://zulip.com/api) Python bindings require the
The [Zulip API](https://zulipchat.com/api) Python bindings require the
following Python libraries:
* simplejson
* requests (version >= 0.12.1)
* simplejson
* six
* typing (version >= 3.5.2.2)
#### Installing
@@ -36,22 +37,23 @@ file is as follows:
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.
Alternatively, you may explicitly use "--user", "--api-key", and
`--site` in our examples, which is especially useful when testing. If
you are running several bots which share a home directory, we
recommend using `--config` to specify the path to the `zuliprc` file
for a specific bot.
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).
from your Zulip settings page; with current Zulip there's also a
button to download a `zuliprc` file for your account/server pair.
A typical simple bot sending API messages will look as follows:
@@ -71,6 +73,9 @@ When you want to send a message:
}
zulip_client.send_message(message)
If you are parsing arguments, you may find it useful to use Zulip's
option group; see any of our API examples for details on how to do this.
Additional examples:
client.send_message({'type': 'stream', 'content': 'Zulip rules!',
@@ -83,7 +88,14 @@ keys: msg, result. For successful calls, result will be "success" and
msg will be the empty string. On error, result will be "error" and
msg will describe what went wrong.
#### Examples
The API bindings package comes with several nice example scripts that
show how to use the APIs; they are installed as part of the API
bindings bundle.
#### Logging
The Zulip API comes with a ZulipStream class which can be used with the
logging module:
@@ -112,6 +124,7 @@ Alternatively, if you don't want to use your ~/.zuliprc file:
zulip-send --user shakespeare-bot@example.com \
--api-key a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 \
--site https://zulip.example.com \
hamlet@example.com cordelia@example.com -m \
"Conscience doth make cowards of us all."

View File

@@ -27,17 +27,23 @@ import os
import optparse
import logging
from typing import Any, Dict, List, Optional
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import zulip
logging.basicConfig()
log = logging.getLogger('zulip-send')
def do_send_message(client, message_data ):
def do_send_message(client, message_data):
# type: (zulip.Client, Dict[str, Any]) -> bool
'''Sends a message and optionally prints status about the same.'''
if message_data['type'] == 'stream':
log.info('Sending message to stream "%s", subject "%s"... ' % \
(message_data['to'], message_data['subject']))
log.info('Sending message to stream "%s", subject "%s"... ' %
(message_data['to'], message_data['subject']))
else:
log.info('Sending message to %s... ' % message_data['to'])
response = client.send_message(message_data)
@@ -49,6 +55,7 @@ def do_send_message(client, message_data ):
return False
def main(argv=None):
# type: (Optional[List[str]]) -> int
if argv is None:
argv = sys.argv
@@ -63,10 +70,6 @@ def main(argv=None):
'--user' and '--api-key' arguments.
"""
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import zulip
parser = optparse.OptionParser(usage=usage)
# Grab parser options from the API common set
@@ -77,16 +80,15 @@ def main(argv=None):
group = optparse.OptionGroup(parser, 'Stream parameters')
group.add_option('-s', '--stream',
dest='stream',
action='store',
help='Allows the user to specify a stream for the message.')
dest='stream',
action='store',
help='Allows the user to specify a stream for the message.')
group.add_option('-S', '--subject',
dest='subject',
action='store',
help='Allows the user to specify a subject for the message.')
dest='subject',
action='store',
help='Allows the user to specify a subject for the message.')
parser.add_option_group(group)
(options, recipients) = parser.parse_args(argv[1:])
if options.verbose:

View File

@@ -31,7 +31,7 @@ usage = """create-user --new-email=<email address> --new-password=<password> --n
Create a user. You must be a realm admin to use this API, and the user
will be created in your realm.
Example: create-user --site=http://localhost:9991 --user=rwbarton@zulip.com --new-email=jarthur@zulip.com --new-password=random17 --new-full-name 'J. Arthur Random' --new-short-name='jarthur'
Example: create-user --site=http://localhost:9991 --user=rwbarton@example.com --new-email=jarthur@example.com --new-password=random17 --new-full-name 'J. Arthur Random' --new-short-name='jarthur'
"""
sys.path.append(path.join(path.dirname(__file__), '..'))
@@ -48,8 +48,8 @@ parser.add_option('--new-short-name')
client = zulip.init_from_options(options)
print(client.create_user({
'email': options.new_email,
'password': options.new_password,
'full_name': options.new_full_name,
'short_name': options.new_short_name
}))
'email': options.new_email,
'password': options.new_password,
'full_name': options.new_full_name,
'short_name': options.new_short_name
}))

View File

@@ -41,7 +41,7 @@ import zulip
parser = optparse.OptionParser(usage=usage)
parser.add_option('--message-id', default="")
parser.add_option('--subject', default="")
parser.add_option('--content', default="")
parser.add_option('--content', default="")
parser.add_option_group(zulip.generate_option_group(parser))
(options, args) = parser.parse_args()

View File

@@ -26,6 +26,8 @@ import sys
import os
import optparse
from typing import Any, Dict
usage = """print-events --user=<bot's email address> --api-key=<bot's api key> [options]
Prints out certain events received by the indicated bot or user matching the filter below.
@@ -44,6 +46,7 @@ parser.add_option_group(zulip.generate_option_group(parser))
client = zulip.init_from_options(options)
def print_event(event):
# type: (Dict[str, Any]) -> None
print(event)
# This is a blocking call, and will continuously poll for new events

View File

@@ -26,6 +26,8 @@ import sys
import os
import optparse
from typing import Any, Dict
usage = """print-messages --user=<bot's email address> --api-key=<bot's api key> [options]
Prints out each message received by the indicated bot or user.
@@ -44,6 +46,7 @@ parser.add_option_group(zulip.generate_option_group(parser))
client = zulip.init_from_options(options)
def print_message(message):
# type: (Dict[str, Any]) -> None
print(message)
# This is a blocking call, and will continuously poll for new messages

View File

@@ -29,13 +29,13 @@ 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
Prints out last count messages received 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__), '..'))
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
import zulip
parser = optparse.OptionParser(usage=usage)
@@ -45,7 +45,7 @@ parser.add_option_group(zulip.generate_option_group(parser))
client = zulip.init_from_options(options)
req = {
request = {
'narrow': [["stream", "Denmark"]],
'num_before': options.count,
'num_after': 0,
@@ -53,7 +53,12 @@ req = {
'apply_markdown': False
}
old_messages = client.do_api_query(req, zulip.API_VERSTRING + 'messages', method='GET')
old_messages = client.call_endpoint(
url='messages',
method='GET',
request=request,
)
if 'messages' in old_messages:
for message in old_messages['messages']:
print(json.dumps(message, indent=4))

View File

@@ -40,7 +40,7 @@ You can omit --user and --api-key arguments if you have a properly set up ~/.zul
parser = optparse.OptionParser(usage=usage)
parser.add_option('--subject', default="test")
parser.add_option('--message', default="test message")
parser.add_option('--type', default='private')
parser.add_option('--type', default='private')
parser.add_option_group(zulip.generate_option_group(parser))
(options, args) = parser.parse_args()

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright © 2012 Zulip, Inc.
# Copyright © 2012-2017 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
@@ -22,25 +22,45 @@
# THE SOFTWARE.
from __future__ import print_function
import sys
import os
import importlib
import optparse
import sys
usage = """print-next-message --user=<bot's email address> --api-key=<bot's api key> [options]
Prints out the next message received by the user.
Example: print-next-messages --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__), '..'))
from six.moves import StringIO as _StringIO
sys.path.insert(0, './api')
from typing import IO
import zulip
class StringIO(_StringIO):
name = '' # https://github.com/python/typeshed/issues/598
usage = """upload-file --user=<user's email address> --api-key=<user's api key> [options]
Upload a file, and print the corresponding URI.
Example: upload-file --user=cordelia@zulip.com --api-key=a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --file-path=cat.png
You can omit --user and --api-key arguments if you have a properly set up ~/.zuliprc
If no --file-path is specified, a placeholder text file will be used instead.
"""
parser = optparse.OptionParser(usage=usage)
parser.add_option('--file-path')
parser.add_option_group(zulip.generate_option_group(parser))
(options, args) = parser.parse_args()
client = zulip.init_from_options(options)
print(client.get_messages({}))
file = None # type: IO
if options.file_path:
file = open(options.file_path, 'rb')
else:
file = StringIO('This is a test file.')
file.name = 'test.txt'
response = client.upload_file(file)
try:
print('File URI: {}'.format(response['uri']))
except KeyError:
print('Error! API response was: {}'.format(response))

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright © 2014 Zulip, Inc.
@@ -50,7 +49,7 @@ RESUME_FILE = "/var/tmp/zulip_asana.state"
ASANA_INITIAL_HISTORY_HOURS = 1
# Set this to your Zulip API server URI
ZULIP_SITE = "https://api.zulip.com"
ZULIP_SITE = "https://zulip.example.com"
# If properly installed, the Zulip API should be in your import
# path, but if not, set a custom path below

View File

@@ -33,18 +33,20 @@
from __future__ import print_function
import base64
from datetime import datetime, timedelta
from typing import List, Dict, Optional, Any, Tuple
import json
import logging
import os
import time
from six.moves import urllib
from six.moves.urllib import request as urllib_request
import sys
try:
import dateutil.parser
import dateutil.tz
from dateutil.tz import gettz
except ImportError as e:
print(e, file=sys.stderr)
print("Please install the python-dateutil package.", file=sys.stderr)
@@ -67,20 +69,22 @@ client = zulip.Client(email=config.ZULIP_USER, api_key=config.ZULIP_API_KEY,
site=config.ZULIP_SITE, client="ZulipAsana/" + VERSION)
def fetch_from_asana(path):
# type: (str) -> Optional[Dict[str, Any]]
"""
Request a resource through the Asana API, authenticating using
HTTP basic auth.
"""
auth = base64.encodestring('%s:' % (config.ASANA_API_KEY,))
auth = base64.encodestring(b'%s:' % (config.ASANA_API_KEY,))
headers = {"Authorization": "Basic %s" % auth}
url = "https://app.asana.com/api/1.0" + path
request = urllib.request.Request(url, None, headers)
result = urllib.request.urlopen(request)
request = urllib_request.Request(url, None, headers) # type: ignore
result = urllib_request.urlopen(request) # type: ignore
return json.load(result)
def send_zulip(topic, content):
# type: (str, str) -> Dict[str, str]
"""
Send a message to Zulip using the configured stream and bot credentials.
"""
@@ -93,11 +97,12 @@ def send_zulip(topic, content):
return client.send_message(message)
def datestring_to_datetime(datestring):
# type: (str) -> datetime
"""
Given an ISO 8601 datestring, return the corresponding datetime object.
"""
return dateutil.parser.parse(datestring).replace(
tzinfo=dateutil.tz.gettz('Z'))
tzinfo=gettz('Z'))
class TaskDict(dict):
"""
@@ -105,9 +110,11 @@ class TaskDict(dict):
object where each of the keys is an attribute for easy access.
"""
def __getattr__(self, field):
# type: (TaskDict, str) -> Any
return self.get(field)
def format_topic(task, projects):
# type: (TaskDict, Dict[str, str]) -> str
"""
Return a string that will be the Zulip message topic for this task.
"""
@@ -117,6 +124,7 @@ def format_topic(task, projects):
return "%s: %s" % (project_name, task.name)
def format_assignee(task, users):
# type: (TaskDict, Dict[str, str]) -> str
"""
Return a string describing the task's assignee.
"""
@@ -130,6 +138,7 @@ def format_assignee(task, users):
return assignee_info
def format_due_date(task):
# type: (TaskDict) -> str
"""
Return a string describing the task's due date.
"""
@@ -140,6 +149,7 @@ def format_due_date(task):
return due_date_info
def format_task_creation_event(task, projects, users):
# type: (TaskDict, Dict[str, str], Dict[str, str]) -> Tuple[str, str]
"""
Format the topic and content for a newly-created task.
"""
@@ -159,6 +169,7 @@ def format_task_creation_event(task, projects, users):
return topic, content
def format_task_completion_event(task, projects, users):
# type: (TaskDict, Dict[str, str], Dict[str, str]) -> Tuple[str, str]
"""
Format the topic and content for a completed task.
"""
@@ -174,12 +185,14 @@ def format_task_completion_event(task, projects, users):
return topic, content
def since():
# type: () -> datetime
"""
Return a newness threshold for task events to be processed.
"""
# If we have a record of the last event processed and it is recent, use it,
# else process everything from ASANA_INITIAL_HISTORY_HOURS ago.
def default_since():
# type: () -> datetime
return datetime.utcnow() - timedelta(
hours=config.ASANA_INITIAL_HISTORY_HOURS)
@@ -191,8 +204,7 @@ def since():
max_timestamp_processed = datetime.fromtimestamp(timestamp)
logging.info("Reading from resume file: " + datestring)
except (ValueError, IOError) as e:
logging.warn("Could not open resume file: %s" % (
e.message or e.strerror,))
logging.warn("Could not open resume file: " + str(e))
max_timestamp_processed = default_since()
else:
logging.info("No resume file, processing an initial history.")
@@ -203,15 +215,16 @@ def since():
return max(max_timestamp_processed, default_since())
def process_new_events():
# type: () -> None
"""
Forward new Asana task events to Zulip.
"""
# In task queries, Asana only exposes IDs for projects and users, so we need
# to look up the mappings.
projects = dict((elt["id"], elt["name"]) for elt in \
fetch_from_asana("/projects")["data"])
users = dict((elt["id"], elt["name"]) for elt in \
fetch_from_asana("/users")["data"])
projects = dict((elt["id"], elt["name"]) for elt in
fetch_from_asana("/projects")["data"])
users = dict((elt["id"], elt["name"]) for elt in
fetch_from_asana("/users")["data"])
cutoff = since()
max_timestamp_processed = cutoff
@@ -268,7 +281,7 @@ def process_new_events():
# resolve.
if not result.get("result"):
logging.warn("Malformed result, exiting:")
logging.warn(result)
logging.warn(str(result))
return
if result["result"] != "success":

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright © 2014 Zulip, Inc.
@@ -22,7 +21,6 @@
# THE SOFTWARE.
# Change these values to configure authentication for basecamp account
BASECAMP_ACCOUNT_ID = "12345678"
BASECAMP_USERNAME = "foo@example.com"
@@ -42,7 +40,7 @@ ZULIP_STREAM_NAME = "basecamp"
ZULIP_API_PATH = None
# Set this to your Zulip API server URI
ZULIP_SITE = "https://api.zulip.com"
ZULIP_SITE = "https://zulip.example.com"
# If you wish to log to a file rather than stdout/stderr,
# please fill this out your desired path

View File

@@ -32,10 +32,9 @@ import logging
import time
import re
import sys
from stderror import write
import os
from datetime import datetime, timedelta
from six.moves.html_parser import HTMLParser
import six
sys.path.insert(0, os.path.dirname(__file__))
import zulip_basecamp_config as config
@@ -44,7 +43,9 @@ VERSION = "0.9"
if config.ZULIP_API_PATH is not None:
sys.path.append(config.ZULIP_API_PATH)
import zulip
from six.moves.html_parser import HTMLParser
from typing import Any, Dict
import six
client = zulip.Client(
email=config.ZULIP_USER,
@@ -66,25 +67,27 @@ while len(json_implementations):
# void function that checks the permissions of the files this script needs.
def check_permissions():
# type: () -> None
# check that the log file can be written
if config.LOG_FILE:
try:
open(config.LOG_FILE, "w")
except IOError as e:
sys.stderr("Could not open up log for writing:")
sys.stderr(e)
sys.stderr.write("Could not open up log for writing:")
sys.stderr.write(str(e))
# check that the resume file can be written (this creates if it doesn't exist)
try:
open(config.RESUME_FILE, "a+")
except IOError as e:
sys.stderr("Could not open up the file %s for reading and writing" % (config.RESUME_FILE,))
sys.stderr(e)
sys.stderr.write("Could not open up the file %s for reading and writing" % (config.RESUME_FILE),)
sys.stderr.write(str(e))
# builds the message dict for sending a message with the Zulip API
def build_message(event):
# type: (Dict[str, Any]) -> Dict[str, Any]
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,))
"This event doesn't have the expected format:\n%s" % (event,))
return None
# adjust the topic length to be bounded to 60 characters
topic = event['bucket']['name']
@@ -110,16 +113,17 @@ def build_message(event):
# the main run loop for this mirror script
def run_mirror():
# type: () -> None
# we should have the right (write) permissions on the resume file, as seen
# in check_permissions, but it may still be empty or corrupted
try:
with open(config.RESUME_FILE) as f:
since = f.read()
since = f.read() # type: Any
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:
logging.warn("Could not open resume file: %s" % (e.message or e.strerror,))
logging.warn("Could not open resume file: %s" % (e,))
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).
@@ -136,12 +140,12 @@ def run_mirror():
if len(events):
logging.info("Got event(s): %s" % (response.text,))
if response.status_code >= 500:
logging.error(response.status_code)
logging.error(str(response.status_code))
continue
if response.status_code == 429:
# exponential backoff
sleepInterval *= 2
logging.error(response.status_code)
logging.error(str(response.status_code))
continue
if response.status_code == 400:
logging.error("Something went wrong. Basecamp must be unhappy for this reason: %s" % (response.text,))
@@ -173,7 +177,7 @@ def run_mirror():
if __name__ == "__main__":
if not isinstance(config.RESUME_FILE, six.string_types):
sys.stderr("RESUME_FILE path not given; refusing to continue")
sys.stderr.write("RESUME_FILE path not given; refusing to continue")
check_permissions()
if config.LOG_FILE:
logging.basicConfig(filename=config.LOG_FILE, level=logging.INFO)

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright © 2014 Zulip, Inc.
@@ -22,7 +21,6 @@
# THE SOFTWARE.
# Change these values to configure authentication for your codebase account
# Note that this is the Codebase API Username, found in the Settings page
# for your account
@@ -51,7 +49,7 @@ ZULIP_TICKETS_STREAM_NAME = "tickets"
ZULIP_API_PATH = None
# Set this to your Zulip API server URI
ZULIP_SITE = "https://api.zulip.com"
ZULIP_SITE = "https://zulip.example.com"
# If you wish to log to a file rather than stdout/stderr,
# please fill this out your desired path

View File

@@ -38,8 +38,6 @@ import sys
import os
from datetime import datetime, timedelta
import six
try:
import dateutil.parser
@@ -54,7 +52,9 @@ VERSION = "0.9"
if config.ZULIP_API_PATH is not None:
sys.path.append(config.ZULIP_API_PATH)
import six
import zulip
from typing import Any, List, Dict, Optional
client = zulip.Client(
email=config.ZULIP_USER,
@@ -74,17 +74,18 @@ while len(json_implementations):
continue
def make_api_call(path):
# type: (str) -> Optional[List[Dict[str, Any]]]
response = requests.get("https://api3.codebasehq.com/%s" % (path,),
auth=(config.CODEBASE_API_USERNAME, config.CODEBASE_API_KEY),
params={'raw': True},
headers = {"User-Agent": user_agent,
"Content-Type": "application/json",
"Accept": "application/json"})
auth=(config.CODEBASE_API_USERNAME, config.CODEBASE_API_KEY),
params={'raw': True},
headers = {"User-Agent": user_agent,
"Content-Type": "application/json",
"Accept": "application/json"})
if response.status_code == 200:
return json.loads(response.text)
if response.status_code >= 500:
logging.error(response.status_code)
logging.error(str(response.status_code))
return None
if response.status_code == 403:
logging.error("Bad authorization from Codebase. Please check your credentials")
@@ -94,9 +95,11 @@ def make_api_call(path):
return None
def make_url(path):
# type: (str) -> str
return "%s/%s" % (config.CODEBASE_ROOT_URL, path)
def handle_event(event):
# type: (Dict[str, Any]) -> None
event = event['event']
event_type = event['type']
actor_name = event['actor_name']
@@ -116,7 +119,6 @@ def handle_event(event):
url = make_url("projects/%s" % (project_link,))
scm = "of type %s" % (project_repo_type,) if project_repo_type else ""
subject = "Repository %s Created" % (project_name,)
content = "%s created a new repository %s [%s](%s)" % (actor_name, scm, project_name, url)
elif event_type == 'push':
@@ -136,8 +138,8 @@ def handle_event(event):
else:
if new_ref:
branch = "new branch %s" % (branch,)
content = "%s pushed %s commit(s) to %s in project %s:\n\n" % \
(actor_name, num_commits, branch, project)
content = ("%s pushed %s commit(s) to %s in project %s:\n\n" %
(actor_name, num_commits, branch, project))
for commit in raw_props.get('commits'):
ref = commit.get('ref')
url = make_url("projects/%s/repositories/%s/commit/%s" % (project_link, repo_link, ref))
@@ -155,8 +157,8 @@ def handle_event(event):
if assignee is None:
assignee = "no one"
subject = "#%s: %s" % (num, name)
content = """%s created a new ticket [#%s](%s) priority **%s** assigned to %s:\n\n~~~ quote\n %s""" % \
(actor_name, num, url, priority, assignee, name)
content = ("""%s created a new ticket [#%s](%s) priority **%s** assigned to %s:\n\n~~~ quote\n %s""" %
(actor_name, num, url, priority, assignee, name))
elif event_type == 'ticketing_note':
stream = config.ZULIP_TICKETS_STREAM_NAME
@@ -165,7 +167,6 @@ def handle_event(event):
body = raw_props.get('content')
changes = raw_props.get('changes')
url = make_url("projects/%s/tickets/%s" % (project_link, num))
subject = "#%s: %s" % (num, name)
@@ -229,8 +230,8 @@ def handle_event(event):
subject = "Deployment to %s" % (environment,)
content = "%s deployed [%s](%s) [through](%s) [%s](%s) to the **%s** environment." % \
(actor_name, start_ref, start_ref_url, between_url, end_ref, end_ref_url, environment)
content = ("%s deployed [%s](%s) [through](%s) [%s](%s) to the **%s** environment." %
(actor_name, start_ref, start_ref_url, between_url, end_ref, end_ref_url, environment))
if servers is not None:
content += "\n\nServers deployed to: %s" % (", ".join(["`%s`" % (server,) for server in servers]))
@@ -263,9 +264,11 @@ def handle_event(event):
# the main run loop for this mirror script
def run_mirror():
# type: () -> None
# we should have the right (write) permissions on the resume file, as seen
# in check_permissions, but it may still be empty or corrupted
def default_since():
# type: () -> datetime
return datetime.utcnow() - timedelta(hours=config.CODEBASE_INITIAL_HISTORY_HOURS)
try:
@@ -274,10 +277,9 @@ def run_mirror():
if timestamp == '':
since = default_since()
else:
timestamp = int(timestamp, 10)
since = datetime.fromtimestamp(timestamp)
since = datetime.fromtimestamp(float(timestamp))
except (ValueError, IOError) as e:
logging.warn("Could not open resume file: %s" % (e.message or e.strerror,))
logging.warn("Could not open resume file: %s" % (str(e)))
since = default_since()
try:
@@ -299,28 +301,29 @@ def run_mirror():
time.sleep(sleepInterval)
except KeyboardInterrupt:
open(config.RESUME_FILE, 'w').write(since.strftime("%s"));
open(config.RESUME_FILE, 'w').write(since.strftime("%s"))
logging.info("Shutting down Codebase mirror")
# void function that checks the permissions of the files this script needs.
def check_permissions():
# type: () -> None
# check that the log file can be written
if config.LOG_FILE:
try:
open(config.LOG_FILE, "w")
except IOError as e:
sys.stderr("Could not open up log for writing:")
sys.stderr(e)
sys.stderr.write("Could not open up log for writing:")
sys.stderr.write(str(e))
# check that the resume file can be written (this creates if it doesn't exist)
try:
open(config.RESUME_FILE, "a+")
except IOError as e:
sys.stderr("Could not open up the file %s for reading and writing" % (config.RESUME_FILE,))
sys.stderr(e)
sys.stderr.write("Could not open up the file %s for reading and writing" % (config.RESUME_FILE,))
sys.stderr.write(str(e))
if __name__ == "__main__":
if not isinstance(config.RESUME_FILE, six.string_types):
sys.stderr("RESUME_FILE path not given; refusing to continue")
sys.stderr.write("RESUME_FILE path not given; refusing to continue")
check_permissions()
if config.LOG_FILE:
logging.basicConfig(filename=config.LOG_FILE, level=logging.WARNING)

View File

@@ -30,13 +30,14 @@
# aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master
from __future__ import absolute_import
from typing import Text
import os
import sys
import subprocess
import os.path
sys.path.insert(0, os.path.dirname(__file__))
from . import zulip_git_config as config
import zulip_git_config as config
VERSION = "0.9"
if config.ZULIP_API_PATH is not None:
@@ -49,22 +50,8 @@ client = zulip.Client(
api_key=config.ZULIP_API_KEY,
client="ZulipGit/" + VERSION)
# check_output is backported from subprocess.py in Python 2.7
def check_output(*popenargs, **kwargs):
if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.')
process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
output, unused_err = process.communicate()
retcode = process.poll()
if retcode:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
raise subprocess.CalledProcessError(retcode, cmd, output=output)
return output
subprocess.check_output = check_output
def git_repository_name():
# type: () -> Text
output = subprocess.check_output(["git", "rev-parse", "--is-bare-repository"])
if output.strip() == "true":
return os.path.basename(os.getcwd())[:-len(".git")]
@@ -72,6 +59,7 @@ def git_repository_name():
return os.path.basename(os.path.dirname(os.getcwd()))
def git_commit_range(oldrev, newrev):
# type: (str, str) -> str
log_cmd = ["git", "log", "--reverse",
"--pretty=%aE %H %s", "%s..%s" % (oldrev, newrev)]
commits = ''
@@ -84,6 +72,7 @@ def git_commit_range(oldrev, newrev):
return commits
def send_bot_message(oldrev, newrev, refname):
# type: (str, str, str) -> None
repo_name = git_repository_name()
branch = refname.replace('refs/heads/', '')
destination = config.commit_notice_destination(repo_name, branch, newrev)
@@ -95,7 +84,7 @@ def send_bot_message(oldrev, newrev, refname):
old_head = oldrev[:12]
if (oldrev == '0000000000000000000000000000000000000000' or
newrev == '0000000000000000000000000000000000000000'):
newrev == '0000000000000000000000000000000000000000'):
# New branch pushed or old branch removed
added = ''
removed = ''

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright © 2014 Zulip, Inc.
@@ -62,4 +61,4 @@ def format_commit_message(author, subject, commit_id):
ZULIP_API_PATH = None
# Set this to your Zulip server's API URI
ZULIP_SITE = "https://api.zulip.com"
ZULIP_SITE = "https://zulip.example.com"

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env python
from __future__ import print_function
import datetime
import httplib2
import os
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
try:
import argparse
flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
flags = None
# If modifying these scopes, delete your previously saved credentials
# at zulip/bots/gcal/
# NOTE: When adding more scopes, add them after the previous one in the same field, with a space
# seperating them.
SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'
# This file contains the information that google uses to figure out which application is requesting
# this client's data.
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Zulip Calendar Bot'
HOME_DIR = os.path.expanduser('~')
def get_credentials():
# type: () -> client.Credentials
"""Gets valid user credentials from storage.
If nothing has been stored, or if the stored credentials are invalid,
the OAuth2 flow is completed to obtain the new credentials.
Returns:
Credentials, the obtained credential.
"""
credential_path = os.path.join(HOME_DIR,
'google-credentials.json')
store = Storage(credential_path)
credentials = store.get()
if not credentials or credentials.invalid:
flow = client.flow_from_clientsecrets(os.path.join(HOME_DIR, CLIENT_SECRET_FILE), SCOPES)
flow.user_agent = APPLICATION_NAME
if flags:
# This attempts to open an authorization page in the default web browser, and asks the user
# to grant the bot access to their data. If the user grants permission, the run_flow()
# function returns new credentials.
credentials = tools.run_flow(flow, store, flags)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
print('Storing credentials to ' + credential_path)
get_credentials()

View File

@@ -0,0 +1,179 @@
#!/usr/bin/env python
from __future__ import print_function
import datetime
import httplib2
import itertools
import logging
import optparse
import os
from six.moves import urllib
import sys
import time
import traceback
from typing import List, Set, Tuple, Iterable, Optional
from oauth2client import client, tools
from oauth2client.file import Storage
try:
from googleapiclient import discovery
except ImportError:
logging.exception('Install google-api-python-client')
sys.path.append(os.path.join(os.path.dirname(__file__), '../../'))
import zulip
SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Zulip'
HOME_DIR = os.path.expanduser('~')
# Our cached view of the calendar, updated periodically.
events = [] # type: List[Tuple[int, datetime.datetime, str]]
# Unique keys for events we've already sent, so we don't remind twice.
sent = set() # type: Set[Tuple[int, datetime.datetime]]
sys.path.append(os.path.dirname(__file__))
parser = optparse.OptionParser(r"""
%prog \
--user foo@zulip.com \
--calendar calendarID@example.calendar.google.com
This integration can be used to send yourself reminders, on Zulip, of Google Calendar Events.
Before running this integration make sure you run the get-google-credentials file to give Zulip
access to certain aspects of your Google Account.
This integration should be run on your local machine. Your API key and other information are
revealed to local users through the command line.
Depends on: google-api-python-client
""")
parser.add_option('--interval',
dest='interval',
default=30,
type=int,
action='store',
help='Minutes before event for reminder [default: 30]',
metavar='MINUTES')
parser.add_option('--calendar',
dest = 'calendarID',
default = 'primary',
type = str,
action = 'store',
help = 'Calendar ID for the calendar you want to receive reminders from.')
parser.add_option_group(zulip.generate_option_group(parser))
(options, args) = parser.parse_args()
if not (options.zulip_email):
parser.error('You must specify --user')
zulip_client = zulip.init_from_options(options)
def get_credentials():
# type: () -> client.Credentials
"""Gets valid user credentials from storage.
If nothing has been stored, or if the stored credentials are invalid,
an exception is thrown and the user is informed to run the script in this directory to get
credentials.
Returns:
Credentials, the obtained credential.
"""
try:
credential_path = os.path.join(HOME_DIR,
'google-credentials.json')
store = Storage(credential_path)
credentials = store.get()
return credentials
except client.Error:
logging.exception('Error while trying to open the `google-credentials.json` file.')
except IOError:
logging.error("Run the get-google-credentials script from this directory first.")
def get_events():
# type: () -> Iterable[Tuple[int, datetime.datetime, str]]
credentials = get_credentials()
creds = credentials.authorize(httplib2.Http())
service = discovery.build('calendar', 'v3', http=creds)
now = datetime.datetime.utcnow().isoformat() + 'Z' # 'Z' indicates UTC time
feed = service.events().list(calendarId=options.calendarID, timeMin=now, maxResults=5,
singleEvents=True, orderBy='startTime').execute()
for event in feed["items"]:
try:
start = event["start"]["dateTime"]
except KeyError:
start = event["start"]["date"]
start = start[:19]
# All-day events can have only a date
fmt = '%Y-%m-%dT%H:%M:%S' if 'T' in start else '%Y-%m-%d'
start = datetime.datetime.strptime(start, fmt)
try:
yield (event["id"], start, event["summary"])
except KeyError:
yield (event["id"], start, "(No Title)")
def send_reminders():
# type: () -> Optional[None]
global sent
messages = []
keys = set()
now = datetime.datetime.now()
for id, start, summary in events:
dt = start - now
if dt.days == 0 and dt.seconds < 60 * options.interval:
# The unique key includes the start time, because of
# repeating events.
key = (id, start)
if key not in sent:
if start.hour == 0 and start.minute == 0:
line = '%s is today.' % (summary,)
else:
line = '%s starts at %s' % (summary, start.strftime('%H:%M'))
print('Sending reminder:', line)
messages.append(line)
keys.add(key)
if not messages:
return
if len(messages) == 1:
message = 'Reminder: ' + messages[0]
else:
message = 'Reminder:\n\n' + '\n'.join('* ' + m for m in messages)
zulip_client.send_message(dict(
type = 'private',
to = options.zulip_email,
sender = options.zulip_email,
content = message))
sent.update(keys)
# Loop forever
for i in itertools.count():
try:
# We check reminders every minute, but only
# download the calendar every 10 minutes.
if not i % 10:
events = list(get_events())
send_reminders()
except:
logging.exception("Couldn't download Google calendar and/or couldn't post to Zulip.")
time.sleep(60)

View File

@@ -29,10 +29,13 @@ from __future__ import absolute_import
import zulip
from six.moves import range
from typing import Any, Optional, Text
from mercurial import ui, repo
VERSION = "0.9"
def format_summary_line(web_url, user, base, tip, branch, node):
# type: (str, str, int, int, str, Text) -> Text
"""
Format the first line of the message, which contains summary
information about the changeset and links to the changelog if a
@@ -58,6 +61,7 @@ def format_summary_line(web_url, user, base, tip, branch, node):
node=node[:12])
def format_commit_lines(web_url, repo, base, tip):
# type: (str, repo, int, int) -> str
"""
Format the per-commit information for the message, including the one-line
commit summary and a link to the diff if a web URL has been configured:
@@ -83,6 +87,7 @@ def format_commit_lines(web_url, repo, base, tip):
return "\n".join(summary for summary in commit_summaries)
def send_zulip(email, api_key, site, stream, subject, content):
# type: (str, str, str, str, str, Text) -> str
"""
Send a message to Zulip using the provided credentials, which should be for
a bot in most cases.
@@ -101,6 +106,7 @@ def send_zulip(email, api_key, site, stream, subject, content):
client.send_message(message_data)
def get_config(ui, item):
# type: (ui, str) -> Optional[str]
try:
# configlist returns everything in lists.
return ui.configlist('zulip', item)[0]
@@ -108,6 +114,7 @@ def get_config(ui, item):
return None
def hook(ui, repo, **kwargs):
# type: (ui, repo, Optional[Text]) -> None
"""
Invoked by configuring a [hook] entry in .hg/hgrc.
"""

View File

@@ -31,8 +31,8 @@ class ZulipListener extends AbstractIssueEventListener {
// The base JIRA url for browsing
String issueBaseUrl = "https://jira.COMPANY.com/browse/"
// Your zulip domain, only change if you have a custom one
String base_url = "https://api.zulip.com"
// Your zulip domain
String base_url = "https://zulip.example.com/"
@Override
void workflowEvent(IssueEvent event) {
@@ -144,6 +144,6 @@ class ZulipListener extends AbstractIssueEventListener {
}
String zulipUrl(method) {
return base_url + "/v1/" + method
return base_url.replaceAll("/+$", "") + "/api/v1/" + method
}
}

View File

@@ -2,22 +2,25 @@
import optparse
import zulip
from typing import List, Text, Dict, Any
VERSION = "0.9"
# Nagios passes the notification details as command line options.
# In Nagios, "output" means "first line of output", and "long
# output" means "other lines of output".
parser = optparse.OptionParser()
parser.add_option('--output', default='')
parser = optparse.OptionParser() # type: optparse.OptionParser
parser.add_option('--output', default='')
parser.add_option('--long-output', default='')
parser.add_option('--stream', default='nagios')
parser.add_option('--config', default='/etc/nagios3/zuliprc')
for opt in ('type', 'host', 'service', 'state'):
parser.add_option('--' + opt)
(opts, args) = parser.parse_args()
(opts, args) = parser.parse_args() # type: Any, List[Text]
client = zulip.Client(config_file=opts.config, client="ZulipNagios/" + VERSION)
client = zulip.Client(config_file=opts.config,
client="ZulipNagios/" + VERSION) # type: zulip.Client
msg = dict(type='stream', to=opts.stream)
msg = dict(type='stream', to=opts.stream) # type: Dict[str, Any]
# Set a subject based on the host or service in question. This enables
# threaded discussion of multiple concurrent issues, and provides useful
@@ -26,7 +29,7 @@ msg = dict(type='stream', to=opts.stream)
# We send PROBLEM and RECOVERY messages to the same subject.
if opts.service is None:
# Host notification
thing = 'host'
thing = 'host' # type: Text
msg['subject'] = 'host %s' % (opts.host,)
else:
# Service notification
@@ -41,7 +44,7 @@ msg['content'] = '**%s**: %s is %s' % (opts.type, thing, opts.state)
# The "long output" can contain newlines represented by "\n" escape sequences.
# The Nagios mail command uses /usr/bin/printf "%b" to expand these.
# We will be more conservative and handle just this one escape sequence.
output = (opts.output + '\n' + opts.long_output.replace(r'\n', '\n')).strip()
output = (opts.output + '\n' + opts.long_output.replace(r'\n', '\n')).strip() # type: Text
if output:
# Put any command output in a code block.
msg['content'] += ('\n\n~~~~\n' + output + "\n~~~~\n")

View File

@@ -0,0 +1,74 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Zulip notification post-receive hook.
# Copyright © 2012-2017 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.
import os
import subprocess
import sys
sys.path.insert(0, os.path.dirname(__file__))
import zulip_openshift_config as config
VERSION = '0.1'
if config.ZULIP_API_PATH is not None:
sys.path.append(config.ZULIP_API_PATH)
import zulip
client = zulip.Client(
email=config.ZULIP_USER,
site=config.ZULIP_SITE,
api_key=config.ZULIP_API_KEY,
client='ZulipOpenShift/' + VERSION)
def get_deployment_details():
# type: () -> Dict[str, str]
# "gear deployments" output example:
# Activation time - Deployment ID - Git Ref - Git SHA1
# 2017-01-07 15:40:30 -0500 - 9e2b7143 - master - b9ce57c - ACTIVE
dep = subprocess.check_output(['gear', 'deployments']).splitlines()[1]
splits = dep.split(' - ')
return dict(app_name=os.environ['OPENSHIFT_APP_NAME'],
url=os.environ['OPENSHIFT_APP_DNS'],
branch=splits[2],
commit_id=splits[3])
def send_bot_message(deployment):
# type: (Dict[str, str]) -> None
destination = config.deployment_notice_destination(deployment['branch'])
if destination is None:
# No message should be sent
return
message = config.format_deployment_message(**deployment)
client.send_message({
'type': 'stream',
'to': destination['stream'],
'subject': destination['subject'],
'content': message,
})
return
deployment = get_deployment_details()
send_bot_message(deployment)

View File

@@ -0,0 +1,75 @@
# -*- coding: utf-8 -*-
#
# Copyright © 2017 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.
# https://github.com/python/mypy/issues/1141
from typing import Text
# Change these values to configure authentication for the plugin
ZULIP_USER = 'openshift-bot@example.com'
ZULIP_API_KEY = '0123456789abcdef0123456789abcdef'
# deployment_notice_destination() lets you customize where deployment notices
# are sent to with the full power of a Python function.
#
# It takes the following arguments:
# * branch = the name of the branch where the deployed commit was
# pushed to
#
# Returns a dictionary encoding the stream and subject to send the
# notification to (or None to send no notification).
#
# The default code below will send every commit pushed to "master" to
# * stream "deployments"
# * topic "master"
# And similarly for branch "test-post-receive" (for use when testing).
def deployment_notice_destination(branch):
# type: (str) -> Dict[str, Text]
if branch in ['master', 'test-post-receive']:
return dict(stream = 'deployments',
subject = u'%s' % (branch,))
# Return None for cases where you don't want a notice sent
return None
# Modify this function to change how deployments are displayed
#
# It takes the following arguments:
# * app_name = the name of the app being deployed
# * url = the FQDN (Fully Qualified Domain Name) where the app
# can be found
# * branch = the name of the branch where the deployed commit was
# pushed to
# * commit_id = hash of the commit that triggered the deployment
# * dep_id = deployment id
# * dep_time = deployment timestamp
def format_deployment_message(
app_name='', url='', branch='', commit_id='', dep_id='', dep_time=''):
# type: (str, str, str, str, str, str) -> str
return 'Deployed commit `%s` (%s) in [%s](%s)' % (
commit_id, branch, app_name, url)
## If properly installed, the Zulip API should be in your import
## path, but if not, set a custom path below
ZULIP_API_PATH = None # type: str
# Set this to your Zulip server's API URI
ZULIP_SITE = 'https://zulip.example.com'

19
api/integrations/perforce/git_p4.py Normal file → Executable file
View File

@@ -39,9 +39,11 @@ except ImportError:
"""This exception is raised when a process run by check_call() returns
a non-zero exit status. The exit status will be stored in the
returncode attribute."""
def __init__(self, returncode, cmd):
self.returncode = returncode
self.cmd = cmd
def __str__(self):
return "Command '%s' returned non-zero exit status %d" % (self.cmd, self.returncode)
@@ -152,7 +154,7 @@ def p4_has_command(cmd):
command does not exist in this version of p4."""
real_cmd = p4_build_cmd(["help", cmd])
p = subprocess.Popen(real_cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
stderr=subprocess.PIPE)
p.communicate()
return p.returncode == 0
@@ -532,7 +534,7 @@ def parseRevision(ref):
def branchExists(ref):
rev = read_pipe(["git", "rev-parse", "-q", "--verify", ref],
ignore_error=True)
ignore_error=True)
return len(rev) > 0
def extractLogMessageFromGitCommit(commit):
@@ -871,7 +873,6 @@ class P4UserMap(object):
self.users[output["User"]] = output["FullName"] + " <" + output["Email"] + ">"
self.emails[output["Email"]] = output["User"]
s = ''
for (key, val) in self.users.items():
s += "%s\t%s\n" % (key.expandtabs(1), val.expandtabs(1))
@@ -957,7 +958,6 @@ class P4RollBack(Command):
log = extractLogMessageFromGitCommit(ref)
settings = extractSettingsGitLog(log)
depotPaths = settings['depot-paths']
change = settings['change']
@@ -1712,7 +1712,7 @@ class P4Submit(Command, P4UserMap):
if self.conflict_behavior == "ask":
print("What do you want to do?")
response = input("[s]kip this commit but apply"
" the rest, or [q]uit? ")
" the rest, or [q]uit? ")
if not response:
continue
elif self.conflict_behavior == "skip":
@@ -2299,7 +2299,7 @@ class P4Sync(Command, P4UserMap):
print("Change %s is labelled %s" % (change, labelDetails))
files = p4CmdList(["files"] + ["%s...@%s" % (p, change)
for p in self.branchPrefixes])
for p in self.branchPrefixes])
if len(files) == len(labelRevisions):
@@ -2337,8 +2337,8 @@ class P4Sync(Command, P4UserMap):
if self.verbose:
print("Querying files for label %s" % label)
for file in p4CmdList(["files"] +
["%s...@%s" % (p, label)
for p in self.depotPaths]):
["%s...@%s" % (p, label)
for p in self.depotPaths]):
revisions[file["depotFile"]] = file["rev"]
change = int(file["change"])
if change > newestChange:
@@ -2478,7 +2478,6 @@ class P4Sync(Command, P4UserMap):
if source not in self.knownBranches:
lostAndFoundBranches.add(source)
for branch in lostAndFoundBranches:
self.knownBranches[branch] = branch
@@ -2696,7 +2695,6 @@ class P4Sync(Command, P4UserMap):
sys.stderr.write("p4 exitcode: %s\n" % info['p4ExitCode'])
sys.exit(1)
change = int(info["change"])
if change > newestRevision:
newestRevision = change
@@ -2725,7 +2723,6 @@ class P4Sync(Command, P4UserMap):
print("IO error with git fast-import. Is your git version recent enough?")
print(self.gitError.read())
def run(self, args):
self.depotPaths = []
self.changeRange = ""

View File

@@ -23,7 +23,7 @@
'''Zulip notification change-commit hook.
In Perforce, The "change-commit" trigger is fired after a metadata has been
created, files have been transferred, and the changelist comitted to the depot
created, files have been transferred, and the changelist committed to the depot
database.
This specific trigger expects command-line arguments in the form:
@@ -44,6 +44,7 @@ import git_p4
__version__ = "0.1"
sys.path.insert(0, os.path.dirname(__file__))
from typing import Any, Dict, Optional, Text
import zulip_perforce_config as config
if config.ZULIP_API_PATH is not None:
@@ -54,11 +55,11 @@ client = zulip.Client(
email=config.ZULIP_USER,
site=config.ZULIP_SITE,
api_key=config.ZULIP_API_KEY,
client="ZulipPerforce/" + __version__)
client="ZulipPerforce/" + __version__) # type: zulip.Client
try:
changelist = int(sys.argv[1])
changeroot = sys.argv[2]
changelist = int(sys.argv[1]) # type: int
changeroot = sys.argv[2] # type: str
except IndexError:
print("Wrong number of arguments.\n\n", end=' ', file=sys.stderr)
print(__doc__, file=sys.stderr)
@@ -68,22 +69,23 @@ except ValueError:
print(__doc__, file=sys.stderr)
sys.exit(-1)
metadata = git_p4.p4_describe(changelist)
metadata = git_p4.p4_describe(changelist) # type: Dict[str, str]
destination = config.commit_notice_destination(changeroot, changelist)
destination = config.commit_notice_destination(changeroot, changelist) # type: Optional[Dict[str, str]]
if destination is None:
# Don't forward the notice anywhere
sys.exit(0)
message = """**{0}** committed revision @{1} to `{2}`.
> {3}
""".format(metadata["user"], metadata["change"], changeroot, metadata["desc"])
message = "**{0}** committed revision @{1} to `{2}`.\n\n> {3}".format(
metadata["user"],
metadata["change"],
changeroot,
metadata["desc"]) # type: str
message_data = {
"type": "stream",
"to": destination["stream"],
"subject": destination["subject"],
"content": message,
}
} # type: Dict[str, Any]
client.send_message(message_data)

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright © 2014 Zulip, Inc.
@@ -25,6 +24,7 @@
# Change these values to configure authentication for the plugin
ZULIP_USER = "p4-bot@example.com"
ZULIP_API_KEY = "0123456789abcdef0123456789abcdef"
ZULIP_SITE = "https://zulip.example.com"
# commit_notice_destination() lets you customize where commit notices
# are sent to with the full power of a Python function.
@@ -58,6 +58,3 @@ def commit_notice_destination(path, changelist):
## If properly installed, the Zulip API should be in your import
## path, but if not, set a custom path below
ZULIP_API_PATH = None
# This should not need to change unless you have a custom Zulip subdomain.
ZULIP_SITE = "https://api.zulip.com"

70
api/integrations/rss/rss-bot Executable file → Normal file
View File

@@ -34,12 +34,13 @@ import os
import sys
import time
from six.moves import urllib
from typing import Dict, List, Tuple, Any
import feedparser
import zulip
VERSION = "0.9"
RSS_DATA_DIR = os.path.expanduser(os.path.join('~', '.cache', 'zulip-rss'))
OLDNESS_THRESHOLD = 30 # days
VERSION = "0.9" # type: str
RSS_DATA_DIR = os.path.expanduser(os.path.join('~', '.cache', 'zulip-rss')) # type: str
OLDNESS_THRESHOLD = 30 # type: int
usage = """Usage: Send summaries of RSS entries for your favorite feeds to Zulip.
@@ -50,7 +51,7 @@ To use this script:
1. Create an RSS feed file containing 1 feed URL per line (default feed
file location: ~/.cache/zulip-rss/rss-feeds)
2. Subscribe to the stream that will receive RSS updates (default stream: rss)
3. create a ~/.zuliprc as described on https://zulip.com/api#api_keys
3. create a ~/.zuliprc as described on https://zulipchat.com/api#api_keys
4. Test the script by running it manually, like this:
/usr/local/share/zulip/integrations/rss/rss-bot
@@ -65,7 +66,7 @@ stream every 5 minutes is:
*/5 * * * * /usr/local/share/zulip/integrations/rss/rss-bot"""
parser = optparse.OptionParser(usage)
parser = optparse.OptionParser(usage) # type: optparse.OptionParser
parser.add_option('--stream',
dest='stream',
help='The stream to which to send RSS messages.',
@@ -82,9 +83,10 @@ parser.add_option('--feed-file',
default=os.path.join(RSS_DATA_DIR, "rss-feeds"),
action='store')
parser.add_option_group(zulip.generate_option_group(parser))
(opts, args) = parser.parse_args()
(opts, args) = parser.parse_args() # type: Tuple[Any, List[str]]
def mkdir_p(path):
# type: (str) -> None
# Python doesn't have an analog to `mkdir -p` < Python 3.2.
try:
os.makedirs(path)
@@ -101,90 +103,98 @@ except OSError:
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")
log_format = "%(asctime)s: %(message)s"
log_file = os.path.join(opts.data_dir, "rss-bot.log") # type: str
log_format = "%(asctime)s: %(message)s" # type: str
logging.basicConfig(format=log_format)
formatter = logging.Formatter(log_format)
file_handler = logging.FileHandler(log_file)
formatter = logging.Formatter(log_format) # type: logging.Formatter
file_handler = logging.FileHandler(log_file) # type: logging.FileHandler
file_handler.setFormatter(formatter)
logger = logging.getLogger(__name__)
logger = logging.getLogger(__name__) # type: logging.Logger
logger.setLevel(logging.DEBUG)
logger.addHandler(file_handler)
def log_error_and_exit(error):
# type: (str) -> None
logger.error(error)
logger.error(usage)
exit(1)
class MLStripper(HTMLParser):
def __init__(self):
# type: () -> None
self.reset()
self.fed = []
self.fed = [] # type: List[str]
def handle_data(self, data):
# type: (str) -> None
self.fed.append(data)
def get_data(self):
# type: () -> str
return ''.join(self.fed)
def strip_tags(html):
# type: (str) -> str
stripper = MLStripper()
stripper.feed(html)
return stripper.get_data()
def compute_entry_hash(entry):
# type: (Dict[str, Any]) -> str
entry_time = entry.get("published", entry.get("updated"))
entry_id = entry.get("id", entry.get("link"))
return hashlib.md5(entry_id + str(entry_time)).hexdigest()
def elide_subject(subject):
# type: (str) -> str
MAX_TOPIC_LENGTH = 60
if len(subject) > MAX_TOPIC_LENGTH:
subject = subject[:MAX_TOPIC_LENGTH - 3].rstrip() + '...'
return subject
def send_zulip(entry, feed_name):
# type: (Any, str) -> Dict[str, Any]
content = "**[%s](%s)**\n%s\n%s" % (entry.title,
entry.link,
strip_tags(entry.summary),
entry.link)
entry.link,
strip_tags(entry.summary),
entry.link) # type: str
message = {"type": "stream",
"sender": opts.email,
"sender": opts.zulip_email,
"to": opts.stream,
"subject": elide_subject(feed_name),
"content": content,
}
} # type: Dict[str, str]
return client.send_message(message)
try:
with open(opts.feed_file, "r") as f:
feed_urls = [feed.strip() for feed in f.readlines()]
feed_urls = [feed.strip() for feed in f.readlines()] # type: List[str]
except IOError:
log_error_and_exit("Unable to read feed file at %s." % (opts.feed_file,))
client = zulip.Client(email=opts.email, api_key=opts.api_key,
site=opts.site, client="ZulipRSS/" + VERSION)
client = zulip.Client(email=opts.zulip_email, api_key=opts.zulip_api_key,
site=opts.zulip_site, client="ZulipRSS/" + VERSION) # type: zulip.Client
first_message = True
first_message = True # type: bool
for feed_url in feed_urls:
feed_file = os.path.join(opts.data_dir, urllib.parse.urlparse(feed_url).netloc)
feed_file = os.path.join(opts.data_dir, urllib.parse.urlparse(feed_url).netloc) # Type: str
try:
with open(feed_file, "r") as f:
old_feed_hashes = dict((line.strip(), True) for line in f.readlines())
old_feed_hashes = dict((line.strip(), True) for line in f.readlines()) # type: Dict[str, bool]
except IOError:
old_feed_hashes = {}
new_hashes = []
data = feedparser.parse(feed_url)
new_hashes = [] # type: List[str]
data = feedparser.parse(feed_url) # type: feedparser.parse
for entry in data.entries:
entry_hash = compute_entry_hash(entry)
entry_hash = compute_entry_hash(entry) # type: str
# An entry has either been published or updated.
entry_time = entry.get("published_parsed", entry.get("updated_parsed"))
entry_time = entry.get("published_parsed", entry.get("updated_parsed")) # type: Tuple[int, int]
if entry_time is not None and (time.time() - calendar.timegm(entry_time)) > OLDNESS_THRESHOLD * 60 * 60 * 24:
# As a safeguard against misbehaving feeds, don't try to process
# entries older than some threshold.
@@ -197,12 +207,12 @@ for feed_url in feed_urls:
# entries in reverse chronological order.
break
feed_name = data.feed.title or feed_url
feed_name = data.feed.title or feed_url # type: str
response = send_zulip(entry, feed_name)
response = send_zulip(entry, feed_name) # type: Dict[str, Any]
if response["result"] != "success":
logger.error("Error processing %s" % (feed_url,))
logger.error(response)
logger.error(str(response))
if first_message:
# This is probably some fundamental problem like the stream not
# existing or something being misconfigured, so bail instead of

View File

@@ -34,6 +34,9 @@ import sys
import os.path
import pysvn
if False:
from typing import Any, Dict, List, Optional, Text, Tuple, Union
sys.path.insert(0, os.path.dirname(__file__))
import zulip_svn_config as config
VERSION = "0.9"
@@ -46,26 +49,27 @@ client = zulip.Client(
email=config.ZULIP_USER,
site=config.ZULIP_SITE,
api_key=config.ZULIP_API_KEY,
client="ZulipSVN/" + VERSION)
svn = pysvn.Client()
client="ZulipSVN/" + VERSION) # type: zulip.Client
svn = pysvn.Client() # type: pysvn.Client
path, rev = sys.argv[1:]
path, rev = sys.argv[1:] # type: Tuple[Text, Text]
# since its a local path, prepend "file://"
path = "file://" + path
entry = svn.log(path, revision_end=pysvn.Revision(pysvn.opt_revision_kind.number, rev))[0]
message = """**{0}** committed revision r{1} to `{2}`.
entry = svn.log(path, revision_end=pysvn.Revision(pysvn.opt_revision_kind.number, rev))[0] # type: Dict[Text, Union[Text, pysvn.Revision, List[Dict[Text, pysvn.Revision]]]]
message = "**{0}** committed revision r{1} to `{2}`.\n\n> {3}".format(
entry['author'],
rev,
path.split('/')[-1],
entry['revprops']['svn:log']) # type: Text
> {3}
""".format(entry['author'], rev, path.split('/')[-1], entry['revprops']['svn:log'])
destination = config.commit_notice_destination(path, rev)
destination = config.commit_notice_destination(path, rev) # type: Optional[Dict[Text, Text]]
message_data = {
"type": "stream",
"to": destination["stream"],
"subject": destination["subject"],
"content": message,
}
} # type: Dict[str, Any]
client.send_message(message_data)

View File

@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright © 2014 Zulip, Inc.
@@ -54,4 +53,4 @@ def commit_notice_destination(path, commit):
ZULIP_API_PATH = None
# Set this to your Zulip server's API URI
ZULIP_SITE = "https://api.zulip.com"
ZULIP_SITE = "https://zulip.example.com"

View File

@@ -42,6 +42,9 @@ sys.path.insert(0, os.path.dirname(__file__))
import zulip_trac_config as config
VERSION = "0.9"
if False:
from typing import Any
if config.ZULIP_API_PATH is not None:
sys.path.append(config.ZULIP_API_PATH)
@@ -53,31 +56,37 @@ client = zulip.Client(
client="ZulipTrac/" + VERSION)
def markdown_ticket_url(ticket, heading="ticket"):
# type: (Any, str) -> str
return "[%s #%s](%s/%s)" % (heading, ticket.id, config.TRAC_BASE_TICKET_URL, ticket.id)
def markdown_block(desc):
# type: (str) -> str
return "\n\n>" + "\n> ".join(desc.split("\n")) + "\n"
def truncate(string, length):
# type: (str, int) -> str
if len(string) <= length:
return string
return string[:length - 3] + "..."
def trac_subject(ticket):
# type: (Any) -> str
return truncate("#%s: %s" % (ticket.id, ticket.values.get("summary")), 60)
def send_update(ticket, content):
# type: (Any, str) -> None
client.send_message({
"type": "stream",
"to": config.STREAM_FOR_NOTIFICATIONS,
"content": content,
"subject": trac_subject(ticket)
})
"type": "stream",
"to": config.STREAM_FOR_NOTIFICATIONS,
"content": content,
"subject": trac_subject(ticket)
})
class ZulipPlugin(Component):
implements(ITicketChangeListener)
def ticket_created(self, ticket):
# type: (Any) -> None
"""Called when a ticket is created."""
content = "%s created %s in component **%s**, priority **%s**:\n" % \
(ticket.values.get("reporter"), markdown_ticket_url(ticket),
@@ -90,6 +99,7 @@ class ZulipPlugin(Component):
send_update(ticket, content)
def ticket_changed(self, ticket, comment, author, old_values):
# type: (Any, str, str, Dict[str, Any]) -> None
"""Called when a ticket is modified.
`old_values` is a dictionary containing the previous values of the
@@ -121,6 +131,7 @@ class ZulipPlugin(Component):
send_update(ticket, content)
def ticket_deleted(self, ticket):
# type: (Any) -> None
"""Called when a ticket is deleted."""
content = "%s was deleted." % markdown_ticket_url(ticket, heading="Ticket")
send_update(ticket, content)

View File

@@ -48,4 +48,4 @@ TRAC_NOTIFY_FIELDS = ["description", "summary", "resolution", "comment", "owner"
ZULIP_API_PATH = None
# Set this to your Zulip API server URI
ZULIP_SITE = "https://api.zulip.com"
ZULIP_SITE = "https://zulip.example.com"

View File

@@ -27,13 +27,14 @@ from __future__ import print_function
import os
import sys
import optparse
import six.moves.configparser
from six.moves.configparser import ConfigParser, NoSectionError, NoOptionError
import zulip
VERSION = "0.9"
CONFIGFILE = os.path.expanduser("~/.zulip_twitterrc")
def write_config(config, since_id, user):
# type: (ConfigParser, int, int) -> None
config.set('twitter', 'since_id', since_id)
config.set('twitter', 'user_id', user)
with open(CONFIGFILE, 'wb') as configfile:
@@ -41,7 +42,7 @@ def write_config(config, since_id, user):
parser = optparse.OptionParser(r"""
%prog --user foo@example.com --api-key 0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --twitter-id twitter_handle
%prog --user foo@example.com --api-key 0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --twitter-id twitter_handle --site=https://zulip.example.com
Slurp tweets on your timeline into a specific zulip stream.
@@ -69,18 +70,19 @@ parser = optparse.OptionParser(r"""
Make sure to go the application you created and click "create my
access token" as well. Fill in the values displayed.
Depends on: twitter-python
Depends on: https://github.com/bear/python-twitter version 3.1
(`pip install python-twitter`)
""")
parser.add_option('--twitter-id',
help='Twitter username to poll for new tweets from"',
metavar='URL')
help='Twitter username to poll for new tweets from"',
metavar='URL')
parser.add_option('--stream',
help='Default zulip stream to write tweets to')
help='Default zulip stream to write tweets to')
parser.add_option('--limit-tweets',
default=15,
type='int',
help='Maximum number of tweets to push at once')
default=15,
type='int',
help='Maximum number of tweets to push at once')
parser.add_option_group(zulip.generate_option_group(parser))
(options, args) = parser.parse_args()
@@ -89,18 +91,18 @@ if not options.twitter_id:
parser.error('You must specify --twitter-id')
try:
config = six.moves.configparser.ConfigParser()
config = 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 (six.moves.configparser.NoSectionError, six.moves.configparser.NoOptionError):
parser.error("Please provide a ~/.zulip_twitterrc")
except (NoSectionError, 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:
parser.error("Please provide a ~/.zulip_twitterrc")
parser.error("Please provide a ~/.zulip_twitterrc")
try:
import twitter
@@ -115,18 +117,18 @@ api = twitter.Api(consumer_key=consumer_key,
user = api.VerifyCredentials()
if not user.GetId():
if not user.id:
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 six.moves.configparser.NoOptionError:
except NoOptionError:
since_id = -1
try:
user_id = config.get('twitter', 'user_id')
except six.moves.configparser.NoOptionError:
except NoOptionError:
user_id = options.twitter_id
client = zulip.Client(
@@ -140,18 +142,18 @@ if since_id < 0 or options.twitter_id != user_id:
# No since id yet, fetch the latest and then start monitoring from next time
# Or, a different user id is being asked for, so start from scratch
# Either way, fetch last 5 tweets to start off
statuses = api.GetFriendsTimeline(user=options.twitter_id, count=5)
statuses = api.GetUserTimeline(screen_name=options.twitter_id, count=5)
else:
# We have a saved last id, so insert all newer tweets into the zulip stream
statuses = api.GetFriendsTimeline(user=options.twitter_id, since_id=since_id)
statuses = api.GetUserTimeline(screen_name=options.twitter_id, since_id=since_id)
for status in statuses[::-1][:options.limit_tweets]:
composed = "%s (%s)" % (status.GetUser().GetName(), status.GetUser().GetScreenName())
composed = "%s (%s)" % (status.user.name, status.user.screen_name)
message = {
"type": "stream",
"to": [options.stream],
"subject": composed,
"content": status.GetText(),
"type": "stream",
"to": [options.stream],
"subject": composed,
"content": status.text,
}
ret = client.send_message(message)
@@ -161,6 +163,6 @@ for status in statuses[::-1][:options.limit_tweets]:
print("Error sending message to zulip: %s" % ret['msg'])
break
else:
since_id = status.GetId()
since_id = status.id
write_config(config, since_id, user_id)

View File

@@ -27,13 +27,14 @@ from __future__ import print_function
import os
import sys
import optparse
import six.moves.configparser
from six.moves.configparser import ConfigParser, NoSectionError, NoOptionError
import zulip
VERSION = "0.9"
CONFIGFILE = os.path.expanduser("~/.zulip_twitterrc")
def write_config(config, since_id):
# type: (ConfigParser, int) -> None
if 'search' not in config.sections():
config.add_section('search')
config.set('search', 'since_id', since_id)
@@ -42,24 +43,27 @@ def write_config(config, since_id):
parser = optparse.OptionParser(r"""
%prog --user foo@zulip.com --api-key a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 --search="@nprnews,quantum physics"
%prog --user username@example.com --api-key a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5 \
--search="@nprnews,quantum physics"
Send Twitter search results to a Zulip stream.
Depends on: twitter-python version 1.0 or later
Depends on: https://github.com/bear/python-twitter version 3.1
To use this script:
0. Use `pip install python-twitter` to install `python-twitter`.
1. Set up Twitter authentication, as described below
2. Subscribe to the stream that will receive Twitter updates (default stream: twitter)
3. Test the script by running it manually, like this:
/usr/local/share/zulip/integrations/twitter/twitter-search-bot --search="@nprnews,quantum physics"
/usr/local/share/zulip/integrations/twitter/twitter-search-bot \
--search="@nprnews,quantum physics" --site=https://zulip.example.com
4. Configure a crontab entry for this script. A sample crontab entry
that will process tweets every 5 minutes is:
*/5 * * * * /usr/local/share/zulip/integrations/twitter/twitter-search-bot --search="@nprnews,quantum physics"
*/5 * * * * /usr/local/share/zulip/integrations/twitter/twitter-search-bot [options]
== Setting up Twitter authentications ==
@@ -108,22 +112,22 @@ if not opts.search_terms:
parser.error('You must specify a search term.')
try:
config = six.moves.configparser.ConfigParser()
config = 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 (six.moves.configparser.NoSectionError, six.moves.configparser.NoOptionError):
parser.error("Please provide a ~/.zulip_twitterrc")
except (NoSectionError, NoOptionError):
parser.error("Please provide a ~/.zulip_twitterrc")
if not (consumer_key and consumer_secret and access_token_key and access_token_secret):
parser.error("Please provide a ~/.zulip_twitterrc")
parser.error("Please provide a ~/.zulip_twitterrc")
try:
since_id = config.getint('search', 'since_id')
except (six.moves.configparser.NoOptionError, six.moves.configparser.NoSectionError):
except (NoOptionError, NoSectionError):
since_id = 0
try:
@@ -138,15 +142,14 @@ 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.")
if not user.id:
print("Unable to log in to twitter with supplied credentials. Please double-check and try again")
sys.exit()
client = zulip.Client(
email=opts.email,
api_key=opts.api_key,
site=opts.site,
email=opts.zulip_email,
api_key=opts.zulip_api_key,
site=opts.zulip_site,
client="ZulipTwitterSearch/" + VERSION,
verbose=True)
@@ -155,11 +158,11 @@ statuses = api.GetSearch(search_query, since_id=since_id)
for status in statuses[::-1][:opts.limit_tweets]:
# https://twitter.com/eatevilpenguins/status/309995853408530432
composed = "%s (%s)" % (status.GetUser().GetName(),
status.GetUser().GetScreenName())
url = "https://twitter.com/%s/status/%s" % (status.GetUser().GetScreenName(),
status.GetId())
content = status.GetText()
composed = "%s (%s)" % (status.user.name,
status.user.screen_name)
url = "https://twitter.com/%s/status/%s" % (status.user.screen_name,
status.id)
content = status.text
search_term_used = None
for term in opts.search_terms.split(","):
@@ -173,10 +176,10 @@ for status in statuses[::-1][:opts.limit_tweets]:
search_term_used = "mentions"
message = {
"type": "stream",
"to": [opts.stream],
"subject": search_term_used,
"content": url,
"type": "stream",
"to": [opts.stream],
"subject": search_term_used,
"content": url,
}
ret = client.send_message(message)
@@ -186,6 +189,6 @@ for status in statuses[::-1][:opts.limit_tweets]:
print("Error sending message to zulip: %s" % ret['msg'])
break
else:
since_id = status.GetId()
since_id = status.id
write_config(config, since_id)

34
api/setup.py Normal file → Executable file
View File

@@ -2,7 +2,8 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
if False: from typing import Any, Generator, List, Tuple
if False:
from typing import Any, Generator, List, Tuple
import os
import sys
@@ -14,7 +15,7 @@ def version():
version_py = os.path.join(os.path.dirname(__file__), "zulip", "__init__.py")
with open(version_py) as in_handle:
version_line = next(itertools.dropwhile(lambda x: not x.startswith("__version__"),
in_handle))
in_handle))
version = version_line.split('=')[-1].strip().replace('"', '')
return version
@@ -30,7 +31,7 @@ package_info = dict(
name='zulip',
version=version(),
description='Bindings for the Zulip message API',
author='Zulip, Inc.',
author='Zulip Open Source Project',
author_email='zulip-devel@googlegroups.com',
classifiers=[
'Development Status :: 3 - Alpha',
@@ -39,13 +40,22 @@ package_info = dict(
'License :: OSI Approved :: MIT License',
'Topic :: Communications :: Chat',
],
url='https://www.zulip.com/dist/api/',
url='https://www.zulip.org/dist/api/',
packages=['zulip'],
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/recent-messages"])] + \
list(recur_expand('share/zulip', 'integrations/')),
data_files=[('share/zulip/examples',
["examples/zuliprc",
"examples/create-user",
"examples/edit-message",
"examples/get-public-streams",
"examples/list-members",
"examples/list-subscriptions",
"examples/print-events",
"examples/print-messages",
"examples/recent-messages",
"examples/send-message",
"examples/subscribe",
"examples/unsubscribe",
])] + list(recur_expand('share/zulip', 'integrations/')),
scripts=["bin/zulip-send"],
) # type: Dict[str, Any]
@@ -53,8 +63,8 @@ setuptools_info = dict(
install_requires=['requests>=0.12.1',
'simplejson',
'six',
'typing',
],
'typing>=3.5.2.2',
],
)
try:
@@ -71,7 +81,7 @@ except ImportError:
sys.exit(1)
try:
import requests
assert(LooseVersion(requests.__version__) >= LooseVersion('0.12.1')) # type: ignore # https://github.com/JukkaL/mypy/issues/1165
assert(LooseVersion(requests.__version__) >= LooseVersion('0.12.1'))
except (ImportError, AssertionError):
print("requests >=0.12.1 is not installed", file=sys.stderr)
sys.exit(1)

View File

@@ -38,8 +38,7 @@ from six.moves.configparser import SafeConfigParser
from six.moves import urllib
import logging
import six
from typing import Any, Dict
from typing import Any, Callable, Dict, Iterable, IO, Mapping, Optional, Text, Tuple, Union
__version__ = "0.2.5"
@@ -47,7 +46,7 @@ logger = logging.getLogger(__name__)
# Check that we have a recent enough version
# Older versions don't provide the 'json' attribute on responses.
assert(LooseVersion(requests.__version__) >= LooseVersion('0.12.1')) # type: ignore # https://github.com/python/mypy/issues/1165 and https://github.com/python/typeshed/pull/206
assert(LooseVersion(requests.__version__) >= LooseVersion('0.12.1'))
# In newer versions, the 'json' attribute is a function, not a property
requests_json_is_function = callable(requests.Response.json)
@@ -55,33 +54,39 @@ API_VERSTRING = "v1/"
class CountingBackoff(object):
def __init__(self, maximum_retries=10, timeout_success_equivalent=None):
# type: (int, Optional[float]) -> None
self.number_of_retries = 0
self.maximum_retries = maximum_retries
self.timeout_success_equivalent = timeout_success_equivalent
self.last_attempt_time = 0
self.last_attempt_time = 0.0
def keep_going(self):
# type: () -> bool
self._check_success_timeout()
return self.number_of_retries < self.maximum_retries
def succeed(self):
# type: () -> None
self.number_of_retries = 0
self.last_attempt_time = time.time()
def fail(self):
# type: () -> None
self._check_success_timeout()
self.number_of_retries = min(self.number_of_retries + 1,
self.maximum_retries)
self.last_attempt_time = time.time()
def _check_success_timeout(self):
if (self.timeout_success_equivalent is not None
and self.last_attempt_time != 0
and time.time() - self.last_attempt_time > self.timeout_success_equivalent):
# type: () -> None
if (self.timeout_success_equivalent is not None and
self.last_attempt_time != 0 and
time.time() - self.last_attempt_time > self.timeout_success_equivalent):
self.number_of_retries = 0
class RandomExponentialBackoff(CountingBackoff):
def fail(self):
# type: () -> None
super(RandomExponentialBackoff, self).fail()
# Exponential growth with ratio sqrt(2); compute random delay
# between x and 2x where x is growing exponentially
@@ -95,9 +100,11 @@ class RandomExponentialBackoff(CountingBackoff):
time.sleep(delay)
def _default_client():
# type: () -> str
return "ZulipPython/" + __version__
def generate_option_group(parser, prefix=''):
# type: (optparse.OptionParser, str) -> optparse.OptionGroup
group = optparse.OptionGroup(parser, 'Zulip API configuration')
group.add_option('--%ssite' % (prefix,),
dest="zulip_site",
@@ -148,6 +155,7 @@ def generate_option_group(parser, prefix=''):
return group
def init_from_options(options, client=None):
# type: (Any, Optional[str]) -> Client
if options.zulip_client is not None:
client = options.zulip_client
elif client is None:
@@ -160,9 +168,10 @@ def init_from_options(options, client=None):
client_cert_key=options.client_cert_key)
def get_default_config_filename():
# type: () -> str
config_file = os.path.join(os.environ["HOME"], ".zuliprc")
if (not os.path.exists(config_file) and
os.path.exists(os.path.join(os.environ["HOME"], ".humbugrc"))):
os.path.exists(os.path.join(os.environ["HOME"], ".humbugrc"))):
raise RuntimeError("The Zulip API configuration file is now ~/.zuliprc; please run:\n\n"
" mv ~/.humbugrc ~/.zuliprc\n")
return config_file
@@ -173,6 +182,7 @@ class Client(object):
site=None, client=None,
cert_bundle=None, insecure=None,
client_cert=None, client_cert_key=None):
# type: (Optional[str], Optional[str], Optional[str], bool, bool, Optional[str], Optional[str], Optional[str], bool, Optional[str], Optional[str]) -> None
if client is None:
client = _default_client()
@@ -213,47 +223,50 @@ class Client(object):
self.email = email
self.verbose = verbose
if site is not None:
if not site.startswith("http"):
if site.startswith("localhost"):
site = "http://" + site
elif not site.startswith("http"):
site = "https://" + site
# Remove trailing "/"s from site to simplify the below logic for adding "/api"
site = site.rstrip("/")
self.base_url = site
else:
self.base_url = "https://api.zulip.com"
raise RuntimeError("Missing Zulip server URL; specify via --site or ~/.zuliprc.")
if self.base_url != "https://api.zulip.com" and not self.base_url.endswith("/api"):
if not self.base_url.endswith("/api"):
self.base_url += "/api"
self.base_url += "/"
self.retry_on_errors = retry_on_errors
self.client_name = client
if insecure:
self.tls_verification=False
self.tls_verification = False # type: Union[bool, str]
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
% (cert_bundle,))
self.tls_verification = cert_bundle
else:
# Default behavior: verify against system CA certificates
self.tls_verification=True
self.tls_verification = True
if client_cert is None:
if client_cert_key is not None:
raise RuntimeError("client cert key '%s' specified, but no client cert public part provided"
%(client_cert_key,))
% (client_cert_key,))
else: # we have a client cert
if not os.path.isfile(client_cert):
raise RuntimeError("client cert '%s' does not exist"
%(client_cert,))
% (client_cert,))
if client_cert_key is not None:
if not os.path.isfile(client_cert_key):
raise RuntimeError("client cert key '%s' does not exist"
%(client_cert_key,))
% (client_cert_key,))
self.client_cert = client_cert
self.client_cert_key = client_cert_key
def get_user_agent(self):
# type: () -> str
vendor = ''
vendor_version = ''
try:
@@ -272,20 +285,28 @@ class Client(object):
vendor_version = platform.mac_ver()[0]
return "{client_name} ({vendor}; {vendor_version})".format(
client_name=self.client_name,
vendor=vendor,
vendor_version=vendor_version,
)
client_name=self.client_name,
vendor=vendor,
vendor_version=vendor_version,
)
def do_api_query(self, orig_request, url, method="POST", longpolling=False, files=None):
# type: (Mapping[str, Any], str, str, bool, List[IO]) -> Dict[str, Any]
if files is None:
files = []
def do_api_query(self, orig_request, url, method="POST", longpolling = False):
request = {}
req_files = []
for (key, val) in six.iteritems(orig_request):
if isinstance(val, str) or isinstance(val, six.text_type):
if isinstance(val, str) or isinstance(val, Text):
request[key] = val
else:
request[key] = simplejson.dumps(val)
for f in files:
req_files.append((f.name, f))
query_state = {
'had_error_retry': False,
'request': request,
@@ -293,12 +314,13 @@ class Client(object):
} # type: Dict[str, Any]
def error_retry(error_string):
# type: (str) -> bool
if not self.retry_on_errors or query_state["failures"] >= 10:
return False
if self.verbose:
if not query_state["had_error_retry"]:
sys.stdout.write("zulip API(%s): connection error%s -- retrying." % \
(url.split(API_VERSTRING, 2)[0], error_string,))
sys.stdout.write("zulip API(%s): connection error%s -- retrying." %
(url.split(API_VERSTRING, 2)[0], error_string,))
query_state["had_error_retry"] = True
else:
sys.stdout.write(".")
@@ -309,6 +331,7 @@ class Client(object):
return True
def end_error_retry(succeeded):
# type: (bool) -> None
if query_state["had_error_retry"] and self.verbose:
if succeeded:
print("Success!")
@@ -321,24 +344,28 @@ class Client(object):
kwarg = "params"
else:
kwarg = "data"
kwargs = {kwarg: query_state["request"]}
if files:
kwargs['files'] = req_files
# Build a client cert object for requests
if self.client_cert_key is not None:
client_cert = (self.client_cert, self.client_cert_key)
client_cert = (self.client_cert, self.client_cert_key) # type: Union[str, Tuple[str, str]]
else:
client_cert = self.client_cert
res = requests.request(
method,
urllib.parse.urljoin(self.base_url, url),
auth=requests.auth.HTTPBasicAuth(self.email,
self.api_key),
verify=self.tls_verification,
cert=client_cert,
timeout=90,
headers={"User-agent": self.get_user_agent()},
**kwargs)
method,
urllib.parse.urljoin(self.base_url, url),
auth=requests.auth.HTTPBasicAuth(self.email,
self.api_key),
verify=self.tls_verification,
cert=client_cert,
timeout=90,
headers={"User-agent": self.get_user_agent()},
**kwargs)
# On 50x errors, try again after a short sleep
if str(res.status_code).startswith('5'):
@@ -350,7 +377,7 @@ class Client(object):
# want the later exception handlers to deal with any
# non-timeout other SSLErrors
if (isinstance(e, requests.exceptions.SSLError) and
str(e) != "The read operation timed out"):
str(e) != "The read operation timed out"):
raise
if longpolling:
# When longpolling, we expect the timeout to fire,
@@ -386,35 +413,24 @@ class Client(object):
return {'msg': "Unexpected error from the server", "result": "http-error",
"status_code": res.status_code}
@classmethod
def _register(cls, name, url=None, make_request=None,
method="POST", computed_url=None, **query_kwargs):
if url is None:
url = name
if make_request is None:
def make_request(request=None):
if request is None:
request = {}
return request
def call(self, *args, **kwargs):
request = make_request(*args, **kwargs)
if computed_url is not None:
req_url = computed_url(request)
else:
req_url = url
return self.do_api_query(request, API_VERSTRING + req_url, method=method, **query_kwargs)
call.__name__ = name
setattr(cls, name, call)
def call_endpoint(self, url=None, method="POST", request=None, longpolling=False, files=None):
# type: (str, str, Dict[str, Any], bool, List[IO]) -> Dict[str, Any]
if request is None:
request = dict()
return self.do_api_query(request, API_VERSTRING + url, method=method, files=files)
def call_on_each_event(self, callback, event_types=None, narrow=None):
# type: (Callable, Optional[List[str]], Any) -> None
if narrow is None:
narrow = []
def do_register():
# type: () -> Tuple[str, int]
while True:
if event_types is None:
res = self.register()
res = self.register() # type: ignore
else:
res = self.register(event_types=event_types, narrow=narrow)
res = self.register(event_types=event_types, narrow=narrow) # type: ignore
if 'error' in res.get('result'):
if self.verbose:
@@ -428,7 +444,7 @@ class Client(object):
if queue_id is None:
(queue_id, last_event_id) = do_register()
res = self.get_events(queue_id=queue_id, last_event_id=last_event_id)
res = self.get_events(queue_id=queue_id, last_event_id=last_event_id) # type: ignore
if 'error' in res.get('result'):
if res["result"] == "http-error":
if self.verbose:
@@ -459,32 +475,227 @@ class Client(object):
callback(event)
def call_on_each_message(self, callback):
# type: (Callable) -> None
def event_callback(event):
# type: (Dict[str, str]) -> None
if event['type'] == 'message':
callback(event['message'])
self.call_on_each_event(event_callback, ['message'])
def _mk_subs(streams, **kwargs):
result = kwargs
result['subscriptions'] = streams
return result
def send_message(self, message_data):
# type: (Dict[str, Any]) -> Dict[str, Any]
'''
See api/examples/send-message for example usage.
'''
return self.call_endpoint(
url='messages',
request=message_data,
)
def _mk_rm_subs(streams):
return {'delete': streams}
def upload_file(self, file):
# type: (IO) -> Dict[str, Any]
'''
See api/examples/upload-file for example usage.
'''
return self.call_endpoint(
url='user_uploads',
files=[file]
)
def _mk_deregister(queue_id):
return {'queue_id': queue_id}
def update_message(self, message_data):
# type: (Dict[str, Any]) -> Dict[str, Any]
'''
See api/examples/edit-message for example usage.
'''
return self.call_endpoint(
url='messages/%d' % (message_data['message_id'],),
method='PATCH',
request=message_data,
)
def _mk_events(event_types=None, narrow=None):
if event_types is None:
return dict()
if narrow is None:
narrow = []
return dict(event_types=event_types, narrow=narrow)
def get_events(self, **request):
# type: (**Any) -> Dict[str, Any]
'''
See the register() method for example usage.
'''
return self.call_endpoint(
url='events',
method='GET',
longpolling=True,
request=request,
)
def _kwargs_to_dict(**kwargs):
return kwargs
def register(self, event_types=None, narrow=None, **kwargs):
# type: (Iterable[str], Any, **Any) -> Dict[str, Any]
'''
Example usage:
>>> client.register(['message'])
{u'msg': u'', u'max_message_id': 112, u'last_event_id': -1, u'result': u'success', u'queue_id': u'1482093786:2'}
>>> client.get_events(queue_id='1482093786:2', last_event_id=0)
{...}
'''
if narrow is None:
narrow = []
request = dict(
event_types=event_types,
narrow=narrow,
**kwargs
)
return self.call_endpoint(
url='register',
request=request,
)
def deregister(self, queue_id):
# type: (str) -> Dict[str, Any]
'''
Example usage:
>>> client.register(['message'])
{u'msg': u'', u'max_message_id': 113, u'last_event_id': -1, u'result': u'success', u'queue_id': u'1482093786:3'}
>>> client.deregister('1482093786:3')
{u'msg': u'', u'result': u'success'}
'''
request = dict(queue_id=queue_id)
return self.call_endpoint(
url="events",
method="DELETE",
request=request,
)
def get_profile(self, request=None):
# type: (Dict[str, Any]) -> Dict[str, Any]
'''
Example usage:
>>> client.get_profile()
{u'user_id': 5, u'full_name': u'Iago', u'short_name': u'iago', ...}
'''
return self.call_endpoint(
url='users/me',
method='GET',
request=request,
)
def get_streams(self, **request):
# type: (**Any) -> Dict[str, Any]
'''
See api/examples/get-public-streams for example usage.
'''
return self.call_endpoint(
url='streams',
method='GET',
request=request,
)
def get_members(self, request=None):
# type: (Dict[str, Any]) -> Dict[str, Any]
'''
See api/examples/list-members for example usage.
'''
return self.call_endpoint(
url='users',
method='GET',
request=request,
)
def list_subscriptions(self, request=None):
# type: (Dict[str, Any]) -> Dict[str, Any]
'''
See api/examples/list-subscriptions for example usage.
'''
return self.call_endpoint(
url='users/me/subscriptions',
method='GET',
request=request,
)
def add_subscriptions(self, streams, **kwargs):
# type: (Iterable[Dict[str, Any]], **Any) -> Dict[str, Any]
'''
See api/examples/subscribe for example usage.
'''
request = dict(
subscriptions=streams,
**kwargs
)
return self.call_endpoint(
url='users/me/subscriptions',
request=request,
)
def remove_subscriptions(self, streams):
# type: (Iterable[str]) -> Dict[str, Any]
'''
See api/examples/unsubscribe for example usage.
'''
request = dict(delete=streams)
return self.call_endpoint(
url='users/me/subscriptions',
method='PATCH',
request=request,
)
def get_stream_id(self, stream):
# type: (str) -> Dict[str, Any]
'''
Example usage: client.get_stream_id('devel')
'''
stream_encoded = urllib.parse.quote(stream, safe='')
url = 'get_stream_id?stream=%s' % (stream_encoded,)
return self.call_endpoint(
url=url,
method='GET',
request=None,
)
def get_subscribers(self, **request):
# type: (**Any) -> Dict[str, Any]
'''
Example usage: client.get_subscribers(stream='devel')
'''
response = self.get_stream_id(request['stream'])
if response['result'] == 'error':
return response
stream_id = response['stream_id']
url = 'streams/%d/members' % (stream_id,)
return self.call_endpoint(
url=url,
method='GET',
request=request,
)
def render_message(self, request=None):
# type: (Dict[str, Any]) -> Dict[str, Any]
'''
Example usage:
>>> client.render_message(request=dict(content='foo **bar**'))
{u'msg': u'', u'rendered': u'<p>foo <strong>bar</strong></p>', u'result': u'success'}
'''
return self.call_endpoint(
url='messages/render',
method='POST',
request=request,
)
def create_user(self, request=None):
# type: (Dict[str, Any]) -> Dict[str, Any]
'''
See api/examples/create-user for example usage.
'''
return self.call_endpoint(
method='POST',
url='users',
request=request,
)
class ZulipStream(object):
"""
@@ -492,36 +703,20 @@ class ZulipStream(object):
"""
def __init__(self, type, to, subject, **kwargs):
# type: (str, str, str, **Any) -> None
self.client = Client(**kwargs)
self.type = type
self.to = to
self.subject = subject
def write(self, content):
# type: (str) -> None
message = {"type": self.type,
"to": self.to,
"subject": self.subject,
"content": content}
self.client.send_message(message)
self.client.send_message(message) # type: ignore
def flush(self):
# type: () -> None
pass
Client._register('send_message', url='messages', make_request=(lambda request: request))
Client._register('update_message', method='PATCH', url='messages', make_request=(lambda request: request))
Client._register('get_messages', method='GET', url='messages/latest', longpolling=True)
Client._register('get_events', url='events', method='GET', longpolling=True, make_request=(lambda **kwargs: kwargs))
Client._register('register', make_request=_mk_events)
Client._register('export', method='GET', url='export')
Client._register('deregister', url="events", method="DELETE", make_request=_mk_deregister)
Client._register('get_profile', method='GET', url='users/me')
Client._register('get_streams', method='GET', url='streams', make_request=_kwargs_to_dict)
Client._register('get_members', method='GET', url='users')
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.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

@@ -11,6 +11,9 @@ import subprocess
import hashlib
from six.moves import range
if False:
from typing import Any, Dict, List, Set, Tuple
parser = optparse.OptionParser()
parser.add_option('--verbose',
dest='verbose',
@@ -73,32 +76,34 @@ if options.sharded:
("message", "p"),
("tabbott-nagios-test-32", "0"),
("tabbott-nagios-test-33", "1"),
("tabbott-nagios-test-2", "2"),
("tabbott-nagios-test-5", "3"),
("tabbott-nagios-test-2", "2"),
("tabbott-nagios-test-5", "3"),
("tabbott-nagios-test-13", "4"),
("tabbott-nagios-test-7", "5"),
("tabbott-nagios-test-7", "5"),
("tabbott-nagios-test-22", "6"),
("tabbott-nagios-test-35", "7"),
("tabbott-nagios-test-4", "8"),
("tabbott-nagios-test-3", "9"),
("tabbott-nagios-test-1", "a"),
("tabbott-nagios-test-4", "8"),
("tabbott-nagios-test-3", "9"),
("tabbott-nagios-test-1", "a"),
("tabbott-nagios-test-49", "b"),
("tabbott-nagios-test-34", "c"),
("tabbott-nagios-test-12", "d"),
("tabbott-nagios-test-11", "e"),
("tabbott-nagios-test-9", "f"),
]
("tabbott-nagios-test-9", "f"),
]
for (stream, test) in test_streams:
if stream == "message":
continue
assert(hashlib.sha1(stream).hexdigest().startswith(test))
assert(hashlib.sha1(stream.encode("utf-8")).hexdigest().startswith(test))
else:
test_streams = [
("message", "p"),
("tabbott-nagios-test", "a"),
]
]
def print_status_and_exit(status):
# type: (int) -> None
# The output of this script is used by Nagios. Various outputs,
# 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
@@ -107,15 +112,17 @@ def print_status_and_exit(status):
sys.exit(status)
def send_zulip(message):
# type: (Dict[str, str]) -> None
result = zulip_client.send_message(message)
if result["result"] != "success":
logger.error("Error sending zulip, args were:")
logger.error(message)
logger.error(result)
logger.error(str(message))
logger.error(str(result))
print_status_and_exit(1)
# Returns True if and only if we "Detected server failure" sending the zephyr.
def send_zephyr(zwrite_args, content):
# type: (List[str], str) -> bool
p = subprocess.Popen(zwrite_args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate(input=content.encode("utf-8"))
@@ -167,7 +174,7 @@ for tries in range(10):
actually_subscribed = True
break
except IOError as e:
if "SERVNAK received" in e:
if "SERVNAK received" in e: # type: ignore # https://github.com/python/mypy/issues/2118
logger.error("SERVNAK repeatedly received, punting rest of test")
else:
logger.exception("Exception subscribing to zephyrs")
@@ -177,9 +184,10 @@ if not actually_subscribed:
print_status_and_exit(1)
# Prepare keys
zhkeys = {}
hzkeys = {}
zhkeys = {} # type: Dict[str, Tuple[str, str]]
hzkeys = {} # type: Dict[str, Tuple[str, str]]
def gen_key(key_dict):
# type: (Dict[str, Any]) -> str
bits = str(random.getrandbits(32))
while bits in key_dict:
# Avoid the unlikely event that we get the same bits twice
@@ -187,6 +195,7 @@ def gen_key(key_dict):
return bits
def gen_keys(key_dict):
# type: (Dict[str, Tuple[str, str]]) -> None
for (stream, test) in test_streams:
key_dict[gen_key(key_dict)] = (stream, test)
@@ -199,6 +208,7 @@ notices = []
# receive queue with 30+ messages, which might result in messages
# being dropped.
def receive_zephyrs():
# type: () -> None
while True:
try:
notice = zephyr.receive(block=False)
@@ -242,17 +252,17 @@ logger.info("Sent Zephyr messages!")
for key, (stream, test) in hzkeys.items():
if stream == "message":
send_zulip({
"type": "private",
"content": str(key),
"to": zulip_user,
"type": "private",
"content": str(key),
"to": zulip_user,
})
else:
send_zulip({
"type": "stream",
"subject": "test",
"content": str(key),
"to": stream,
})
"type": "stream",
"subject": "test",
"content": str(key),
"to": stream,
})
receive_zephyrs()
logger.info("Sent Zulip messages!")
@@ -281,10 +291,12 @@ logger.info("Finished receiving Zephyr messages!")
all_keys = set(list(zhkeys.keys()) + list(hzkeys.keys()))
def process_keys(content_list):
# type: (List[str]) -> Tuple[Dict[str, int], Set[str], Set[str], bool, bool]
# Start by filtering out any keys that might have come from
# concurrent check-mirroring processes
content_keys = [key for key in content_list if key in all_keys]
key_counts = {}
key_counts = {} # type: Dict[str, int]
for key in all_keys:
key_counts[key] = 0
for key in content_keys:
@@ -316,12 +328,12 @@ for key in all_keys:
continue
if key in zhkeys:
(stream, test) = zhkeys[key]
logger.warning("%10s: z got %s, h got %s. Sent via Zephyr(%s): class %s" % \
(key, z_key_counts[key], h_key_counts[key], test, stream))
logger.warning("%10s: z got %s, h got %s. Sent via Zephyr(%s): class %s" %
(key, z_key_counts[key], h_key_counts[key], test, stream))
if key in hzkeys:
(stream, test) = hzkeys[key]
logger.warning("%10s: z got %s. h got %s. Sent via Zulip(%s): class %s" % \
(key, z_key_counts[key], h_key_counts[key], test, stream))
logger.warning("%10s: z got %s. h got %s. Sent via Zulip(%s): class %s" %
(key, z_key_counts[key], h_key_counts[key], test, stream))
logger.error("")
logger.error("Summary of specific problems:")

View File

@@ -1,132 +0,0 @@
#!/usr/bin/env python
from __future__ import print_function
import sys
import time
import datetime
import optparse
from six.moves import urllib
import itertools
import traceback
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '../api'))
import zulip
parser = optparse.OptionParser(r"""
%prog \
--user foo@zulip.com \
--calendar http://www.google.com/calendar/feeds/foo%40zulip.com/private-fedcba9876543210fedcba9876543210/basic
Send yourself reminders on Zulip of Google Calendar events.
To get the calendar URL:
- Load Google Calendar in a web browser
- Find your calendar in the "My calendars" list on the left
- Click the down-wedge icon that appears on mouseover, and select "Calendar settings"
- Copy the link address for the "XML" button under "Private Address"
Run this on your personal machine. Your API key and calendar URL are revealed to local
users through the command line.
Depends on: python-gdata
""")
parser.add_option('--calendar',
dest='calendar',
action='store',
help='Google Calendar XML "Private Address"',
metavar='URL')
parser.add_option('--interval',
dest='interval',
default=10,
type=int,
action='store',
help='Minutes before event for reminder [default: 10]',
metavar='MINUTES')
parser.add_option_group(zulip.generate_option_group(parser))
(options, args) = parser.parse_args()
if not (options.zulip_email and options.calendar):
parser.error('You must specify --user and --calendar')
try:
from gdata.calendar.client import CalendarClient
except ImportError:
parser.error('Install python-gdata')
def get_calendar_url():
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 urllib.parse.urlunparse((parts.scheme, parts.netloc, pat[0] + '/full',
'', 'futureevents=true&orderby=startdate', ''))
calendar_url = get_calendar_url()
client = zulip.init_from_options(options)
def get_events():
feed = CalendarClient().GetCalendarEventFeed(uri=calendar_url)
for event in feed.entry:
start = event.when[0].start.split('.')[0]
# All-day events can have only a date
fmt = '%Y-%m-%dT%H:%M:%S' if 'T' in start else '%Y-%m-%d'
start = datetime.datetime.strptime(start, fmt)
yield (event.uid.value, start, event.title.text)
# Our cached view of the calendar, updated periodically.
events = []
# Unique keys for events we've already sent, so we don't remind twice.
sent = set()
def send_reminders():
global sent
messages = []
keys = set()
now = datetime.datetime.now()
for uid, start, title in events:
dt = start - now
if dt.days == 0 and dt.seconds < 60*options.interval:
# The unique key includes the start time, because of
# repeating events.
key = (uid, start)
if key not in sent:
line = '%s starts at %s' % (title, start.strftime('%H:%M'))
print('Sending reminder:', line)
messages.append(line)
keys.add(key)
if not messages:
return
if len(messages) == 1:
message = 'Reminder: ' + messages[0]
else:
message = 'Reminder:\n\n' + '\n'.join('* ' + m for m in messages)
client.send_message(dict(
type = 'private',
to = options.user,
content = message))
sent |= keys
# Loop forever
for i in itertools.count():
try:
# We check reminders every minute, but only
# download the calendar every 10 minutes.
if not i % 10:
events = list(get_events())
send_reminders()
except:
traceback.print_exc()
time.sleep(60)

47
bots/irc-mirror.py Normal file → Executable file
View File

@@ -4,32 +4,41 @@
# IRC <=> Zulip mirroring bot
#
# Setup: First, you need to install python-irc version 8.5.3
# (https://bitbucket.org/jaraco/irc)
# (https://github.com/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
from irc.client import ip_numstr_to_quad, ip_quad_to_numstr, Event, ServerConnection
import zulip
import optparse
if False:
from typing import Any
IRC_DOMAIN = "irc.example.com"
def zulip_sender(sender_string):
# type: (str) -> str
nick = sender_string.split("!")[0]
return nick + "@" + IRC_DOMAIN
class IRCBot(irc.bot.SingleServerIRCBot):
def __init__(self, channel, nickname, server, port=6667):
# type: (irc.bot.Channel, str, str, int) -> None
irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
self.channel = channel
self.channel = channel # type: irc.bot.Channel
def on_nicknameinuse(self, c, e):
# type: (ServerConnection, Event) -> None
c.nick(c.get_nickname().replace("_zulip", "__zulip"))
def on_welcome(self, c, e):
# type: (ServerConnection, Event) -> None
c.join(self.channel)
def forward_to_irc(msg):
# type: (Dict[str, Any]) -> None
if msg["type"] == "stream":
send = lambda x: c.privmsg(msg["display_recipient"], x)
else:
@@ -48,6 +57,7 @@ class IRCBot(irc.bot.SingleServerIRCBot):
# zulip_client.call_on_each_message(forward_to_irc)
def on_privmsg(self, c, e):
# type: (ServerConnection, Event) -> None
content = e.arguments[0]
sender = zulip_sender(e.source)
if sender.endswith("_zulip@" + IRC_DOMAIN):
@@ -55,13 +65,14 @@ class IRCBot(irc.bot.SingleServerIRCBot):
# Forward the PM to Zulip
print(zulip_client.send_message({
"sender": sender,
"type": "private",
"to": "username@example.com",
"content": content,
}))
"sender": sender,
"type": "private",
"to": "username@example.com",
"content": content,
}))
def on_pubmsg(self, c, e):
# type: (ServerConnection, Event) -> None
content = e.arguments[0]
stream = e.target
sender = zulip_sender(e.source)
@@ -70,18 +81,20 @@ class IRCBot(irc.bot.SingleServerIRCBot):
# Forward the stream message to Zulip
print(zulip_client.send_message({
"forged": "yes",
"sender": sender,
"type": "stream",
"to": stream,
"subject": "IRC",
"content": content,
}))
"forged": "yes",
"sender": sender,
"type": "stream",
"to": stream,
"subject": "IRC",
"content": content,
}))
def on_dccmsg(self, c, e):
# type: (ServerConnection, Event) -> None
c.privmsg("You said: " + e.arguments[0])
def on_dccchat(self, c, e):
# type: (ServerConnection, Event) -> None
if len(e.arguments) != 2:
return
args = e.arguments[1].split()
@@ -93,11 +106,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 = """./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
./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

@@ -46,7 +46,7 @@ while backoff.keep_going():
print("Starting Jabber mirroring bot")
try:
ret = subprocess.call(args)
except:
except Exception:
traceback.print_exc()
else:
if ret == 2:

View File

@@ -44,35 +44,46 @@ import threading
import optparse
from sleekxmpp import ClientXMPP, InvalidJID, JID
from sleekxmpp.stanza import Message as JabberMessage
from sleekxmpp.exceptions import IqError, IqTimeout
from six.moves.configparser import SafeConfigParser
import os, sys, zulip, getpass
import getpass
import os
import sys
import zulip
from zulip import Client
import re
from typing import Any, Callable
__version__ = "1.1"
def room_to_stream(room):
# type: (str) -> str
return room + "/xmpp"
def stream_to_room(stream):
# type: (str) -> str
return stream.lower().rpartition("/xmpp")[0]
def jid_to_zulip(jid):
# type: (JID) -> str
suffix = ''
if not jid.username.endswith("-bot"):
suffix = options.zulip_email_suffix
return "%s%s@%s" % (jid.username, suffix, options.zulip_domain)
def zulip_to_jid(email, jabber_domain):
# type: (str, str) -> JID
jid = JID(email, domain=jabber_domain)
if (options.zulip_email_suffix
and options.zulip_email_suffix in jid.username
and not jid.username.endswith("-bot")):
if (options.zulip_email_suffix and
options.zulip_email_suffix in jid.username and
not jid.username.endswith("-bot")):
jid.username = jid.username.rpartition(options.zulip_email_suffix)[0]
return jid
class JabberToZulipBot(ClientXMPP):
def __init__(self, jid, password, rooms):
# type: (JID, str, List[str]) -> None
if jid.resource:
self.nick = jid.resource
else:
@@ -83,22 +94,25 @@ class JabberToZulipBot(ClientXMPP):
self.rooms_to_join = rooms
self.add_event_handler("session_start", self.session_start)
self.add_event_handler("message", self.message)
self.zulip = None # type: zulip.Client
self.zulip = None # type: Client
self.use_ipv6 = False
self.register_plugin('xep_0045') # Jabber chatrooms
self.register_plugin('xep_0199') # XMPP Ping
def set_zulip_client(self, client):
self.zulip = client
def set_zulip_client(self, zulipToJabberClient):
# type: (ZulipToJabberBot) -> None
self.zulipToJabber = zulipToJabberClient
def session_start(self, event):
# type: (Dict[str, Any]) -> None
self.get_roster()
self.send_presence()
for room in self.rooms_to_join:
self.join_muc(room)
def join_muc(self, room):
# type: (str) -> None
if room in self.rooms:
return
logging.debug("Joining " + room)
@@ -124,6 +138,7 @@ class JabberToZulipBot(ClientXMPP):
logging.error("Could not configure room: " + str(muc_jid))
def leave_muc(self, room):
# type: (str) -> None
if room not in self.rooms:
return
logging.debug("Leaving " + room)
@@ -132,6 +147,7 @@ class JabberToZulipBot(ClientXMPP):
self.plugin['xep_0045'].leaveMUC(muc_jid, self.nick)
def message(self, msg):
# type: (JabberMessage) -> Any
try:
if msg["type"] == "groupchat":
return self.group(msg)
@@ -144,6 +160,7 @@ class JabberToZulipBot(ClientXMPP):
logging.exception("Error forwarding Jabber => Zulip")
def private(self, msg):
# type: (JabberMessage) -> None
if options.mode == 'public' or msg['thread'] == u'\u1FFFE':
return
sender = jid_to_zulip(msg["from"])
@@ -154,12 +171,13 @@ class JabberToZulipBot(ClientXMPP):
type = "private",
to = recipient,
content = msg["body"],
)
ret = self.zulip.client.send_message(zulip_message)
)
ret = self.zulipToJabber.client.send_message(zulip_message)
if ret.get("result") != "success":
logging.error(ret)
logging.error(str(ret))
def group(self, msg):
# type: (JabberMessage) -> None
if options.mode == 'personal' or msg["thread"] == u'\u1FFFE':
return
@@ -181,12 +199,13 @@ class JabberToZulipBot(ClientXMPP):
subject = subject,
to = stream,
content = msg["body"],
)
ret = self.zulip.client.send_message(zulip_message)
)
ret = self.zulipToJabber.client.send_message(zulip_message)
if ret.get("result") != "success":
logging.error(ret)
logging.error(str(ret))
def nickname_to_jid(self, room, nick):
# type: (str, str) -> JID
jid = self.plugin['xep_0045'].getJidProperty(room, nick, "jid")
if (jid is None or jid == ''):
return JID(local=nick.replace(' ', ''), domain=self.boundjid.domain)
@@ -195,13 +214,16 @@ class JabberToZulipBot(ClientXMPP):
class ZulipToJabberBot(object):
def __init__(self, zulip_client):
# type: (Client) -> None
self.client = zulip_client
self.jabber = None # type: JabberToZulipBot
def set_jabber_client(self, client):
# type: (JabberToZulipBot) -> None
self.jabber = client
def process_event(self, event):
# type: (Dict[str, Any]) -> None
if event['type'] == 'message':
message = event["message"]
if message['sender_email'] != self.client.email:
@@ -220,6 +242,7 @@ class ZulipToJabberBot(object):
self.process_stream(event)
def stream_message(self, msg):
# type: (Dict[str, str]) -> None
stream = msg['display_recipient']
if not stream.endswith("/xmpp"):
return
@@ -234,6 +257,7 @@ class ZulipToJabberBot(object):
outgoing.send()
def private_message(self, msg):
# type: (Dict[str, Any]) -> None
for recipient in msg['display_recipient']:
if recipient["email"] == self.client.email:
continue
@@ -249,6 +273,7 @@ class ZulipToJabberBot(object):
outgoing.send()
def process_subscription(self, event):
# type: (Dict[str, Any]) -> None
if event['op'] == 'add':
streams = [s['name'].lower() for s in event['subscriptions']]
streams = [s for s in streams if s.endswith("/xmpp")]
@@ -261,6 +286,7 @@ class ZulipToJabberBot(object):
self.jabber.leave_muc(stream_to_room(stream))
def process_stream(self, event):
# type: (Dict[str, Any]) -> None
if event['op'] == 'occupy':
streams = [s['name'].lower() for s in event['streams']]
streams = [s for s in streams if s.endswith("/xmpp")]
@@ -272,8 +298,10 @@ class ZulipToJabberBot(object):
for stream in streams:
self.jabber.leave_muc(stream_to_room(stream))
def get_rooms(zulip):
def get_rooms(zulipToJabber):
# type: (ZulipToJabberBot) -> List[str]
def get_stream_infos(key, method):
# type: (str, Callable) -> Any
ret = method()
if ret.get("result") != "success":
logging.error(ret)
@@ -281,11 +309,11 @@ def get_rooms(zulip):
return ret[key]
if options.mode == 'public':
stream_infos = get_stream_infos("streams", zulip.client.get_streams)
stream_infos = get_stream_infos("streams", zulipToJabber.client.get_streams)
else:
stream_infos = get_stream_infos("subscriptions", zulip.client.list_subscriptions)
stream_infos = get_stream_infos("subscriptions", zulipToJabber.client.list_subscriptions)
rooms = []
rooms = [] # type: List[str]
for stream_info in stream_infos:
stream = stream_info['name']
if stream.endswith("/xmpp"):
@@ -293,32 +321,33 @@ def get_rooms(zulip):
return rooms
def config_error(msg):
# type: (str) -> None
sys.stderr.write("%s\n" % (msg,))
sys.exit(2)
if __name__ == '__main__':
parser = optparse.OptionParser(epilog=
'''Most general and Jabber configuration options may also be specified in the
parser = optparse.OptionParser(
epilog='''Most general and Jabber configuration options may also be specified in the
zulip configuration file under the jabber_mirror section (exceptions are noted
in their help sections). Keys have the same name as options with hyphens
replaced with underscores. Zulip configuration options go in the api section,
as normal.'''.replace("\n", " ")
)
parser.add_option('--mode',
default=None,
action='store',
help= \
'''Which mode to run in. Valid options are "personal" and "public". In
)
parser.add_option(
'--mode',
default=None,
action='store',
help='''Which mode to run in. Valid options are "personal" and "public". In
"personal" mode, the mirror uses an individual users' credentials and mirrors
all messages they send on Zulip to Jabber and all private Jabber messages to
Zulip. In "public" mode, the mirror uses the credentials for a dedicated mirror
user and mirrors messages sent to Jabber rooms to Zulip. Defaults to
"personal"'''.replace("\n", " "))
parser.add_option('--zulip-email-suffix',
default=None,
action='store',
help= \
'''Add the specified suffix to the local part of email addresses constructed
parser.add_option(
'--zulip-email-suffix',
default=None,
action='store',
help='''Add the specified suffix to the local part of email addresses constructed
from JIDs and nicks before sending requests to the Zulip server, and remove the
suffix before sending requests to the Jabber server. For example, specifying
"+foo" will cause messages that are sent to the "bar" room by nickname "qux" to
@@ -332,14 +361,15 @@ option does not affect login credentials.'''.replace("\n", " "))
default=logging.INFO)
jabber_group = optparse.OptionGroup(parser, "Jabber configuration")
jabber_group.add_option('--jid',
default=None,
action='store',
help="Your Jabber JID. If a resource is specified, "
+ "it will be used as the nickname when joining MUCs. "
+ "Specifying the nickname is mostly useful if you want "
+ "to run the public mirror from a regular user instead of "
+ "from a dedicated account.")
jabber_group.add_option(
'--jid',
default=None,
action='store',
help="Your Jabber JID. If a resource is specified, "
"it will be used as the nickname when joining MUCs. "
"Specifying the nickname is mostly useful if you want "
"to run the public mirror from a regular user instead of "
"from a dedicated account.")
jabber_group.add_option('--jabber-password',
default=None,
action='store',
@@ -348,19 +378,19 @@ option does not affect login credentials.'''.replace("\n", " "))
default=None,
action='store',
help="Your Jabber conference domain (E.g. conference.jabber.example.com). "
+ "If not specifed, \"conference.\" will be prepended to your JID's domain.")
"If not specifed, \"conference.\" will be prepended to your JID's domain.")
jabber_group.add_option('--no-use-tls',
default=None,
action='store_true')
jabber_group.add_option('--jabber-server-address',
default=None,
action='store',
help="The hostname of your Jabber server. This is only needed if "
help="The hostname of your Jabber server. This is only needed if "
"your server is missing SRV records")
jabber_group.add_option('--jabber-server-port',
default='5222',
action='store',
help="The port of your Jabber server. This is only needed if "
help="The port of your Jabber server. This is only needed if "
"your server is missing SRV records")
parser.add_option_group(jabber_group)
@@ -383,8 +413,8 @@ option does not affect login credentials.'''.replace("\n", " "))
pass
for option in ("jid", "jabber_password", "conference_domain", "mode", "zulip_email_suffix",
"jabber_server_address", "jabber_server_port"):
if (getattr(options, option) is None
and config.has_option("jabber_mirror", option)):
if (getattr(options, option) is None and
config.has_option("jabber_mirror", option)):
setattr(options, option, config.get("jabber_mirror", option))
for option in ("no_use_tls",):
@@ -405,11 +435,11 @@ option does not affect login credentials.'''.replace("\n", " "))
if None in (options.jid, options.jabber_password):
config_error("You must specify your Jabber JID and Jabber password either "
+ "in the Zulip configuration file or on the commandline")
"in the Zulip configuration file or on the commandline")
zulip = ZulipToJabberBot(zulip.init_from_options(options, "JabberMirror/" + __version__))
zulipToJabber = ZulipToJabberBot(zulip.init_from_options(options, "JabberMirror/" + __version__))
# This won't work for open realms that don't have a consistent domain
options.zulip_domain = zulip.client.email.partition('@')[-1]
options.zulip_domain = zulipToJabber.client.email.partition('@')[-1]
try:
jid = JID(options.jid)
@@ -419,7 +449,7 @@ option does not affect login credentials.'''.replace("\n", " "))
if options.conference_domain is None:
options.conference_domain = "conference.%s" % (jid.domain,)
xmpp = JabberToZulipBot(jid, options.jabber_password, get_rooms(zulip))
xmpp = JabberToZulipBot(jid, options.jabber_password, get_rooms(zulipToJabber))
address = None
if options.jabber_server_address:
@@ -428,8 +458,8 @@ option does not affect login credentials.'''.replace("\n", " "))
if not xmpp.connect(use_tls=not options.no_use_tls, address=address):
sys.exit("Unable to connect to Jabber server")
xmpp.set_zulip_client(zulip)
zulip.set_jabber_client(xmpp)
xmpp.set_zulip_client(zulipToJabber)
zulipToJabber.set_jabber_client(xmpp)
xmpp.process(block=False)
if options.mode == 'public':
@@ -439,8 +469,8 @@ option does not affect login credentials.'''.replace("\n", " "))
try:
logging.info("Connecting to Zulip.")
zulip.client.call_on_each_event(zulip.process_event,
event_types=event_types)
zulipToJabber.client.call_on_each_event(zulipToJabber.process_event,
event_types=event_types)
except BaseException as e:
logging.exception("Exception in main loop")
xmpp.abort()

View File

@@ -27,6 +27,7 @@ lock_path = "/var/tmp/log2zulip.lock"
control_path = "/etc/log2zulip.conf"
def mkdir_p(path):
# type: (str) -> None
# Python doesn't have an analog to `mkdir -p` < Python 3.2.
try:
os.makedirs(path)
@@ -37,15 +38,17 @@ def mkdir_p(path):
raise
def send_log_zulip(file_name, count, lines, extra=""):
# type: (str, int, List[str], str) -> None
content = "%s new errors%s:\n```\n%s\n```" % (count, extra, "\n".join(lines))
zulip_client.send_message({
"type": "stream",
"to": "logs",
"subject": "%s on %s" % (file_name, platform.node()),
"content": content,
})
})
def process_lines(raw_lines, file_name):
# type: (List[str], str) -> None
lines = []
for line in raw_lines:
# Add any filtering or modification code here
@@ -61,6 +64,7 @@ def process_lines(raw_lines, file_name):
send_log_zulip(file_name, len(lines), lines)
def process_logs():
# type: () -> None
for filename in log_files:
data_file_path = "/var/tmp/log2zulip.state"
mkdir_p(os.path.dirname(data_file_path))
@@ -110,4 +114,3 @@ if __name__ == "__main__":
os.remove(lock_path)
except OSError as IOError:
pass

View File

@@ -7,8 +7,9 @@ import zulip
import re
import collections
def get_recent_messages(client, narrow, count=100):
narrow = [word.split(':') for word in narrow.split()]
def get_recent_messages(client, narrow_str, count=100):
# type: (zulip.Client, str, int) -> List[Dict[str, Any]]
narrow = [word.split(':') for word in narrow_str.split()]
req = {
'narrow': narrow,
'num_before': count,
@@ -22,6 +23,7 @@ def get_recent_messages(client, narrow, count=100):
return old_messages['messages']
def get_words(content):
# type: (str) -> List[str]
regex = "[A-Z]{2,}(?![a-z])|[A-Z][a-z]+(?=[A-Z])|[\'\w\-]+"
words = re.findall(regex, content, re.M)
words = [w.lower() for w in words]
@@ -29,6 +31,7 @@ def get_words(content):
return words
def analyze_messages(msgs, word_count, email_count):
# type: (List[Dict[str, Any]], Dict[str, int], Dict[str, int]) -> None
for msg in msgs:
if False:
if ' ack' in msg['content']:
@@ -47,6 +50,7 @@ def analyze_messages(msgs, word_count, email_count):
print('%-20s: %s' % (k, v))
def generate_support_stats():
# type: () -> None
client = zulip.Client()
narrow = 'stream:support'
count = 2000

View File

@@ -10,9 +10,12 @@ import unicodedata
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'api'))
import zulip
from typing import Set
zulip_client = zulip.Client(client="ZulipSyncPublicStreamsBot/0.1")
def fetch_public_streams():
# type: () -> Set[str]
public_streams = set()
try:
@@ -64,4 +67,3 @@ if __name__ == "__main__":
f.close()
subprocess.call(["mv", "/home/zulip/public_streams.tmp", "/home/zulip/public_streams"])

View File

@@ -1,69 +0,0 @@
#!/usr/bin/env python
# Copyright (C) 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.
import sys
import os
# Configure this script as a Tddium post-build task and it will send
# messages to Zulip when a build finishes.
#
# Expects Tddium environment variables plus:
#
# ZULIP_USER e.g. builds@solanolabs.com
# ZULIP_API_KEY e.g. 00000000000000000000000000000000
# ZULIP_STREAM e.g. builds
#
# If ZULIP_API_KEY is not specified, it will be read from
# ~/.zulip-api-key.
# Path to the directory where zulip.py lives.
# Here we assume it's in the parent of the directory
# where this script lives.
zulip_directory = os.path.join(os.path.dirname(__file__), '../api')
sys.path.append(zulip_directory)
import zulip
client = zulip.Client(
client = "ZulipTddiumNotifier/0.1",
email = os.environ['ZULIP_USER'],
api_key = os.environ.get('ZULIP_API_KEY'))
tddium_server = os.environ.get('TDDIUM_API_SERVER', 'api.tddium.com')
report_url = 'https://%s/1/reports/%s' % (tddium_server, os.environ['TDDIUM_SESSION_ID'])
repo_name = os.path.basename(os.environ['TDDIUM_REPO_ROOT'])
result = client.send_message(dict(
type = 'stream',
to = os.environ['ZULIP_STREAM'],
subject = 'build for ' + repo_name,
content = '%s [%s](%s)' %
(repo_name, os.environ['TDDIUM_BUILD_STATUS'], report_url)))
if result['result'] != 'success':
sys.stderr.write('Error sending to Zulip:\n%s\n' % (result['msg'],))
sys.exit(1)

View File

@@ -62,6 +62,7 @@ if options.forward_class_messages and not options.noshard:
from zerver.lib.parallel import run_parallel
print("Starting parallel zephyr class mirroring bot")
jobs = list("0123456789abcdef")
def run_job(shard):
# type: (str) -> int
subprocess.call(args + ["--shard=%s" % (shard,)])
@@ -76,15 +77,16 @@ while backoff.keep_going():
print("Starting zephyr mirroring bot")
try:
subprocess.call(args)
except:
except Exception:
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("")
error_message = """
ERROR: The Zephyr mirroring bot is unable to continue mirroring Zephyrs.
This is often caused by failing to maintain unexpired Kerberos tickets
or AFS tokens. See https://zulip.com/zephyr for documentation on how to
maintain unexpired Kerberos tickets and AFS tokens.
"""
print(error_message)
sys.exit(1)

View File

@@ -21,7 +21,8 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
from __future__ import absolute_import
from typing import Any, List
from typing import IO, Any, Text, Union, Set, Tuple
from types import FrameType
import sys
from six.moves import map
@@ -52,6 +53,7 @@ CURRENT_STATE = States.Startup
logger = None # type: logging.Logger
def to_zulip_username(zephyr_username):
# type: (str) -> str
if "@" in zephyr_username:
(user, realm) = zephyr_username.split("@")
else:
@@ -64,6 +66,7 @@ def to_zulip_username(zephyr_username):
return user.lower() + "|" + realm.upper() + "@mit.edu"
def to_zephyr_username(zulip_username):
# type: (str) -> str
(user, realm) = zulip_username.split("@")
if "|" not in user:
# Hack to make ctl's fake username setup work :)
@@ -82,10 +85,11 @@ def to_zephyr_username(zulip_username):
# significantly shorter than the following line (which, if they were
# in the same paragraph, should have been wrapped in a way consistent
# with how the previous line was wrapped) or (2) shorter than 60
# characters (our assumed minimum linewrapping threshhold for Zephyr)
# characters (our assumed minimum linewrapping threshold for Zephyr)
# or (3) the first word of the next line is longer than this entire
# line.
def different_paragraph(line, next_line):
# type: (str, str) -> bool
words = next_line.split()
return (len(line + " " + words[0]) < len(next_line) * 0.8 or
len(line + " " + words[0]) < 50 or
@@ -94,18 +98,19 @@ def different_paragraph(line, next_line):
# Linewrapping algorithm based on:
# http://gcbenison.wordpress.com/2011/07/03/a-program-to-intelligently-remove-carriage-returns-so-you-can-paste-text-without-having-it-look-awful/ #ignorelongline
def unwrap_lines(body):
# type: (str) -> str
lines = body.split("\n")
result = ""
previous_line = lines[0]
for line in lines[1:]:
line = line.rstrip()
if (re.match(r'^\W', line, flags=re.UNICODE)
and re.match(r'^\W', previous_line, flags=re.UNICODE)):
if (re.match(r'^\W', line, flags=re.UNICODE) and
re.match(r'^\W', previous_line, flags=re.UNICODE)):
result += previous_line + "\n"
elif (line == "" or
previous_line == "" or
re.match(r'^\W', line, flags=re.UNICODE) or
different_paragraph(previous_line, line)):
previous_line == "" or
re.match(r'^\W', line, flags=re.UNICODE) or
different_paragraph(previous_line, line)):
# Use 2 newlines to separate sections so that we
# trigger proper Markdown processing on things like
# bulleted lists
@@ -117,6 +122,7 @@ def unwrap_lines(body):
return result
def send_zulip(zeph):
# type: (Dict[str, str]) -> Dict[str, str]
message = {}
if options.forward_class_messages:
message["forged"] = "yes"
@@ -149,6 +155,7 @@ def send_zulip(zeph):
return zulip_client.send_message(message)
def send_error_zulip(error_msg):
# type: (str) -> None
message = {"type": "private",
"sender": zulip_account_email,
"to": zulip_account_email,
@@ -158,6 +165,7 @@ def send_error_zulip(error_msg):
current_zephyr_subs = set()
def zephyr_bulk_subscribe(subs):
# type: (List[Tuple[str, str, str]]) -> None
try:
zephyr._z.subAll(subs)
except IOError:
@@ -193,11 +201,12 @@ def zephyr_bulk_subscribe(subs):
current_zephyr_subs.add(cls)
def update_subscriptions():
# type: () -> None
try:
f = open(options.stream_file_path, "r")
public_streams = simplejson.loads(f.read())
f.close()
except:
except Exception:
logger.exception("Error reading public streams:")
return
@@ -205,7 +214,7 @@ def update_subscriptions():
for stream in public_streams:
zephyr_class = stream.encode("utf-8")
if (options.shard is not None and
not hashlib.sha1(zephyr_class).hexdigest().startswith(options.shard)):
not hashlib.sha1(zephyr_class).hexdigest().startswith(options.shard)):
# This stream is being handled by a different zephyr_mirror job.
continue
if zephyr_class in current_zephyr_subs:
@@ -216,6 +225,7 @@ def update_subscriptions():
zephyr_bulk_subscribe(list(classes_to_subscribe))
def maybe_kill_child():
# type: () -> None
try:
if child_pid is not None:
os.kill(child_pid, signal.SIGTERM)
@@ -224,6 +234,7 @@ def maybe_kill_child():
logger.exception("")
def maybe_restart_mirroring_script():
# type: () -> None
if os.stat(os.path.join(options.root_path, "stamps", "restart_stamp")).st_mtime > start_time or \
((options.user == "tabbott" or options.user == "tabbott/extra") and
os.stat(os.path.join(options.root_path, "stamps", "tabbott_stamp")).st_mtime > start_time):
@@ -243,6 +254,7 @@ def maybe_restart_mirroring_script():
time.sleep(1)
def process_loop(log):
# type: (IO) -> None
restart_check_count = 0
last_check_time = time.time()
while True:
@@ -282,6 +294,7 @@ def process_loop(log):
logger.exception("Error updating subscriptions from Zulip:")
def parse_zephyr_body(zephyr_data):
# type: (str) -> Tuple[str, str]
try:
(zsig, body) = zephyr_data.split("\x00", 1)
except ValueError:
@@ -289,6 +302,7 @@ def parse_zephyr_body(zephyr_data):
return (zsig, body)
def parse_crypt_table(zephyr_class, instance):
# type: (Text, str) -> str
try:
crypt_table = open(os.path.join(os.environ["HOME"], ".crypt-table"))
except IOError:
@@ -310,6 +324,7 @@ def parse_crypt_table(zephyr_class, instance):
return None
def decrypt_zephyr(zephyr_class, instance, body):
# type: (Text, str, str) -> str
keypath = parse_crypt_table(zephyr_class, instance)
if keypath is None:
# We can't decrypt it, so we just return the original body
@@ -340,6 +355,7 @@ def decrypt_zephyr(zephyr_class, instance, body):
return decrypted
def process_notice(notice, log):
# type: (zulip, IO) -> None
(zsig, body) = parse_zephyr_body(notice.message)
is_personal = False
is_huddle = False
@@ -369,7 +385,7 @@ def process_notice(notice, log):
logger.debug("Skipping message we got from Zulip!")
return
if (zephyr_class == "mail" and notice.instance.lower() == "inbox" and is_personal and
not options.forward_mail_zephyrs):
not options.forward_mail_zephyrs):
# Only forward mail zephyrs if forwarding them is enabled.
return
@@ -386,10 +402,10 @@ def process_notice(notice, log):
if options.forward_class_messages and notice.opcode.lower() == "crypt":
body = decrypt_zephyr(zephyr_class, notice.instance.lower(), body)
zeph = { 'time' : str(notice.time),
'sender' : notice.sender,
'zsig' : zsig, # logged here but not used by app
'content' : body }
zeph = {'time': str(notice.time),
'sender': notice.sender,
'zsig': zsig, # logged here but not used by app
'content': body}
if is_huddle:
zeph['type'] = 'private'
zeph['recipient'] = huddle_recipients
@@ -438,6 +454,8 @@ def process_notice(notice, log):
os._exit(0)
def decode_unicode_byte_strings(zeph):
# type: (Dict[str, Any]) -> Dict[str, str]
# 'Any' can be of any type of text that is converted to str.
for field in zeph.keys():
if isinstance(zeph[field], str):
try:
@@ -448,11 +466,13 @@ def decode_unicode_byte_strings(zeph):
return zeph
def quit_failed_initialization(message):
# type: (str) -> str
logger.error(message)
maybe_kill_child()
sys.exit(1)
def zephyr_init_autoretry():
# type: () -> None
backoff = zulip.RandomExponentialBackoff()
while backoff.keep_going():
try:
@@ -468,6 +488,7 @@ def zephyr_init_autoretry():
quit_failed_initialization("Could not initialize Zephyr library, quitting!")
def zephyr_load_session_autoretry(session_path):
# type: (str) -> None
backoff = zulip.RandomExponentialBackoff()
while backoff.keep_going():
try:
@@ -483,6 +504,7 @@ def zephyr_load_session_autoretry(session_path):
quit_failed_initialization("Could not load saved Zephyr session, quitting!")
def zephyr_subscribe_autoretry(sub):
# type: (Tuple[str, str, str]) -> None
backoff = zulip.RandomExponentialBackoff()
while backoff.keep_going():
try:
@@ -498,6 +520,7 @@ def zephyr_subscribe_autoretry(sub):
quit_failed_initialization("Could not subscribe to personals, quitting!")
def zephyr_to_zulip(options):
# type: (Any) -> None
if options.use_sessions and os.path.exists(options.session_path):
logger.info("Loading old session")
zephyr_load_session_autoretry(options.session_path)
@@ -549,6 +572,7 @@ def zephyr_to_zulip(options):
process_loop(None)
def send_zephyr(zwrite_args, content):
# type: (list, str) -> Tuple[int, str]
p = subprocess.Popen(zwrite_args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate(input=content.encode("utf-8"))
@@ -565,12 +589,15 @@ def send_zephyr(zwrite_args, content):
return (p.returncode, stderr)
def send_authed_zephyr(zwrite_args, content):
# type: (list[str], str) -> Tuple[int, str]
return send_zephyr(zwrite_args, content)
def send_unauthed_zephyr(zwrite_args, content):
# type: (list[str], str) -> Tuple[int, str]
return send_zephyr(zwrite_args + ["-d"], content)
def zcrypt_encrypt_content(zephyr_class, instance, content):
# type: (str, str, str) -> str
keypath = parse_crypt_table(zephyr_class, instance)
if keypath is None:
return None
@@ -596,13 +623,15 @@ def zcrypt_encrypt_content(zephyr_class, instance, content):
return encrypted
def forward_to_zephyr(message):
# type: (Dict[str, Any]) -> None
# 'Any' can be of any type of text
support_heading = "Hi there! This is an automated message from Zulip."
support_closing = """If you have any questions, please be in touch through the \
Feedback button or at support@zulipchat.com."""
wrapper = textwrap.TextWrapper(break_long_words=False, break_on_hyphens=False)
wrapped_content = "\n".join("\n".join(wrapper.wrap(line))
for line in message["content"].replace("@", "@@").split("\n"))
for line in message["content"].replace("@", "@@").split("\n"))
zwrite_args = ["zwrite", "-n", "-s", message["sender_full_name"],
"-F", "Zephyr error: See http://zephyr.1ts.org/wiki/df",
@@ -622,7 +651,7 @@ Feedback button or at support@zulipchat.com."""
# appropriate WHITESPACE instance for bidirectional mirroring
instance = match_whitespace_instance.group(1)
elif (instance == "instance %s" % (zephyr_class,) or
instance == "test instance %s" % (zephyr_class,)):
instance == "test instance %s" % (zephyr_class,)):
# Forward messages to e.g. -c -i white-magic back from the
# place we forward them to
if instance.startswith("test"):
@@ -656,7 +685,7 @@ Feedback button or at support@zulipchat.com."""
if message.get("invite_only_stream"):
result = zcrypt_encrypt_content(zephyr_class, instance, wrapped_content)
if result is None:
return send_error_zulip("""%s
send_error_zulip("""%s
Your Zulip-Zephyr mirror bot was unable to forward that last message \
from Zulip to Zephyr because you were sending to a zcrypted Zephyr \
@@ -665,6 +694,7 @@ key (perhaps because your AFS tokens expired). That means that while \
Zulip users (like you) received it, Zephyr users did not.
%s""" % (support_heading, support_closing))
return
# Proceed with sending a zcrypted message
wrapped_content = result
@@ -679,7 +709,7 @@ Zulip users (like you) received it, Zephyr users did not.
if code == 0 and stderr == "":
return
elif code == 0:
return send_error_zulip("""%s
send_error_zulip("""%s
Your last message was successfully mirrored to zephyr, but zwrite \
returned the following warning:
@@ -687,6 +717,7 @@ returned the following warning:
%s
%s""" % (support_heading, stderr, support_closing))
return
elif code != 0 and (stderr.startswith("zwrite: Ticket expired while sending notice to ") or
stderr.startswith("zwrite: No credentials cache found while sending notice to ")):
# Retry sending the message unauthenticated; if that works,
@@ -695,7 +726,7 @@ returned the following warning:
if code == 0:
if options.ignore_expired_tickets:
return
return send_error_zulip("""%s
send_error_zulip("""%s
Your last message was forwarded from Zulip to Zephyr unauthenticated, \
because your Kerberos tickets have expired. It was sent successfully, \
@@ -704,11 +735,12 @@ are running the Zulip-Zephyr mirroring bot, so we can send \
authenticated Zephyr messages for you again.
%s""" % (support_heading, support_closing))
return
# zwrite failed and it wasn't because of expired tickets: This is
# probably because the recipient isn't subscribed to personals,
# but regardless, we should just notify the user.
return send_error_zulip("""%s
send_error_zulip("""%s
Your Zulip-Zephyr mirror bot was unable to forward that last message \
from Zulip to Zephyr. That means that while Zulip users (like you) \
@@ -717,8 +749,11 @@ received it, Zephyr users did not. The error message from zwrite was:
%s
%s""" % (support_heading, stderr, support_closing))
return
def maybe_forward_to_zephyr(message):
# type: (Dict[str, Any]) -> None
# The key string can be used to direct any type of text.
if (message["sender_email"] == zulip_account_email):
if not ((message["type"] == "stream") or
(message["type"] == "private" and
@@ -740,6 +775,7 @@ def maybe_forward_to_zephyr(message):
logger.exception("Error forwarding message:")
def zulip_to_zephyr(options):
# type: (int) -> None
# Sync messages from zulip to zephyr
logger.info("Starting syncing messages.")
while True:
@@ -750,6 +786,7 @@ def zulip_to_zephyr(options):
time.sleep(1)
def subscribed_to_mail_messages():
# type: () -> bool
# In case we have lost our AFS tokens and those won't be able to
# parse the Zephyr subs file, first try reading in result of this
# query from the environment so we can avoid the filesystem read.
@@ -764,6 +801,7 @@ def subscribed_to_mail_messages():
return False
def add_zulip_subscriptions(verbose):
# type: (bool) -> None
zephyr_subscriptions = set()
skipped = set()
for (cls, instance, recipient) in parse_zephyr_subs(verbose=verbose):
@@ -850,9 +888,11 @@ web interface.
""")) + "\n")
def valid_stream_name(name):
# type: (str) -> bool
return name != ""
def parse_zephyr_subs(verbose=False):
# type: (bool) -> Union[List, Tuple, Set[Tuple[str, str, str]]]
zephyr_subscriptions = set()
subs_file = os.path.join(os.environ["HOME"], ".zephyr.subs")
if not os.path.exists(subs_file):
@@ -907,6 +947,7 @@ def open_logger():
return logger
def configure_logger(logger, direction_name):
# type: (logging.Logger, str) -> None
if direction_name is None:
log_format = "%(message)s"
else:
@@ -921,6 +962,7 @@ def configure_logger(logger, direction_name):
handler.setFormatter(formatter)
def parse_args():
# type: () -> Tuple
parser = optparse.OptionParser()
parser.add_option('--forward-class-messages',
default=False,
@@ -1004,6 +1046,7 @@ def parse_args():
return parser.parse_args()
def die_gracefully(signal, frame):
# type: (int, FrameType) -> None
if CURRENT_STATE == States.ZulipToZephyr or CURRENT_STATE == States.ChildSending:
# this is a child process, so we want os._exit (no clean-up necessary)
os._exit(1)
@@ -1029,6 +1072,9 @@ if __name__ == "__main__":
signal.signal(signal.SIGINT, die_gracefully)
# The properties available on 'options' are dynamically
# determined, so we have to treat it as an Any for type
# annotations.
(options, args) = parse_args() # type: Any, List[str]
logger = open_logger()

View File

@@ -1,5 +1,5 @@
[program:zmirror-USERNAME]
command=python /home/zulip/zulip/bots/zephyr_mirror_backend.py --root-path=/home/zulip/zulip --user=USERNAME --log-path=/home/zulip/logs/mirror-log-%(program_name)s --use-sessions --session-path=/home/zulip/zephyr_sessions/%(program_name)s --api-key-file=/home/zulip/api-keys/%(program_name)s --ignore-expired-tickets --nagios-path=/home/zulip/mirror_status/%(program_name)s --nagios-class=zulip-mirror-nagios
command=/home/zulip/zulip/bots/zephyr_mirror_backend.py --root-path=/home/zulip/zulip --user=USERNAME --log-path=/home/zulip/logs/mirror-log-%(program_name)s --use-sessions --session-path=/home/zulip/zephyr_sessions/%(program_name)s --api-key-file=/home/zulip/api-keys/%(program_name)s --ignore-expired-tickets --nagios-path=/home/zulip/mirror_status/%(program_name)s --nagios-class=zulip-mirror-nagios
priority=200 ; the relative start priority (default 999)
autostart=true ; start at supervisord start (default: true)
autorestart=true ; whether/when to restart (default: unexpected)

View File

@@ -1,42 +0,0 @@
# Zulip, Inc's internal git plugin configuration.
# The plugin and example config are under api/integrations/
# Leaving all the instructions out of this file to avoid having to
# sync them as we update the comments.
ZULIP_USER = "commit-bot@zulip.com"
ZULIP_API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# commit_notice_destination() lets you customize where commit notices
# are sent to.
#
# It takes the following arguments:
# * repo = the name of the git repository
# * branch = the name of the branch that was pushed to
# * commit = the commit id
#
# Returns a dictionary encoding the stream and subject to send the
# notification to (or None to send no notification, e.g. for ).
#
# The default code below will send every commit pushed to "master" to
# * stream "commits"
# * topic "master"
# And similarly for branch "test-post-receive" (for use when testing).
def commit_notice_destination(repo, branch, commit):
if branch in ["master", "prod", "test-post-receive"]:
return dict(stream = 'test' if 'test-' in branch else 'commits',
subject = u"%s" % (branch,))
# Return None for cases where you don't want a notice sent
return None
# Modify this function to change how commits are displayed; the most
# common customization is to include a link to the commit in your
# graphical repository viewer, e.g.
#
# return '!avatar(%s) [%s](https://example.com/commits/%s)\n' % (author, subject, commit_id)
def format_commit_message(author, subject, commit_id):
return '!avatar(%s) [%s](https://git.zulip.net/eng/zulip/commit/%s)\n' % (author, subject, commit_id)
ZULIP_API_PATH = "/home/zulip/zulip/api"
ZULIP_SITE = "https://zulip.com"

View File

@@ -1,14 +0,0 @@
# Zulip, Inc's internal trac plugin configuration.
# The plugin and example config are under api/integrations/
# Leaving all the instructions out of this file to avoid having to
# sync them as we update the comments.
ZULIP_USER = "trac-bot@zulip.com"
ZULIP_API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
STREAM_FOR_NOTIFICATIONS = "trac"
TRAC_BASE_TICKET_URL = "https://trac.zulip.net/ticket"
TRAC_NOTIFY_FIELDS = ["description", "summary", "resolution", "comment", "owner"]
ZULIP_API_PATH = "/home/zulip/zulip/api"
ZULIP_SITE = "https://zulip.com"

View File

@@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright: (c) 2008, Jarek Zgoda <jarek.zgoda@gmail.com>
__revision__ = '$Id: cleanupconfirmation.py 5 2008-11-18 09:10:12Z jarek.zgoda $'
from typing import Any
from django.core.management.base import NoArgsCommand
from confirmation.models import Confirmation
class Command(NoArgsCommand):
help = 'Delete expired confirmations from database'
def handle_noargs(self, **options):
# type: (**Any) -> None
Confirmation.objects.delete_expired_confirmations()

View File

@@ -13,24 +13,19 @@ from django.conf import settings
from django.template import loader, Context
from django.contrib.sites.models import Site
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.fields import GenericForeignKey
from django.utils.translation import ugettext_lazy as _
from django.utils.timezone import now
from confirmation.util import get_status_field
from zerver.lib.utils import generate_random_token
try:
import mailer
send_mail = mailer.send_mail
except ImportError:
# no mailer app present, stick with default
pass
from zerver.models import PreregistrationUser
from typing import Optional, Union, Any, Text
B16_RE = re.compile('^[a-f0-9]{40}$')
def check_key_is_valid(creation_key):
# type: (Text) -> bool
if not RealmCreationKey.objects.filter(creation_key=creation_key).exists():
return False
days_sofar = (now() - RealmCreationKey.objects.get(creation_key=creation_key).date_created).days
@@ -40,9 +35,11 @@ def check_key_is_valid(creation_key):
return False
def generate_key():
# type: () -> Text
return generate_random_token(40)
def generate_activation_url(key, host=None):
# type: (Text, Optional[str]) -> Text
if host is None:
host = settings.EXTERNAL_HOST
return u'%s%s%s' % (settings.EXTERNAL_URI_SCHEME,
@@ -51,16 +48,18 @@ def generate_activation_url(key, host=None):
kwargs={'confirmation_key': key}))
def generate_realm_creation_url():
# type: () -> Text
key = generate_key()
RealmCreationKey.objects.create(creation_key=key, date_created=now())
return u'%s%s%s' % (settings.EXTERNAL_URI_SCHEME,
settings.EXTERNAL_HOST,
reverse('zerver.views.create_realm',
kwargs={'creation_key': key}))
kwargs={'creation_key': key}))
class ConfirmationManager(models.Manager):
def confirm(self, confirmation_key):
# type: (str) -> Union[bool, PreregistrationUser]
if B16_RE.search(confirmation_key):
try:
confirmation = self.get(confirmation_key=confirmation_key)
@@ -74,16 +73,22 @@ class ConfirmationManager(models.Manager):
return False
def get_link_for_object(self, obj, host=None):
# type: (Union[ContentType, int], Optional[str]) -> Text
key = generate_key()
self.create(content_object=obj, date_sent=now(), confirmation_key=key)
return generate_activation_url(key, host=host)
return self.get_activation_url(key, host=host)
def get_activation_url(self, confirmation_key, host=None):
# type: (Text, Optional[str]) -> Text
return generate_activation_url(confirmation_key, host=host)
def send_confirmation(self, obj, email_address, additional_context=None,
subject_template_path=None, body_template_path=None,
host=None):
# type: (ContentType, Text, Optional[Dict[str, Any]], Optional[str], Optional[str], Optional[str]) -> Confirmation
confirmation_key = generate_key()
current_site = Site.objects.get_current()
activate_url = generate_activation_url(confirmation_key, host=host)
activate_url = self.get_activation_url(confirmation_key, host=host)
context = Context({
'activate_url': activate_url,
'current_site': current_site,
@@ -122,7 +127,7 @@ class ConfirmationManager(models.Manager):
class Confirmation(models.Model):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
content_object = GenericForeignKey('content_type', 'object_id')
date_sent = models.DateTimeField(_('sent'))
confirmation_key = models.CharField(_('activation key'), max_length=40)
@@ -133,6 +138,7 @@ class Confirmation(models.Model):
verbose_name_plural = _('confirmation emails')
def __unicode__(self):
# type: () -> Text
return _('confirmation email for %s') % (self.content_object,)
class RealmCreationKey(models.Model):

View File

@@ -7,6 +7,7 @@ __revision__ = '$Id: util.py 3 2008-11-18 07:33:52Z jarek.zgoda $'
from django.conf import settings
def get_status_field(app_label, model_name):
# type: (str, str) -> str
model = '%s.%s' % (app_label, model_name)
mapping = getattr(settings, 'STATUS_FIELDS', {})
return mapping.get(model, 'status')

View File

@@ -11,6 +11,7 @@ from django.conf import settings
from django.http import HttpRequest, HttpResponse
from confirmation.models import Confirmation
from zerver.models import PreregistrationUser
from zproject.jinja2 import render_to_response
@@ -39,7 +40,7 @@ def confirm(request, confirmation_key):
templates = [
'confirmation/confirm.html',
]
if obj:
if obj and isinstance(obj, (PreregistrationUser, Confirmation)):
# if we have an object, we can use specific template
templates.insert(0, 'confirmation/confirm_%s.html' % (obj._meta.model_name,))
return render_to_response(templates, ctx, request=request)

93
contrib_bots/bot_lib.py Normal file
View File

@@ -0,0 +1,93 @@
from __future__ import print_function
import logging
import os
import signal
import sys
import time
our_dir = os.path.dirname(os.path.abspath(__file__))
# For dev setups, we can find the API in the repo itself.
if os.path.exists(os.path.join(our_dir, '../api/zulip')):
sys.path.insert(0, '../api')
from zulip import Client
def exit_gracefully(signum, frame):
sys.exit(0)
class RateLimit(object):
def __init__(self, message_limit, interval_limit):
self.message_limit = message_limit
self.interval_limit = interval_limit
self.message_list = []
def is_legal(self):
self.message_list.append(time.time())
if len(self.message_list) > self.message_limit:
self.message_list.pop(0)
time_diff = self.message_list[-1] - self.message_list[0]
return time_diff >= self.interval_limit
else:
return True
class BotHandlerApi(object):
def __init__(self, client):
# Only expose a subset of our Client's functionality
user_profile = client.get_profile()
self._rate_limit = RateLimit(20, 5)
self._client = client
try:
self.full_name = user_profile['full_name']
self.email = user_profile['email']
except KeyError:
logging.error('Cannot fetch user profile, make sure you have set'
' up the zuliprc file correctly.')
sys.exit(1)
def send_message(self, *args, **kwargs):
if self._rate_limit.is_legal():
self._client.send_message(*args, **kwargs)
else:
logging.error('-----> !*!*!*MESSAGE RATE LIMIT REACHED, EXITING*!*!*! <-----\n'
'Is your bot trapped in an infinite loop by reacting to'
' its own messages?')
sys.exit(1)
def run_message_handler_for_bot(lib_module, quiet, config_file):
# Make sure you set up your ~/.zuliprc
client = Client(config_file=config_file)
restricted_client = BotHandlerApi(client)
message_handler = lib_module.handler_class()
class StateHandler(object):
def __init__(self):
self.state = None
def set_state(self, state):
self.state = state
def get_state(self):
return self.state
state_handler = StateHandler()
if not quiet:
print(message_handler.usage())
def handle_message(message):
logging.info('waiting for next message')
if message_handler.triage_message(message=message,
client=restricted_client):
message_handler.handle_message(
message=message,
client=restricted_client,
state_handler=state_handler
)
signal.signal(signal.SIGINT, exit_gracefully)
logging.info('starting message handling...')
client.call_on_each_message(handle_message)

View File

@@ -0,0 +1,72 @@
This bot will allow briefings of estimated travel times, distances and
fare information for transit travel.
It can respond to: departure times, arrival times, user preferences
(toll avoidance, highway avoidance) and a mode of transport
It can output: fare information, more detailed addresses on origin and
destination, duration in traffic information, metric and imperical
units and information in various languages.
The bot will respond to the same stream input was in. And if called as
private message, the bot will reply with a private message.
To setup the bot, you will first need to move google-commute.ini into
the user home directory and add an API key.
Move
```
~/zulip/contrib_bots/bots/commute_bot/CommuteBot/google-commute.ini
```
into
```
~/google-commute.ini
```
To add an API key, please visit:
https://developers.google.com/maps/documentation/distance-matrix/start
to retrieve a key and copy your api key into google-commute.ini
Sample input and output:
<pre><code>@commute help</code></pre>
<pre><code>Obligatory Inputs:
Origin e.g. origins=New+York,NY,USA
Destination e.g. destinations=Chicago,IL,USA
Optional Inputs:
Mode Of Transport (inputs: driving, walking, bicycling, transit)
Default mode (no mode input) is driving
e.g. mode=driving or mode=transit
Units (metric or imperial)
e.g. units=metric
Restrictions (inputs: tolls, highways, ferries, indoor)
e.g. avoid=tolls
Departure Time (inputs: now or (YYYY, MM, DD, HH, MM, SS) departing)
e.g. departure_time=now or departure_time=2016,12,17,23,40,40
Arrival Time (inputs: (YYYY, MM, DD, HH, MM, SS) arriving)
e.g. arrival_time=2016,12,17,23,40,40
Languages:
Languages list: https://developers.google.com/maps/faq#languagesupport)
e.g. language=fr
</code></pre>
Sample request:
<pre><code>
@commute origins=Chicago,IL,USA destinations=New+York,NY,USA language=fr
</code></pre>
Please note:
Fare information can be derived, though is solely dependent on the
availability of the information released by public transport operators.
Duration in traffic can only be derived if a departure time is set.
If a location has spaces in its name, please use a + symbol in the
place of the space/s.
A departure time and a arrival time can not be inputted at the same time
No spaces within addresses.
Departure times and arrival times must be in the UTC timezone,
you can use the timezone bot.

View File

@@ -0,0 +1,2 @@
[Google.com]
api_key = abcdefghijklmnopqrstuvwxyz

View File

@@ -0,0 +1,264 @@
from __future__ import print_function
import datetime as dt
import requests
from os.path import expanduser
from six.moves import configparser as cp
home = expanduser('~')
CONFIG_PATH = home + '/google-commute.ini'
class CommuteHandler(object):
'''
This plugin provides information regarding commuting
from an origin to a destination, providing a multitude of information.
It looks for messages starting with '@commute'.
'''
def __init__(self):
self.api_key = self.get_api_key()
def usage(self):
return '''
This plugin will allow briefings of estimated travel times,
distances and fare information for transit travel.
It can vary outputs depending on traffic conditions, departure and
arrival times as well as user preferences
(toll avoidance, preference for bus travel, etc.).
It looks for messages starting with '@commute'.
Users should input an origin and a destination
in any stream or through private messages to the bot to receive a
response in the same stream or through private messages if the
input was originally private.
Sample input:
@commute origins=Chicago,IL,USA destinations=New+York,NY,USA
@commute help
'''
help_info = '''
Obligatory Inputs:
Origin e.g. origins=New+York,NY,USA
Destination e.g. destinations=Chicago,IL,USA
Optional Inputs:
Mode Of Transport (inputs: driving, walking, bicycling, transit)
Default mode (no mode input) is driving
e.g. mode=driving or mode=transit
Units (metric or imperial)
e.g. units=metric
Restrictions (inputs: tolls, highways, ferries, indoor)
e.g. avoid=tolls
Departure Time (inputs: now or (YYYY, MM, DD, HH, MM, SS) departing)
e.g. departure_time=now or departure_time=2016,12,17,23,40,40
Arrival Time (inputs: (YYYY, MM, DD, HH, MM, SS) arriving)
e.g. arrival_time=2016,12,17,23,40,40
Languages:
Languages list: https://developers.google.com/maps/faq#languagesupport)
e.g. language=fr
Sample request:
@commute origins=Chicago,IL,USA destinations=New+York,NY,USA language=fr
Please note:
Fare information can be derived, though is solely dependent on the
availability of the information
python run.py bots/followup/followup.py --config-file ~/.zuliprc-local
released by public transport operators.
Duration in traffic can only be derived if a departure time is set.
If a location has spaces in its name, please use a + symbol in the
place of the space/s.
A departure time and a arrival time can not be inputted at the same time
To add more than 1 input for a category,
e.g. more than 1 destinations,
use (|), e.g. destinations=Empire+State+Building|Statue+Of+Liberty
No spaces within addresses.
Departure times and arrival times must be in the UTC timezone,
you can use the timezone bot.
'''
def triage_message(self, message, client):
original_content = message['content']
# This next line of code is defensive, as we
# never want to get into an infinite loop of posting follow
# ups for own follow ups!
if message['display_recipient'] == 'commute':
return False
is_commute = original_content.startswith('@commute')
return is_commute
# adds API Authentication Key to url request
def get_api_key(self):
# google-commute.ini must have been moved from
# ~/zulip/contrib_bots/bots/commute_bot/CommuteBot/google-commute.ini into
# /google-commute.ini for program to work
# see doc.md for more information
with open(CONFIG_PATH) as settings:
config = cp.ConfigParser()
config.readfp(settings)
return config.get('Google.com', 'api_key')
# determines if bot will respond as a private message/ stream message
def send_info(self, message, letter, client):
if message['type'] == 'private':
client.send_message(dict(
type='private',
to=message['sender_email'],
content=letter,
))
else:
client.send_message(dict(
type='stream',
subject=message['subject'],
to=message['display_recipient'],
content=letter,
))
def calculate_seconds(self, time_str):
times = time_str.split(',')
times = [int(x) for x in times]
# UNIX time from January 1, 1970 00:00:00
unix_start_date = dt.datetime(1970, 1, 1, 0, 0, 0)
requested_time = dt.datetime(*times)
total_seconds = str(int((requested_time-unix_start_date)
.total_seconds()))
return total_seconds
# adds departure time and arrival time paramaters into HTTP request
def add_time_to_params(self, params):
# limited to UTC timezone because of difficulty with user inputting
# correct string for input
if 'departure_time' in params:
if 'departure_time' != 'now':
params['departure_time'] = self.calculate_seconds(params['departure_time'])
elif 'arrival_time' in params:
params['arrival_time'] = self.calculate_seconds(params['arrival_time'])
return
# gets content for output and sends it to user
def get_send_content(self, rjson, params, message, client):
try:
# JSON list of output variables
variable_list = rjson["rows"][0]["elements"][0]
# determines if user has valid inputs
not_found = (variable_list["status"] == "NOT_FOUND")
invalid_request = (rjson["status"] == "INVALID_REQUEST")
no_result = (variable_list["status"] == "ZERO_RESULTS")
if no_result:
self.send_info(message,
"Zero results\nIf stuck, try '@commute help'.",
client)
return
elif not_found or invalid_request:
raise IndexError
except IndexError:
self.send_info(message,
"Invalid input, please see instructions."
"\nIf stuck, try '@commute help'.", client)
return
# origin and destination strings
begin = 'From: ' + rjson["origin_addresses"][0]
end = 'To: ' + rjson["destination_addresses"][0]
distance = 'Distance: ' + variable_list["distance"]["text"]
duration = 'Duration: ' + variable_list["duration"]["text"]
output = begin + '\n' + end + '\n' + distance
# if user doesn't know that default mode is driving
if 'mode' not in params:
mode = 'Mode of Transport: Driving'
output += '\n' + mode
# determines if fare information is available
try:
fare = ('Fare: ' + variable_list["fare"]["currency"] +
variable_list["fare"]["text"])
output += '\n' + fare
except (KeyError, IndexError):
pass
# determines if traffic duration information is available
try:
traffic_duration = ('Duration in traffic: ' +
variable_list["duration_in_traffic"]
["text"])
output += '\n' + traffic_duration
except (KeyError, IndexError):
output += '\n' + duration
# bot sends commute information to user
self.send_info(message, output, client)
# creates parameters for HTTP request
def parse_pair(self, content_list):
result = {}
for item in content_list:
# enables key value pair
org = item.split('=')
# ensures that invalid inputs are not entered into url request
if len(org) != 2:
continue
key, value = org
result[key] = value
return result
def receive_response(self, params, message, client):
def validate_requests(request):
if request.status_code == 200:
return request.json()
else:
self.send_info(message,
"Something went wrong. Please try again." +
" Error: {error_num}.\n{error_text}"
.format(error_num=request.status_code,
error_text=request.text), client)
return
r = requests.get('https://maps.googleapis.com/maps/api/' +
'distancematrix/json', params=params)
result = validate_requests(r)
return result
def handle_message(self, message, client, state_handler):
original_content = message['content']
content_list = original_content.split()
if "help" in content_list:
self.send_info(message, self.help_info, client)
return
params = self.parse_pair(content_list)
params['key'] = self.api_key
self.add_time_to_params(params)
rjson = self.receive_response(params, message, client)
if not rjson:
return
self.get_send_content(rjson, params, message, client)
handler_class = CommuteHandler
handler = CommuteHandler()
def test_parse_pair():
result = handler.parse_pair(['departure_time=2016,12,20,23,59,00',
'dog_foo=cat-foo'])
assert result == dict(departure_time='2016,12,20,23,59,00',
dog_foo='cat-foo')
def test_calculate_seconds():
result = handler.calculate_seconds('2016,12,20,23,59,00')
assert result == str(1482278340)
def test_get_api_key():
# must change to your own api key for test to work
result = handler.get_api_key()
assert result == 'abcdefghijksm'
def test_helper_functions():
test_parse_pair()
test_calculate_seconds()
test_get_api_key()
if __name__ == '__main__':
test_helper_functions()
print('Success')

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

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