Skip to content

Commit d5b0167

Browse files
Alexander HvidtAlexander Hvidt
Alexander Hvidt
authored and
Alexander Hvidt
committedOct 18, 2018
Initial commit
0 parents  commit d5b0167

31 files changed

+5030
-0
lines changed
 

‎.arcconfig

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"project_id": "snippets",
3+
"conduit_uri": "https://phabricator.khanacademy.org/",
4+
"lint.engine": "ArcanistConfigurationDrivenLintEngine"
5+
}

‎.arclint

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"linters": {
3+
"khan-linter": {
4+
"type": "script-and-regex",
5+
"script-and-regex.script": "ka-lint --always-exit-0 --blacklist=yes --propose-arc-fixes",
6+
"script-and-regex.regex": "\/^((?P<file>[^:]*):(?P<line>\\d+):((?P<char>\\d+):)? (?P<name>((?P<error>E)|(?P<warning>W))\\S+) (?P<message>[^\\x00\n]*)(\\x00(?P<original>[^\\x00]*)\\x00(?P<replacement>[^\\x00]*)\\x00)?)|(?P<ignore>SKIPPING.*)$\/m"
7+
}
8+
}
9+
}

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*.pyc

‎.travis.yml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
sudo: false
2+
language: python
3+
4+
cache:
5+
pip: true
6+
directories:
7+
- "$HOME/google-cloud-sdk/"
8+
9+
env:
10+
global:
11+
- PATH=$PATH:${HOME}/google-cloud-sdk/bin
12+
- GAE_PYTHONPATH=${HOME}/google-cloud-sdk/platform/google_appengine
13+
- PYTHONPATH=${PYTHONPATH}:${GAE_PYTHONPATH}
14+
- CLOUDSDK_CORE_DISABLE_PROMPTS=1
15+
16+
install:
17+
- if [ ! -d ${HOME}/google-cloud-sdk/bin ]; then
18+
rm -rf ${HOME}/google-cloud-sdk;
19+
curl -s https://sdk.cloud.google.com | bash;
20+
fi
21+
- gcloud components update app-engine-python
22+
23+
before_script:
24+
- make test_deps
25+
26+
script:
27+
- make test

‎Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.PHONY: serve test_deps test check appcfg-update deploy
2+
3+
serve:
4+
dev_appserver.py --log_level=debug . --host=0.0.0.0
5+
6+
test_deps:
7+
pip install -r requirements-dev.txt
8+
9+
test check:
10+
python -m unittest discover -p '*_test.py'
11+
12+
appcfg-update deploy:
13+
gcloud app deploy --project "${APP}"

‎README.md

+247
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
Snippet Server
2+
==============
3+
4+
This server supports writing and reading weekly snippets -- status
5+
updates -- for a group of people.
6+
7+
When I joined Khan Academy, my first project was to write a version of
8+
the weekly-snippet server I had worked with [at
9+
Google](http://blog.idonethis.com/google-snippets-internal-tool/).
10+
Years later, with the help of many other intrepid Khan Academy
11+
employees, it's ready for the world!
12+
13+
While there are [many](https://weekdone.com/)
14+
[snippet](https://www.workingon.co/)
15+
[systems](https://www.teamsnippets.com/) out there, this one is
16+
optimized for simplicity (also, free-ness). For instance, it prefers
17+
single webpages with lots of info over paging, queries, or fancy
18+
javascript. Filling out a snippet involves writing into a textbox: no
19+
fields or text editors or other barriers to productivity. (Markdown
20+
is available for those who want nice formatting.) This makes it easy
21+
to learn and easy to program with.
22+
23+
24+
What are weekly snippets?
25+
-------------------------
26+
27+
A weekly snippet is an (ideally) brief description of what you did the
28+
last week. To give an idea of 'brief': the snippet-entry textbox is
29+
sized for 4 bullet-point entries, each 80 characters or less.
30+
31+
Your snippets are visible to everyone else on your email domain. (So
32+
my snippets are visible to everyone who logs in to KA snippet server
33+
with a `@khanacademy.org` email address.) Depending on your
34+
configuration options, they may also be visible to everyone else on
35+
your server.
36+
37+
38+
Why have snippets?
39+
------------------
40+
41+
Different people might have different purposes for weekly snippets:
42+
43+
* Instead of a weekly standup or other meeting where everyone shares
44+
what they've done in the last week, they can just read (and write)
45+
snippets.
46+
* Managers can read snippets of their direct reports to make better
47+
use of 1-on-1 meetings.
48+
* You can look over your own snippets when writing a self-evaluation
49+
or applying for a promotion, or when you have any other need to remind
50+
yourself what you've worked on.
51+
52+
I've found this last reason is particularly compelling. I also use
53+
snippets as a simple "time and motion" study: when I have too many
54+
things to put into snippets one week, I know I'm being spread too
55+
thin!
56+
57+
Another benefit of snippets is serendipidous helping: by reading
58+
someone's snippet, you may discover a task or problem they're working
59+
on that you can help with, that otherwise you would never have known
60+
about.
61+
62+
63+
What are snippets not good for?
64+
-------------------------------
65+
66+
Some people go into a snippet system with unrealistic expectations and
67+
are disappointed.
68+
69+
* Snippets do not work well for large groups, say **over 100
70+
people**. If you have 1000 people using your snippet server, it is
71+
neither practical nor useful to read through everyone's snippets
72+
every week.
73+
74+
* Snippets are, by design, a low level tool: they show you trees but
75+
not the forest. The snippet system does not support "rolling up"
76+
groups of snippets or having team-based snippets (though certain
77+
individuals could certainly choose to have their own snippets refer
78+
to a team's progress).
79+
80+
* Snippets do not provide context. If you don't already know what
81+
someone is working on, their snippet may well be more confusing
82+
than enlightening.
83+
84+
At Khan Academy, the entire company uses one snippet server. The
85+
snippets are divided into various categories, some functional, some
86+
project-based. I like to skim over the snippets for people in
87+
unrelated categories such as "facilities" or "recruiting." I read
88+
more closely the snippets in projects I'm interested in but not
89+
working on, such as "mobile." And I read most closely the snippets of
90+
people in my own project or closely related projects.
91+
92+
93+
How do you use the snippet-server?
94+
==================================
95+
96+
After setting up your settings, to control things like how public your
97+
snippets are and whether you want to use plain text or
98+
[markdown](https://daringfireball.net/projects/markdown/), there are
99+
only two web pages: the one where you write your snippets, and the one
100+
where you read everyone's snippets for a week.
101+
102+
The administrator can set up the system to send you reminder emails to
103+
write snippets, or to email when snippets are ready for a week. (The
104+
snippet server can also use chat systems for this.)
105+
106+
107+
System requirements
108+
-------------------
109+
110+
The snippet server is built on top of [Google
111+
AppEngine](https://cloud.google.com/appengine/docs), and uses Google
112+
services for authentication. To use it, you need to clone the
113+
[snippet github project](https://github.com/Khan/snippets) and then
114+
upload it to your own appengine instance. (It uses few resources, so
115+
Google's "free tier" would work fine.)
116+
117+
The people using your snippet server must log in using Google (aka
118+
Gmail) accounts. The snippet server works particularly well with
119+
companies that use [Google Apps for Work](https://apps.google.com).
120+
121+
122+
Access control
123+
--------------
124+
125+
When a snippet server is first set up, the administrator restricts it
126+
to specific domains. (The Khan Academy server, for instance, is
127+
restricted to `@khanacademy.org`.) If you want to create a snippet on
128+
the server, you must log in via an email address from one of those
129+
domains.
130+
131+
You can set your snippet to be either "public" or "private". "Public"
132+
snippets are visible to everyone who has access to your snippet
133+
server. "Private" snippets are visible only to people on the same
134+
domain as you. So if you logged in as `jane@example.com`, only other
135+
users at `example.com` would be able to see your Snippet.
136+
137+
138+
Email and chat
139+
--------------
140+
141+
The snippet server integrates with email, HipChat, and Slack.
142+
143+
It can send individual emails to people who have not written a snippet
144+
for this week, reminding them to do so. (Users can turn this feature
145+
off in their preferences.) It can also send an email to all
146+
registered users, at 5pm on Monday, to say snippets are ready.
147+
148+
It can also send reminders and ready messages via chat. (In this
149+
case, the reminder isn't individualized.)
150+
151+
152+
Installing and administering the snippet server
153+
===============================================
154+
155+
To install the snippet-server you will need to [download the Google
156+
AppEngine SDK](https://cloud.google.com/appengine/downloads)
157+
158+
Second, you will need a Google AppEngine project set up where this
159+
code will live. You can create one at
160+
https://console.developers.google.com: click on "Select a project..."
161+
in the top navbar and then "Create a project."
162+
163+
You will then need a name for your AppEngine project. Let's suppose
164+
you call it `mycompany-snippets`, you can then deploy with
165+
166+
```
167+
make deploy APP=mycompany-snippets
168+
```
169+
170+
Your app will then be available at `mycompany-snippets.appspot.com`.
171+
172+
If you get an error like 'gcloud: not found', it means you need to
173+
add the appengine-SDK location to your `$PATH`.
174+
175+
You may also need to manually trigger an index build for datastore
176+
177+
```
178+
gcloud datastore create-indexes index.yaml
179+
```
180+
(try this if you're seeing 500 errors)
181+
182+
183+
Adding administrators
184+
---------------------
185+
186+
By dint of creating the AppEngine project, you are an administrator of
187+
that project, and thus an administrator for the snippet-server as
188+
well. In fact, the only way to be an app administrator is to also be
189+
an administrator of the AppEngine project. You can add administrators
190+
at `https://console.developers.google.com/permissions/projectpermissions?project=mycompany-snippets`.
191+
192+
Everyone who is an administrator on the underlying Google AppEngine
193+
account is also an administrator of the Snippet Server.
194+
195+
196+
First-time setup
197+
----------------
198+
199+
When you log into the snippet server for the first time, you will be
200+
brought to the 'global settings' page. Fill out these settings and
201+
click 'Save'. Most are self-explanatory. The hostname is probably
202+
pre-filled to be `mycompany-snippets.appspot.com`, but if you have set
203+
up a
204+
[CNAME](https://cloud.google.com/appengine/docs/python/console/using-custom-domains-and-ssl)
205+
(`snippets.mycompany.com`) you can use that instead.
206+
207+
Once you have clicked "Save", you will be prompted to fill in your own
208+
user settings. This is the first page your users will see, when they
209+
first log in, as well.
210+
211+
Once you've entered your user settings, you'll be taken to the page to
212+
enter your first snippets!
213+
214+
215+
Deleting users
216+
--------------
217+
218+
At any time you are logged into the snippet server, you can get to the
219+
global settings page by clicking the "app settings" button in the top
220+
navbar. You can modify the global settings there at any time. You
221+
can also click "delete or hide users". This allows you to delete
222+
users who are no longer part of the snippet server. You can also hide
223+
users.
224+
225+
"Deleting" a user in the snippet-server has some non-obvious
226+
semantics:
227+
228+
1. Deleting a user does **not** cause their snippets to be deleted.
229+
(Neither does hiding a user.) Old snippets will still be visible.
230+
231+
2. Both deleting and hiding a user means their name will not show up
232+
on subsequent weeks' snippet reports. This is useful for saving
233+
screen real estate.
234+
235+
3. Both deleting and hiding a user means they will not receive weekly
236+
reminder or reporting emails from now on.
237+
238+
4. Here is the difference between deleting and hiding: when you delete
239+
a user, the next time they log into the snippet-server they will be
240+
prompted to re-enter their user settings. When you hide a user, the
241+
next time they log into the snippet-server it will automatically use
242+
their pre-existing user settings.
243+
244+
As you can see, hiding and deleting are almost the same thing. In my
245+
own use, I use "delete" when full-time employees leave Khan Academy,
246+
and "hide" when interns end their internship (since we hope they'll
247+
return!).

‎app.yaml

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
runtime: python27
2+
threadsafe: yes
3+
api_version: 1
4+
default_expiration: "365d"
5+
6+
handlers:
7+
- url: /static
8+
static_dir: static
9+
10+
- url: /favicon.ico
11+
static_files: static/favicon.ico
12+
mime_type: image/x-icon
13+
upload: static/favicon.ico
14+
15+
- url: /admin/.*
16+
script: snippets.application
17+
login: admin
18+
19+
- url: .*
20+
script: snippets.application
21+
22+
skip_files:
23+
- .git
24+
- .DS_Store
25+
- .*.pyc
26+
27+
builtins:
28+
- remote_api: on
29+
30+
libraries:
31+
- name: jinja2
32+
version: "2.6"
33+
# This also brings in webapp2_extras:
34+
- name: webapp2
35+
version: "2.5.1"

‎cron.yaml

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
cron:
2+
3+
- description: snippets hipchat -- early reminder to write snippets
4+
url: /admin/send_friday_reminder_chat
5+
schedule: every friday 16:00
6+
timezone: US/Pacific
7+
8+
- description: snippets email -- reminder to write snippets
9+
url: /admin/send_reminder_email
10+
schedule: every sunday 23:50
11+
timezone: US/Pacific
12+
13+
- description: snippets email -- notification that snippets are ready to view
14+
url: /admin/send_view_email
15+
schedule: every monday 19:00
16+
timezone: US/Pacific

0 commit comments

Comments
 (0)
Please sign in to comment.