forked from mrlan/EnglishPal
Merge branch 'master' of https://github.com/lanlab-org/EnglishPal into SPM-Spring2021-2597-占健豪201831990539
Conflicts: app/main.pyBugFix254-Author-ZhanJianhao^2
commit
dcfed23d6f
|
@ -7,6 +7,5 @@ app/static/img/
|
||||||
app/static/frequency/frequency_*.pickle
|
app/static/frequency/frequency_*.pickle
|
||||||
app/static/frequency/frequency.p
|
app/static/frequency/frequency.p
|
||||||
app/static/wordfreqapp.db
|
app/static/wordfreqapp.db
|
||||||
app/static/wordfreqapp.sql
|
|
||||||
app/static/donate-the-author.jpg
|
app/static/donate-the-author.jpg
|
||||||
app/static/donate-the-author-hidden.jpg
|
app/static/donate-the-author-hidden.jpg
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
FROM tiangolo/uwsgi-nginx-flask:python3.6
|
||||||
|
COPY ./app /app
|
|
@ -0,0 +1,34 @@
|
||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('MakeDatabasefile') {
|
||||||
|
steps {
|
||||||
|
sh 'touch ./app/static/wordfreqapp.db && rm -f ./app/static/wordfreqapp.db'
|
||||||
|
sh 'cat ./app/static/wordfreqapp.sql | sqlite3 ./app/static/wordfreqapp.db'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('BuildIt') {
|
||||||
|
steps {
|
||||||
|
echo 'Building..'
|
||||||
|
sh 'sudo docker build -t englishpal .'
|
||||||
|
sh 'sudo docker stop $(docker ps -aq)'
|
||||||
|
sh 'sudo docker run -d -p 91:80 -v /var/lib/jenkins/workspace/EnglishPal_Pipeline_master/app/static/frequency:/app/static/frequency -t englishpal'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('TestIt') {
|
||||||
|
steps {
|
||||||
|
echo 'Testing..'
|
||||||
|
sh 'sudo docker run -d -p 4444:4444 selenium/standalone-chrome'
|
||||||
|
sh 'pip3 install pytest -U -q'
|
||||||
|
sh 'pip3 install selenium -U -q'
|
||||||
|
sh 'pytest -v -s --html=EnglishPalTestReport.html ./app/test'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stage('DeployIt') {
|
||||||
|
steps {
|
||||||
|
echo 'Deploying (TBD)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
在生词簿每个单词后面,加上两个按钮,熟悉与不熟悉:
|
||||||
|
1.如果点熟悉,就将生词簿中该单词后面记录的添加次数减一,直至减为0,就将该单词从生词簿中移除。
|
||||||
|
2.如果点不熟悉,就将生词簿中该单词后面记录的添加次数加一。
|
||||||
|
|
||||||
|
- 朱文绮
|
||||||
|
|
56
app/main.py
56
app/main.py
|
@ -22,24 +22,20 @@ app.secret_key = 'lunch.time!'
|
||||||
path_prefix = '/var/www/wordfreq/wordfreq/'
|
path_prefix = '/var/www/wordfreq/wordfreq/'
|
||||||
path_prefix = './' # comment this line in deployment
|
path_prefix = './' # comment this line in deployment
|
||||||
|
|
||||||
|
|
||||||
def get_random_image(path):
|
def get_random_image(path):
|
||||||
img_path = random.choice(glob.glob(os.path.join(path, '*.jpg')))
|
img_path = random.choice(glob.glob(os.path.join(path, '*.jpg')))
|
||||||
return img_path[img_path.rfind('/static'):]
|
return img_path[img_path.rfind('/static'):]
|
||||||
|
|
||||||
|
|
||||||
def get_random_ads():
|
def get_random_ads():
|
||||||
ads = random.choice(['个性化分析精准提升', '你的专有单词本', '智能捕捉阅读弱点,针对性提高你的阅读水平'])
|
ads = random.choice(['个性化分析精准提升', '你的专有单词本', '智能捕捉阅读弱点,针对性提高你的阅读水平'])
|
||||||
return ads + '。 <a href="/signup">试试</a>吧!'
|
return ads + '。 <a href="/signup">试试</a>吧!'
|
||||||
|
|
||||||
|
|
||||||
def load_freq_history(path):
|
def load_freq_history(path):
|
||||||
d = {}
|
d = {}
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
d = pickle_idea.load_record(path)
|
d = pickle_idea.load_record(path)
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
|
||||||
def verify_user(username, password):
|
def verify_user(username, password):
|
||||||
rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
|
rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
|
||||||
rq.instructions("SELECT * FROM user WHERE name='%s' AND password='%s'" % (username, password))
|
rq.instructions("SELECT * FROM user WHERE name='%s' AND password='%s'" % (username, password))
|
||||||
|
@ -47,7 +43,6 @@ def verify_user(username, password):
|
||||||
result = rq.get_results()
|
result = rq.get_results()
|
||||||
return result != []
|
return result != []
|
||||||
|
|
||||||
|
|
||||||
def add_user(username, password):
|
def add_user(username, password):
|
||||||
start_date = datetime.now().strftime('%Y%m%d')
|
start_date = datetime.now().strftime('%Y%m%d')
|
||||||
expiry_date = '20211230'
|
expiry_date = '20211230'
|
||||||
|
@ -63,7 +58,6 @@ def check_username_availability(username):
|
||||||
result = rq.get_results()
|
result = rq.get_results()
|
||||||
return result == []
|
return result == []
|
||||||
|
|
||||||
|
|
||||||
def get_expiry_date(username):
|
def get_expiry_date(username):
|
||||||
rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
|
rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
|
||||||
rq.instructions("SELECT expiry_date FROM user WHERE name='%s'" % (username))
|
rq.instructions("SELECT expiry_date FROM user WHERE name='%s'" % (username))
|
||||||
|
@ -75,11 +69,13 @@ def get_expiry_date(username):
|
||||||
return '20191024'
|
return '20191024'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def within_range(x, y, r):
|
def within_range(x, y, r):
|
||||||
return x > y and abs(x - y) <= r
|
return x > y and abs(x - y) <= r
|
||||||
|
|
||||||
|
|
||||||
def get_today_article(user_word_list, articleID):
|
def get_today_article(user_word_list, articleID):
|
||||||
|
|
||||||
rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
|
rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
|
||||||
if articleID == None:
|
if articleID == None:
|
||||||
rq.instructions("SELECT * FROM article")
|
rq.instructions("SELECT * FROM article")
|
||||||
|
@ -95,8 +91,7 @@ def get_today_article(user_word_list, articleID):
|
||||||
|
|
||||||
d = {}
|
d = {}
|
||||||
d_user = load_freq_history(user_word_list)
|
d_user = load_freq_history(user_word_list)
|
||||||
user_level = user_difficulty_level(d_user,
|
user_level = user_difficulty_level(d_user, d3) # more consideration as user's behaviour is dynamic. Time factor should be considered.
|
||||||
d3) # more consideration as user's behaviour is dynamic. Time factor should be considered.
|
|
||||||
random.shuffle(result) # shuffle list
|
random.shuffle(result) # shuffle list
|
||||||
d = random.choice(result)
|
d = random.choice(result)
|
||||||
text_level = text_difficulty_level(d['text'], d3)
|
text_level = text_difficulty_level(d['text'], d3)
|
||||||
|
@ -108,8 +103,7 @@ def get_today_article(user_word_list, articleID):
|
||||||
d = reading
|
d = reading
|
||||||
break
|
break
|
||||||
|
|
||||||
s = '<p><i>According to your word list, your level is <b>%4.2f</b> and we have chosen an article with a difficulty level of <b>%4.2f</b> for you.</i></p>' % (
|
s = '<p><i>According to your word list, your level is <b>%4.2f</b> and we have chosen an article with a difficulty level of <b>%4.2f</b> for you.</i></p>' % (user_level, text_level)
|
||||||
user_level, text_level)
|
|
||||||
s += '<p><b>%s</b></p>' % (d['date'])
|
s += '<p><b>%s</b></p>' % (d['date'])
|
||||||
s += '<p><font size=+2>%s</font></p>' % (d['text'])
|
s += '<p><font size=+2>%s</font></p>' % (d['text'])
|
||||||
s += '<p><i>%s</i></p>' % (d['source'])
|
s += '<p><i>%s</i></p>' % (d['source'])
|
||||||
|
@ -177,6 +171,7 @@ def get_answer_part(s):
|
||||||
return html_code
|
return html_code
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/<username>/reset", methods=['GET', 'POST'])
|
@app.route("/<username>/reset", methods=['GET', 'POST'])
|
||||||
def user_reset(username):
|
def user_reset(username):
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
|
@ -201,6 +196,7 @@ def mark_word():
|
||||||
return 'Under construction'
|
return 'Under construction'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@app.route("/", methods=['GET', 'POST'])
|
@app.route("/", methods=['GET', 'POST'])
|
||||||
def mainpage():
|
def mainpage():
|
||||||
if request.method == 'POST': # when we submit a form
|
if request.method == 'POST': # when we submit a form
|
||||||
|
@ -210,8 +206,7 @@ def mainpage():
|
||||||
page = '<form method="post" action="/mark">\n'
|
page = '<form method="post" action="/mark">\n'
|
||||||
count = 1
|
count = 1
|
||||||
for x in lst:
|
for x in lst:
|
||||||
page += '<p><font color="grey">%d</font>: <a href="%s">%s</a> (%d) <input type="checkbox" name="marked" value="%s"></p>\n' % (
|
page += '<p><font color="grey">%d</font>: <a href="%s">%s</a> (%d) <input type="checkbox" name="marked" value="%s"></p>\n' % (count, youdao_link(x[0]), x[0], x[1], x[0])
|
||||||
count, youdao_link(x[0]), x[0], x[1], x[0])
|
|
||||||
count += 1
|
count += 1
|
||||||
page += ' <input type="submit" value="确定并返回"/>\n'
|
page += ' <input type="submit" value="确定并返回"/>\n'
|
||||||
page += '</form>\n'
|
page += '</form>\n'
|
||||||
|
@ -279,31 +274,24 @@ def user_mark_word(username):
|
||||||
def unfamiliar(username,word):
|
def unfamiliar(username,word):
|
||||||
user_freq_record = path_prefix + 'static/frequency/' + 'frequency_%s.pickle' % (username)
|
user_freq_record = path_prefix + 'static/frequency/' + 'frequency_%s.pickle' % (username)
|
||||||
pickle_idea.unfamiliar(user_freq_record,word)
|
pickle_idea.unfamiliar(user_freq_record,word)
|
||||||
|
|
||||||
session['thisWord'] = word # 1. put a word into session
|
|
||||||
|
|
||||||
return redirect(url_for('userpage', username=username))
|
return redirect(url_for('userpage', username=username))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/<username>/<word>/familiar", methods=['GET', 'POST'])
|
@app.route("/<username>/<word>/familiar", methods=['GET', 'POST'])
|
||||||
def familiar(username,word):
|
def familiar(username,word):
|
||||||
user_freq_record = path_prefix + 'static/frequency/' + 'frequency_%s.pickle' % (username)
|
user_freq_record = path_prefix + 'static/frequency/' + 'frequency_%s.pickle' % (username)
|
||||||
pickle_idea.familiar(user_freq_record,word)
|
pickle_idea.familiar(user_freq_record,word)
|
||||||
|
|
||||||
session['thisWord'] = word # 1. put a word into session
|
|
||||||
|
|
||||||
return redirect(url_for('userpage', username=username))
|
return redirect(url_for('userpage', username=username))
|
||||||
|
|
||||||
|
|
||||||
@app.route("/<username>", methods=['GET', 'POST'])
|
@app.route("/<username>", methods=['GET', 'POST'])
|
||||||
def userpage(username):
|
def userpage(username):
|
||||||
|
|
||||||
if not session.get('logged_in'):
|
if not session.get('logged_in'):
|
||||||
return '<p>请先<a href="/login">登录</a>。</p>'
|
return '<p>请先<a href="/login">登录</a>。</p>'
|
||||||
|
|
||||||
user_expiry_date = session.get('expiry_date')
|
user_expiry_date = session.get('expiry_date')
|
||||||
if datetime.now().strftime('%Y%m%d') > user_expiry_date:
|
if datetime.now().strftime('%Y%m%d') > user_expiry_date:
|
||||||
return '<p>账号 %s 过期。</p><p>为了提高服务质量,English Pal 收取会员费用, 每天0元。</p> <p>请决定你要试用的时间长度,扫描下面支付宝二维码支付。 支付时请注明<i>English Pal Membership Fee</i>。 我们会于12小时内激活账号。</p><p><img src="static/donate-the-author-hidden.jpg" width="120px" alt="支付宝二维码" /></p><p>如果有问题,请加开发者微信 torontohui。</p> <p><a href="/logout">登出</a></p>' % (
|
return '<p>账号 %s 过期。</p><p>为了提高服务质量,English Pal 收取会员费用, 每天0元。</p> <p>请决定你要试用的时间长度,扫描下面支付宝二维码支付。 支付时请注明<i>English Pal Membership Fee</i>。 我们会于12小时内激活账号。</p><p><img src="static/donate-the-author-hidden.jpg" width="120px" alt="支付宝二维码" /></p><p>如果有问题,请加开发者微信 torontohui。</p> <p><a href="/logout">登出</a></p>' % (username)
|
||||||
username)
|
|
||||||
|
|
||||||
username = session.get('username')
|
username = session.get('username')
|
||||||
|
|
||||||
|
@ -321,22 +309,13 @@ def userpage(username):
|
||||||
count = 1
|
count = 1
|
||||||
words_tests_dict = pickle_idea.load_record(path_prefix + 'static/words_and_tests.p')
|
words_tests_dict = pickle_idea.load_record(path_prefix + 'static/words_and_tests.p')
|
||||||
for x in lst:
|
for x in lst:
|
||||||
page += '<p><font color="grey">%d</font>: <a href="%s" title="%s">%s</a> (%d) <input type="checkbox" name="marked" value="%s"></p>\n' % (
|
page += '<p><font color="grey">%d</font>: <a href="%s" title="%s">%s</a> (%d) <input type="checkbox" name="marked" value="%s"></p>\n' % (count, youdao_link(x[0]), appears_in_test(x[0], words_tests_dict), x[0], x[1], x[0])
|
||||||
count, youdao_link(x[0]), appears_in_test(x[0], words_tests_dict), x[0], x[1], x[0])
|
|
||||||
count += 1
|
count += 1
|
||||||
page += '</form>\n'
|
page += '</form>\n'
|
||||||
return page
|
return page
|
||||||
|
|
||||||
elif request.method == 'GET': # when we load a html page
|
elif request.method == 'GET': # when we load a html page
|
||||||
page = '<meta charset="UTF8">\n'
|
page = '<meta charset="UTF8">\n'
|
||||||
|
|
||||||
if session.get('thisWord'):
|
|
||||||
page += '''
|
|
||||||
<script type="text/javascript">
|
|
||||||
location.href = "#aaa" // 2. define a anchor URL and point to the anchor in the page whose id is aaa
|
|
||||||
</script>
|
|
||||||
'''
|
|
||||||
|
|
||||||
page += '<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=3.0, user-scalable=yes" />\n'
|
page += '<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=3.0, user-scalable=yes" />\n'
|
||||||
page += '<meta name="format-detection" content="telephone=no" />\n' # forbid treating numbers as cell numbers in smart phones
|
page += '<meta name="format-detection" content="telephone=no" />\n' # forbid treating numbers as cell numbers in smart phones
|
||||||
page += '<title>EnglishPal Study Room for %s</title>' % (username)
|
page += '<title>EnglishPal Study Room for %s</title>' % (username)
|
||||||
|
@ -375,20 +354,15 @@ def userpage(username):
|
||||||
for x in sort_in_descending_order(lst2):
|
for x in sort_in_descending_order(lst2):
|
||||||
word = x[0]
|
word = x[0]
|
||||||
freq = x[1]
|
freq = x[1]
|
||||||
if session.get('thisWord') == x[0]:
|
|
||||||
page += '<a name="aaa"></a>' # 3. anchor
|
|
||||||
if isinstance(d[word], list): # d[word] is a list of dates
|
if isinstance(d[word], list): # d[word] is a list of dates
|
||||||
if freq > 1:
|
if freq > 1:
|
||||||
page += '<p class="new-word"> <a href="%s">%s</a>(<a title="%s">%d</a>) <a href="%s/%s/familiar">熟悉</a> <a href="%s/%s/unfamiliar">不熟悉</a> </p>\n' % (
|
page += '<p class="new-word"> <a href="%s">%s</a>(<a title="%s">%d</a>) <a href="%s/%s/familiar">熟悉</a> <a href="%s/%s/unfamiliar">不熟悉</a> </p>\n' % (youdao_link(word), word, '; '.join(d[word]), freq,username, word,username,word)
|
||||||
youdao_link(word), word, '; '.join(d[word]), freq, username, word, username, word)
|
|
||||||
else:
|
else:
|
||||||
page += '<p class="new-word"> <a href="%s">%s</a>(<a title="%s">%d</a>) <a href="%s/%s/familiar">熟悉</a> <a href="%s/%s/unfamiliar">不熟悉</a> </p>\n' % (
|
page += '<p class="new-word"> <a href="%s">%s</a>(<a title="%s">%d</a>) <a href="%s/%s/familiar">熟悉</a> <a href="%s/%s/unfamiliar">不熟悉</a> </p>\n' % (youdao_link(word), word, '; '.join(d[word]), freq,username, word,username,word)
|
||||||
youdao_link(word), word, '; '.join(d[word]), freq, username, word, username, word)
|
|
||||||
elif isinstance(d[word], int): # d[word] is a frequency. to migrate from old format.
|
elif isinstance(d[word], int): # d[word] is a frequency. to migrate from old format.
|
||||||
page += '<a href="%s">%s</a>%d\n' % (youdao_link(word), word, freq)
|
page += '<a href="%s">%s</a>%d\n' % (youdao_link(word), word, freq)
|
||||||
return page
|
return page
|
||||||
|
|
||||||
|
|
||||||
### Sign-up, login, logout ###
|
### Sign-up, login, logout ###
|
||||||
@app.route("/signup", methods=['GET', 'POST'])
|
@app.route("/signup", methods=['GET', 'POST'])
|
||||||
def signup():
|
def signup():
|
||||||
|
@ -423,8 +397,7 @@ def login():
|
||||||
if not session.get('logged_in'):
|
if not session.get('logged_in'):
|
||||||
return render_template('login.html')
|
return render_template('login.html')
|
||||||
else:
|
else:
|
||||||
return '你已登录 <a href="/%s">%s</a>。 登出点击<a href="/logout">这里</a>。' % (
|
return '你已登录 <a href="/%s">%s</a>。 登出点击<a href="/logout">这里</a>。' % (session['username'], session['username'])
|
||||||
session['username'], session['username'])
|
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
# check database and verify user
|
# check database and verify user
|
||||||
username = request.form['username']
|
username = request.form['username']
|
||||||
|
@ -454,3 +427,4 @@ if __name__ == '__main__':
|
||||||
app.run(debug=True)
|
app.run(debug=True)
|
||||||
#app.run(debug=True, port='6000')
|
#app.run(debug=True, port='6000')
|
||||||
#app.run(host='0.0.0.0', debug=True, port='6000')
|
#app.run(host='0.0.0.0', debug=True, port='6000')
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
# Task: incorporate the functions into wordfreqCMD.py such that it will also show cumulative frequency.
|
# Task: incorporate the functions into wordfreqCMD.py such that it will also show cumulative frequency.
|
||||||
|
|
||||||
import pickle
|
import pickle
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
def lst2dict(lst, d):
|
def lst2dict(lst, d):
|
||||||
|
@ -53,7 +54,22 @@ def save_frequency_to_pickle(d, pickle_fname):
|
||||||
pickle.dump(d2, f)
|
pickle.dump(d2, f)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
def unfamiliar(path,word):
|
||||||
|
f = open(path,"rb")
|
||||||
|
dic = pickle.load(f)
|
||||||
|
dic[word] += [datetime.now().strftime('%Y%m%d%H%M')]
|
||||||
|
fp = open(path,"wb")
|
||||||
|
pickle.dump(dic,fp)
|
||||||
|
|
||||||
|
def familiar(path,word):
|
||||||
|
f = open(path,"rb")
|
||||||
|
dic = pickle.load(f)
|
||||||
|
if len(dic[word])>1:
|
||||||
|
del dic[word][0]
|
||||||
|
else:
|
||||||
|
dic.pop(word)
|
||||||
|
fp = open(path,"wb")
|
||||||
|
pickle.dump(dic,fp)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -67,15 +67,5 @@ def test_add_word_and_essay_does_not_change():
|
||||||
index = current_essay_content.find('for you.')
|
index = current_essay_content.find('for you.')
|
||||||
assert current_essay_content[index:] == essay_content[index:]
|
assert current_essay_content[index:] == essay_content[index:]
|
||||||
|
|
||||||
# click the Next button. Now the essay should change.
|
|
||||||
elem = driver.find_element_by_link_text('下一篇') # 找到get所有词频按钮
|
|
||||||
elem.click()
|
|
||||||
|
|
||||||
# compare again
|
|
||||||
driver.save_screenshot('./app/test/test_add_word_and_essay_does_not_change_pic2.png')
|
|
||||||
elem = driver.find_element_by_id('text-content')
|
|
||||||
next_essay_content = elem.text
|
|
||||||
|
|
||||||
assert current_essay_content[index:] != next_essay_content[index:]
|
|
||||||
finally:
|
finally:
|
||||||
driver.quit()
|
driver.quit()
|
||||||
|
|
|
@ -41,8 +41,8 @@ def test_next():
|
||||||
essay_content = elem.text
|
essay_content = elem.text
|
||||||
|
|
||||||
# click Next
|
# click Next
|
||||||
differ = 0
|
diff = 0
|
||||||
for i in range(3):
|
for i in range(5):
|
||||||
elem = driver.find_element_by_link_text('下一篇')
|
elem = driver.find_element_by_link_text('下一篇')
|
||||||
elem.click()
|
elem.click()
|
||||||
driver.save_screenshot('./app/test/test_next_essay_pic1.png')
|
driver.save_screenshot('./app/test/test_next_essay_pic1.png')
|
||||||
|
|
Loading…
Reference in New Issue