Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 0 additions & 18 deletions README

This file was deleted.

53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# 스니펫
Snippets는 구글이 사내에서 운영하는 업무 공유용 이메일 시스템입니다.

### 스니펫 동작 방식

매주, 스니펫 시스템으로부터 리마인더 이메일이 발송됩니다.
사용자들은 지난 주에 무엇을 했는지 여기에 답변으로 보낼 수 있습니다.
웹을 통해 다른 사용자들을 follow 할 수 있습니다.
태그 기능도 있어서 자기 자신을 태그에 할당하고, 이렇게 생긴 태그 역시 follow 할 수 있습니다.
그러고나면 매주 월요일에 follow 한 태그나 사용자에 대한 다이제스트 메일을 받게 됩니다.
추가로 각 사용자들의 아카이브도 웹에서 볼 수 있습니다.

**fork 후 수정 내용 - 특이사항 없음**

* 타임존을 서울/아시아로 변경
* 수정할 부분 FIX ME로 표시
* 가입 계정 소문자 변환
* 서명, 답변 패턴 추가

### 사용하기
1. git clone git@github.com:curioe/snippets.git
2. [구글앱엔진](https://appengine.google.com) 에서 새 앱을 생성합니다.
3. 소스를 생성한 이름에 맞게 수정합니다. ('FIX ME'로 검색)
4. 구글앱엔진 런처를 실행하여, 또는 커맨드로 배포하면 완료됩니다.
5. 웹 - {앱명}.appspot.com 과, 메일 - snippets@{앱명}.appsotmail.com 을 통해 스니펫을 시작하면 됩니다. :)

### 나에게 맞게 수정
* trim될 서명, 답변 패턴을 정규식으로 추가 -> receive_email.py
* 리마인더/다이제스트 메일 발송 시각 변경 -> cron.yaml




-----
# Original README
Folks who worked at Google may miss snippets at their current
employers. Help is at hand.

Every week, the system emails out a reminder email. Users can reply to
it with what they did that week. Users can follow other users via the
web, as well as following tags, and assigning tags to themselves. All
content matching the tags they follow will be mailed to them in a
digest every Monday afternoon. In addition, archives for each user and
the most recent data for each tag are visible on the web.

It was hard to make this totally portable. You'll probably want to
fork and change the application name and hardcoded email addresses,
creating your own application on app engine with authentication
restricted to your custom domain. I would love patches to core
functionality, though.

Little attention has been paid to making this particularly scalable,
but it should work for any small or medium company.
8 changes: 6 additions & 2 deletions app.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
application: fssnippets
application: minisnippets # FIX ME
version: 1
runtime: python
api_version: 1

handlers:
- url: /_ah/mail/snippets@.*fssnippets\.appspotmail\.com
- url: /favicon.ico
static_files: templates/favicon.ico
upload: templates/favicon.ico

- url: /_ah/mail/snippets@.*minisnippets\.appspotmail\.com # FIX ME
script: receive_email.py
login: admin

Expand Down
8 changes: 4 additions & 4 deletions cron.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
cron:
- description: weekly reminder
url: /reminderemail
schedule: every sunday 19:00
timezone: America/New_York
schedule: every friday 17:00 # FIX ME
timezone: Asia/Seoul
- description: weekly digest
url: /digestemail
schedule: every monday 19:00
timezone: America/New_York
schedule: every monday 9:00 # FIX ME
timezone: Asia/Seoul
23 changes: 14 additions & 9 deletions dateutil.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import datetime

class Eastern_tzinfo(datetime.tzinfo):
"""Implementation of the Eastern timezone.
class Seoul_tzinfo(datetime.tzinfo):
"""Implementation of the Seoul timezone.

Adapted from http://code.google.com/appengine/docs/python/datastore/typesandpropertyclasses.html
"""
def utcoffset(self, dt):
return datetime.timedelta(hours=-5) + self.dst(dt)
return datetime.timedelta(hours=+9) + self.dst(dt)

def _FirstSunday(self, dt):
"""First Sunday on or after dt."""
return dt + datetime.timedelta(days=(6-dt.weekday()))

def dst(self, dt):
""" 한국은 섬머타임 없으므로 계산 생략 (dst=daylight saving time)
# 2 am on the second Sunday in March
dst_start = self._FirstSunday(datetime.datetime(dt.year, 3, 8, 2))
# 1 am on the first Sunday in November
Expand All @@ -22,17 +23,21 @@ def dst(self, dt):
return datetime.timedelta(hours=1)
else:
return datetime.timedelta(hours=0)

"""
return datetime.timedelta(hours=0)

def tzname(self, dt):
"""
if self.dst(dt) == datetime.timedelta(hours=0):
return "EST"
return "KST"
else:
return "EDT"

return "KDT"
"""
return "KST"

def date_for_new_snippet():
"""Return next Monday, unless it is Monday (0) or Tuesday (1)"""
today = datetime.datetime.now(Eastern_tzinfo()).date()
today = datetime.datetime.now(Seoul_tzinfo()).date()
if (today.weekday() < 2):
aligned = today - datetime.timedelta(days=today.weekday())
else:
Expand All @@ -42,5 +47,5 @@ def date_for_new_snippet():

def date_for_retrieval():
"""Always return the most recent Monday."""
today = datetime.datetime.now(Eastern_tzinfo()).date()
today = datetime.datetime.now(Seoul_tzinfo()).date()
return today - datetime.timedelta(days=today.weekday())
20 changes: 13 additions & 7 deletions emails.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
import logging

from google.appengine.api import mail
Expand All @@ -9,9 +10,14 @@
from model import *

REMINDER = """
Hey nerd,
한 주간 수고하셨습니다.
회신으로 업무내역을 입력해주세요. :)

The kids want to know what you're up to. Don't leave 'em hanging.
지난주 한 일
-

이번주 할 일
-
"""

class ReminderEmail(webapp.RequestHandler):
Expand All @@ -24,9 +30,9 @@ def get(self):

class OneReminderEmail(webapp.RequestHandler):
def post(self):
mail.send_mail(sender="snippets <snippets@fssnippets.appspotmail.com>",
mail.send_mail(sender="snippets <snippets@minisnippets.appspotmail.com>", # FIX ME
to=self.request.get('email'),
subject="Snippet time!",
subject="Snippet 타임!",
body=REMINDER)

def get(self):
Expand All @@ -41,9 +47,9 @@ def get(self):

class OneDigestEmail(webapp.RequestHandler):
def __send_mail(self, recipient, body):
mail.send_mail(sender="snippets <snippets@fssnippets.appspotmail.com>",
mail.send_mail(sender="snippets <snippets@minisnippets.appspotmail.com>", # FIX ME
to=recipient,
subject="Snippet delivery!",
subject="Snippet Digest 메일이 도착하였습니다!",
body=body)

def __snippet_to_text(self, snippet):
Expand All @@ -62,6 +68,6 @@ def post(self):
logging.info(all_snippets)
body = '\n\n\n'.join([self.__snippet_to_text(s) for s in all_snippets if s.user.email in following])
if body:
self.__send_mail(user.email, 'https://fssnippets.appspot.com\n\n' + body)
self.__send_mail(user.email, 'https://minisnippets.appspot.com\n\n' + body) # FIX ME
else:
logging.info(user.email + ' not following anybody.')
3 changes: 2 additions & 1 deletion main.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ def wrapper(self, *args, **kwargs):
class BaseHandler(webapp.RequestHandler):
def get_user(self):
'''Returns the user object on authenticated requests'''
user = users.get_current_user()
curuser = users.get_current_user()
user = users.User(curuser.email().lower())
assert user

userObj = User.all().filter("email =", user.email()).fetch(1)
Expand Down
4 changes: 2 additions & 2 deletions receive_email.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ def receive(self, message):
body.encoding = '7bit'
content = body.decode()

sig_pattern = re.compile(r'^\-\-\s*$', re.MULTILINE)
sig_pattern = re.compile(r'^(\-\-|\=\=)\s*$', re.MULTILINE)
split_email = re.split(sig_pattern, content)
content = split_email[0]

reply_pattern = re.compile(r'^On.*at.*snippets', re.MULTILINE)
reply_pattern = re.compile(r'^(On.*at|2\d{3}).*snippets', re.MULTILINE)
split_email = re.split(reply_pattern, content)
content = split_email[0]

Expand Down
4 changes: 2 additions & 2 deletions templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
a.light { color: #AAA; text-decoration: none }
a.light:hover { text-decoration: underline }
</style>
<title>{% block title %}snippets{% endblock %}</title>
<title>{% block title %}mini snippets{% endblock %}</title> <!-- FIX ME -->
</head>

<body>
<h1><a class="light" style="color: #2398C9" href="/">snippets</a></h1>
<h1><a class="light" style="color: #2398C9" href="/">미니 스니펫</a></h1> <!-- FIX ME -->
{% block body %}
{% endblock %}
</body>
Expand Down
Binary file added templates/favicon.ico
Binary file not shown.
23 changes: 21 additions & 2 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,27 @@ <h2><a href="/user/{{ current_user.email }}">{{ current_user.pretty_name }}</a><

</td></tr></table>
<br/>

send your snippets to snippets@fssnippets.appspotmail.com by monday afternoon!
<!-- FIX ME BEGIN -->
<h4>스니펫 사용법</h4>
스니펫을 일요일까지 보내주세요: <b>snippets@minisnippets.appspotmail.com </b>
<br/><br/>
리마인더 메일은 금요일 오후 5시, 다이제스트 메일은 월요일 오전 9시에 발송됩니다.
<br/><br/>
스니펫 작성 날짜에 따른 입력 기준
<ul>
<li>월요일에 작성 => 해당주 입력됨</li>
<li>화~일요일에 작성 => 다음주 입력됨</li>
</ul>
스니펫 메일을 다시 보내면 수정할 수 있습니다.
<br/><br/>
서명 문자(== 또는 --) 이후는 trim 되어 입력됩니다.
<br/><br/>
<h4>스니펫 기본 설정</h4>
<ol>
<li>자신의 태그란에 팀명을 넣어주세요.</li>
<li>이메일이나 태그를 follow 해주세요. 다이제스트 메일로 발송됩니다.</li>
</ol>
<!-- FIX ME END -->
<br/><br/>
<table cellspacing=20>
<tr>
Expand Down