Compare commits
	
		
			1 Commits 
		
	
	
		
			master
			...
			Bug410-Dua
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								
									
								
								 | 
						d52e60bdd2 | 
							
								
								
									
										530
									
								
								app/main.py
								
								
								
								
							
							
						
						
									
										530
									
								
								app/main.py
								
								
								
								
							| 
						 | 
					@ -6,61 +6,214 @@
 | 
				
			||||||
# Written permission must be obtained from the author for commercial uses.
 | 
					# Written permission must be obtained from the author for commercial uses.
 | 
				
			||||||
###########################################################################
 | 
					###########################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from Login import *
 | 
					from WordFreq import WordFreq
 | 
				
			||||||
from Article import *
 | 
					from wordfreqCMD import youdao_link, sort_in_descending_order
 | 
				
			||||||
import Yaml
 | 
					from UseSqlite import InsertQuery, RecordQuery
 | 
				
			||||||
from user_service import userService
 | 
					import pickle_idea, pickle_idea2
 | 
				
			||||||
from account_service import accountService
 | 
					import os
 | 
				
			||||||
 | 
					import random, glob
 | 
				
			||||||
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					from flask import Flask, request, redirect, render_template, url_for, session, abort, flash, get_flashed_messages
 | 
				
			||||||
 | 
					from difficulty import get_difficulty_level, text_difficulty_level, user_difficulty_level
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app = Flask(__name__)
 | 
					app = Flask(__name__)
 | 
				
			||||||
app.secret_key = 'lunch.time!'
 | 
					app.secret_key = 'lunch.time!'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# 将蓝图注册到Lab app
 | 
					 | 
				
			||||||
app.register_blueprint(userService)
 | 
					 | 
				
			||||||
app.register_blueprint(accountService)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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):
 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    返回随机图
 | 
					 | 
				
			||||||
    :param path: 图片文件(JPEG格式),不包含后缀名
 | 
					 | 
				
			||||||
    :return:
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    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():
 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    返回随机广告
 | 
					 | 
				
			||||||
    :return: 一个广告(包含HTML标签)
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    ads = random.choice(['个性化分析精准提升', '你的专有单词本', '智能捕捉阅读弱点,针对性提高你的阅读水平'])
 | 
					    ads = random.choice(['个性化分析精准提升', '你的专有单词本', '智能捕捉阅读弱点,针对性提高你的阅读水平'])
 | 
				
			||||||
    return ads + '。 <a href="/signup">试试</a>吧!'
 | 
					    return ads + '。 <a href="/signup">试试</a>吧!'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def total_number_of_essays():
 | 
				
			||||||
 | 
					    rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
 | 
				
			||||||
 | 
					    rq.instructions("SELECT * FROM article")
 | 
				
			||||||
 | 
					    rq.do()
 | 
				
			||||||
 | 
					    result = rq.get_results()
 | 
				
			||||||
 | 
					    return  len(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def load_freq_history(path):
 | 
				
			||||||
 | 
					    d = {}
 | 
				
			||||||
 | 
					    if os.path.exists(path):
 | 
				
			||||||
 | 
					        d = pickle_idea.load_record(path)
 | 
				
			||||||
 | 
					    return d
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def verify_user(username, password):
 | 
				
			||||||
 | 
					    rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
 | 
				
			||||||
 | 
					    rq.instructions_with_parameters("SELECT * FROM user WHERE name=? AND password=?", (username, password))
 | 
				
			||||||
 | 
					    rq.do_with_parameters()
 | 
				
			||||||
 | 
					    result = rq.get_results()
 | 
				
			||||||
 | 
					    return result != []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def add_user(username, password):
 | 
				
			||||||
 | 
					    start_date = datetime.now().strftime('%Y%m%d')
 | 
				
			||||||
 | 
					    expiry_date = '20211230'
 | 
				
			||||||
 | 
					    rq = InsertQuery(path_prefix + 'static/wordfreqapp.db')
 | 
				
			||||||
 | 
					    rq.instructions("INSERT INTO user Values ('%s', '%s', '%s', '%s')" % (username, password, start_date, expiry_date))
 | 
				
			||||||
 | 
					    rq.do()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					def check_username_availability(username):
 | 
				
			||||||
 | 
					    rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
 | 
				
			||||||
 | 
					    rq.instructions("SELECT * FROM user WHERE name='%s'" % (username))
 | 
				
			||||||
 | 
					    rq.do()
 | 
				
			||||||
 | 
					    result = rq.get_results()
 | 
				
			||||||
 | 
					    return  result == []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_expiry_date(username):
 | 
				
			||||||
 | 
					    rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
 | 
				
			||||||
 | 
					    rq.instructions("SELECT expiry_date FROM user WHERE name='%s'" % (username))
 | 
				
			||||||
 | 
					    rq.do()
 | 
				
			||||||
 | 
					    result = rq.get_results()
 | 
				
			||||||
 | 
					    if len(result) > 0:
 | 
				
			||||||
 | 
					        return  result[0]['expiry_date']
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        return '20191024'
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def within_range(x, y, r):
 | 
				
			||||||
 | 
					    return x > y and abs(x - y) <= r 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_article_title(s):
 | 
				
			||||||
 | 
					    return s.split('\n')[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_article_body(s):
 | 
				
			||||||
 | 
					    lst = s.split('\n')
 | 
				
			||||||
 | 
					    lst.pop(0) # remove the first line
 | 
				
			||||||
 | 
					    return '\n'.join(lst) 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_today_article(user_word_list, articleID):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rq = RecordQuery(path_prefix + 'static/wordfreqapp.db')
 | 
				
			||||||
 | 
					    if articleID == None:    
 | 
				
			||||||
 | 
					        rq.instructions("SELECT * FROM article")
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        rq.instructions('SELECT * FROM article WHERE article_id=%d' % (articleID))
 | 
				
			||||||
 | 
					    rq.do()
 | 
				
			||||||
 | 
					    result = rq.get_results()
 | 
				
			||||||
 | 
					    random.shuffle(result)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    # Choose article according to reader's level
 | 
				
			||||||
 | 
					    d1 = load_freq_history(path_prefix + 'static/frequency/frequency.p')
 | 
				
			||||||
 | 
					    d2 = load_freq_history(path_prefix + 'static/words_and_tests.p')
 | 
				
			||||||
 | 
					    d3 = get_difficulty_level(d1, d2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    d = {}
 | 
				
			||||||
 | 
					    d_user = load_freq_history(user_word_list)
 | 
				
			||||||
 | 
					    user_level = user_difficulty_level(d_user, d3) # more consideration as user's behaviour is dynamic. Time factor should be considered.
 | 
				
			||||||
 | 
					    random.shuffle(result) # shuffle list
 | 
				
			||||||
 | 
					    d = random.choice(result)
 | 
				
			||||||
 | 
					    text_level = text_difficulty_level(d['text'], d3)
 | 
				
			||||||
 | 
					    if articleID == None:
 | 
				
			||||||
 | 
					        for reading in result:
 | 
				
			||||||
 | 
					            text_level = text_difficulty_level(reading['text'], d3)
 | 
				
			||||||
 | 
					            factor = random.gauss(0.8, 0.1) # a number drawn from Gaussian distribution with a mean of 0.8 and a stand deviation of 1
 | 
				
			||||||
 | 
					            if within_range(text_level, user_level, (8.0 - user_level)*factor):
 | 
				
			||||||
 | 
					                d = reading
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					    s = '<div class="alert alert-success" role="alert">According to your word list, your level is <span class="badge bg-success">%4.2f</span>  and we have chosen an article with a difficulty level of <span class="badge bg-success">%4.2f</span> for you.</div>' % (user_level, text_level)
 | 
				
			||||||
 | 
					    s += '<p class="text-muted">Article added on: %s</p>' % (d['date'])
 | 
				
			||||||
 | 
					    s += '<div class="p-3 mb-2 bg-light text-dark">'
 | 
				
			||||||
 | 
					    article_title = get_article_title(d['text'])
 | 
				
			||||||
 | 
					    article_body = get_article_body(d['text'])
 | 
				
			||||||
 | 
					    s += '<p class="display-3">%s</p>' % (article_title)
 | 
				
			||||||
 | 
					    s += '<p class="lead">%s</p>' % (article_body)
 | 
				
			||||||
 | 
					    s += '<p><small class="text-muted">%s</small></p>' % (d['source'])
 | 
				
			||||||
 | 
					    s += '<p><b>%s</b></p>' % (get_question_part(d['question']))
 | 
				
			||||||
 | 
					    s = s.replace('\n', '<br/>')    
 | 
				
			||||||
 | 
					    s += '%s' % (get_answer_part(d['question']))
 | 
				
			||||||
 | 
					    s += '</div>'
 | 
				
			||||||
 | 
					    session['articleID'] = d['article_id']
 | 
				
			||||||
 | 
					    return s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def appears_in_test(word, d):
 | 
					def appears_in_test(word, d):
 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    如果字符串里没有指定的单词,则返回逗号加单词
 | 
					 | 
				
			||||||
    :param word: 指定单词
 | 
					 | 
				
			||||||
    :param d: 字符串
 | 
					 | 
				
			||||||
    :return: 逗号加单词
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    if not word in d:
 | 
					    if not word in d:
 | 
				
			||||||
        return ''
 | 
					        return ''
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        return ','.join(d[word])
 | 
					        return ','.join(d[word])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_time():
 | 
				
			||||||
 | 
					    return datetime.now().strftime('%Y%m%d%H%M') # upper to minutes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_question_part(s):
 | 
				
			||||||
 | 
					    s = s.strip()
 | 
				
			||||||
 | 
					    result = []
 | 
				
			||||||
 | 
					    flag = 0
 | 
				
			||||||
 | 
					    for line in s.split('\n'):
 | 
				
			||||||
 | 
					        line = line.strip()
 | 
				
			||||||
 | 
					        if line == 'QUESTION':
 | 
				
			||||||
 | 
					            result.append(line)
 | 
				
			||||||
 | 
					            flag = 1
 | 
				
			||||||
 | 
					        elif line == 'ANSWER':
 | 
				
			||||||
 | 
					            flag = 0
 | 
				
			||||||
 | 
					        elif flag == 1:
 | 
				
			||||||
 | 
					            result.append(line)
 | 
				
			||||||
 | 
					    return '\n'.join(result)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_answer_part(s):
 | 
				
			||||||
 | 
					    s = s.strip()
 | 
				
			||||||
 | 
					    result = []
 | 
				
			||||||
 | 
					    flag = 0
 | 
				
			||||||
 | 
					    for line in s.split('\n'):
 | 
				
			||||||
 | 
					        line = line.strip()
 | 
				
			||||||
 | 
					        if line == 'ANSWER':
 | 
				
			||||||
 | 
					            flag = 1
 | 
				
			||||||
 | 
					        elif flag == 1:
 | 
				
			||||||
 | 
					            result.append(line)
 | 
				
			||||||
 | 
					    # https://css-tricks.com/snippets/javascript/showhide-element/
 | 
				
			||||||
 | 
					    js = '''
 | 
				
			||||||
 | 
					<script type="text/javascript">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function toggle_visibility(id) {
 | 
				
			||||||
 | 
					       var e = document.getElementById(id);
 | 
				
			||||||
 | 
					       if(e.style.display == 'block')
 | 
				
			||||||
 | 
					          e.style.display = 'none';
 | 
				
			||||||
 | 
					       else
 | 
				
			||||||
 | 
					          e.style.display = 'block';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</script>   
 | 
				
			||||||
 | 
					    '''
 | 
				
			||||||
 | 
					    html_code = js
 | 
				
			||||||
 | 
					    html_code += '\n'
 | 
				
			||||||
 | 
					    html_code += '<button onclick="toggle_visibility(\'answer\');">ANSWER</button>\n'
 | 
				
			||||||
 | 
					    html_code += '<div id="answer" style="display:none;">%s</div>\n' % ('\n'.join(result))
 | 
				
			||||||
 | 
					    return html_code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_flashed_messages_if_any():
 | 
				
			||||||
 | 
					    messages = get_flashed_messages()
 | 
				
			||||||
 | 
					    s = ''
 | 
				
			||||||
 | 
					    for message in messages:
 | 
				
			||||||
 | 
					        s += '<div class="alert alert-warning" role="alert">'
 | 
				
			||||||
 | 
					        s += f'Congratulations! {message}'
 | 
				
			||||||
 | 
					        s += '</div>'
 | 
				
			||||||
 | 
					    return s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.route("/<username>/reset", methods=['GET', 'POST'])
 | 
				
			||||||
 | 
					def user_reset(username):
 | 
				
			||||||
 | 
					    if request.method == 'GET':
 | 
				
			||||||
 | 
					        session['articleID'] = None
 | 
				
			||||||
 | 
					        return redirect(url_for('userpage', username=username))
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        return 'Under construction'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.route("/mark", methods=['GET', 'POST'])
 | 
					@app.route("/mark", methods=['GET', 'POST'])
 | 
				
			||||||
def mark_word():
 | 
					def mark_word():
 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    标记单词
 | 
					 | 
				
			||||||
    :return: 重定位到主界面
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    if request.method == 'POST':
 | 
					    if request.method == 'POST':
 | 
				
			||||||
        d = load_freq_history(path_prefix + 'static/frequency/frequency.p')
 | 
					        d = load_freq_history(path_prefix + 'static/frequency/frequency.p')
 | 
				
			||||||
        lst_history = pickle_idea.dict2lst(d)
 | 
					        lst_history = pickle_idea.dict2lst(d)
 | 
				
			||||||
| 
						 | 
					@ -70,45 +223,318 @@ def mark_word():
 | 
				
			||||||
        d = pickle_idea.merge_frequency(lst, lst_history)
 | 
					        d = pickle_idea.merge_frequency(lst, lst_history)
 | 
				
			||||||
        pickle_idea.save_frequency_to_pickle(d, path_prefix + 'static/frequency/frequency.p')
 | 
					        pickle_idea.save_frequency_to_pickle(d, path_prefix + 'static/frequency/frequency.p')
 | 
				
			||||||
        return redirect(url_for('mainpage'))
 | 
					        return redirect(url_for('mainpage'))
 | 
				
			||||||
    else: # 不回应GET请求
 | 
					    else:
 | 
				
			||||||
        return 'Under construction'
 | 
					        return 'Under construction'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@app.route("/", methods=['GET', 'POST'])
 | 
					@app.route("/", methods=['GET', 'POST'])
 | 
				
			||||||
def mainpage():
 | 
					def mainpage():
 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    根据GET或POST方法来返回不同的主界面
 | 
					 | 
				
			||||||
    :return: 主界面
 | 
					 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    if request.method == 'POST':  # when we submit a form
 | 
					    if request.method == 'POST':  # when we submit a form
 | 
				
			||||||
        content = request.form['content']
 | 
					        content = request.form['content']
 | 
				
			||||||
        f = WordFreq(content)
 | 
					        f = WordFreq(content)
 | 
				
			||||||
        lst = f.get_freq()
 | 
					        lst = f.get_freq()
 | 
				
			||||||
 | 
					        page = '<form method="post" action="/mark">\n'
 | 
				
			||||||
 | 
					        count = 1
 | 
				
			||||||
 | 
					        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' % (count, youdao_link(x[0]), x[0], x[1], x[0])
 | 
				
			||||||
 | 
					            count += 1
 | 
				
			||||||
 | 
					        page += ' <input type="submit" value="确定并返回"/>\n'
 | 
				
			||||||
 | 
					        page += '</form>\n'
 | 
				
			||||||
        # save history 
 | 
					        # save history 
 | 
				
			||||||
        d = load_freq_history(path_prefix + 'static/frequency/frequency.p')
 | 
					        d = load_freq_history(path_prefix + 'static/frequency/frequency.p')
 | 
				
			||||||
        lst_history = pickle_idea.dict2lst(d)
 | 
					        lst_history = pickle_idea.dict2lst(d)
 | 
				
			||||||
        d = pickle_idea.merge_frequency(lst, lst_history)
 | 
					        d = pickle_idea.merge_frequency(lst, lst_history)
 | 
				
			||||||
        pickle_idea.save_frequency_to_pickle(d, path_prefix + 'static/frequency/frequency.p')
 | 
					        pickle_idea.save_frequency_to_pickle(d, path_prefix + 'static/frequency/frequency.p')
 | 
				
			||||||
        return render_template('mainpage_post.html', lst=lst, yml=Yaml.yml)
 | 
					        
 | 
				
			||||||
 | 
					        return page
 | 
				
			||||||
 | 
					    elif request.method == 'GET': # when we load a html page
 | 
				
			||||||
 | 
					        page = '''
 | 
				
			||||||
 | 
					             <html lang="zh">
 | 
				
			||||||
 | 
					               <head>
 | 
				
			||||||
 | 
					               <meta charset="utf-8">
 | 
				
			||||||
 | 
					               <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=3.0, user-scalable=yes" />
 | 
				
			||||||
 | 
					               <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                 <title>EnglishPal 英文单词高效记</title>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					               </head>
 | 
				
			||||||
 | 
					               <body>
 | 
				
			||||||
 | 
					        '''
 | 
				
			||||||
 | 
					        page += '<div class="container-fluid">'
 | 
				
			||||||
 | 
					        page += '<p><b><font size="+3" color="red">English Pal - Learn English smartly!</font></b></p>'
 | 
				
			||||||
 | 
					        if session.get('logged_in'):
 | 
				
			||||||
 | 
					            page += ' <a href="%s">%s</a></p>\n' % (session['username'], session['username'])
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            page += '<p><a href="/login">登录</a>  <a href="/signup">成为会员</a> <a href="/static/usr/instructions.html">使用说明</a></p>\n'
 | 
				
			||||||
 | 
					        #page += '<p><img src="%s" width="400px" alt="advertisement"/></p>' % (get_random_image(path_prefix + 'static/img/'))
 | 
				
			||||||
 | 
					        page += '<p><b>%s</b></p>' % (get_random_ads())
 | 
				
			||||||
 | 
					        page += '<div class="alert alert-success" role="alert">共有文章 <span class="badge bg-success"> %d </span> 篇</div>' % (total_number_of_essays())
 | 
				
			||||||
 | 
					        page += '<p>粘帖1篇文章 (English only)</p>'
 | 
				
			||||||
 | 
					        page += '<form method="post" action="/">'
 | 
				
			||||||
 | 
					        page += ' <textarea name="content" rows="10" cols="120"></textarea><br/>'
 | 
				
			||||||
 | 
					        page += ' <input type="submit" value="get文章中的词频"/>'
 | 
				
			||||||
 | 
					        page += ' <input type="reset" value="清除"/>'
 | 
				
			||||||
 | 
					        page += '</form>'
 | 
				
			||||||
 | 
					        d = load_freq_history(path_prefix + 'static/frequency/frequency.p')
 | 
				
			||||||
 | 
					        if len(d) > 0:
 | 
				
			||||||
 | 
					            page += '<p><b>最常见的词</b></p>'
 | 
				
			||||||
 | 
					            for x in sort_in_descending_order(pickle_idea.dict2lst(d)):
 | 
				
			||||||
 | 
					                if x[1] <= 99:
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                page += '<a href="%s">%s</a> %d\n' % (youdao_link(x[0]), x[0], x[1])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        page += ' <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>'
 | 
				
			||||||
 | 
					        page += '</div>'
 | 
				
			||||||
 | 
					        page += '</body></html>'
 | 
				
			||||||
 | 
					        return page
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.route("/<username>/mark", methods=['GET', 'POST'])
 | 
				
			||||||
 | 
					def user_mark_word(username):
 | 
				
			||||||
 | 
					    username = session[username]
 | 
				
			||||||
 | 
					    user_freq_record = path_prefix + 'static/frequency/' +  'frequency_%s.pickle' % (username)
 | 
				
			||||||
 | 
					    if request.method == 'POST':
 | 
				
			||||||
 | 
					        d = load_freq_history(user_freq_record)
 | 
				
			||||||
 | 
					        lst_history = pickle_idea2.dict2lst(d)
 | 
				
			||||||
 | 
					        lst = []
 | 
				
			||||||
 | 
					        for word in request.form.getlist('marked'):
 | 
				
			||||||
 | 
					            lst.append((word, [get_time()]))
 | 
				
			||||||
 | 
					        d = pickle_idea2.merge_frequency(lst, lst_history)
 | 
				
			||||||
 | 
					        pickle_idea2.save_frequency_to_pickle(d, user_freq_record)
 | 
				
			||||||
 | 
					        return redirect(url_for('userpage', username=username))
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        return 'Under construction'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.route("/<username>/<word>/unfamiliar", methods=['GET', 'POST'])
 | 
				
			||||||
 | 
					def unfamiliar(username,word):
 | 
				
			||||||
 | 
					    user_freq_record = path_prefix + 'static/frequency/' + 'frequency_%s.pickle' % (username)
 | 
				
			||||||
 | 
					    pickle_idea.unfamiliar(user_freq_record,word)
 | 
				
			||||||
 | 
					    session['thisWord'] = word  # 1. put a word into session
 | 
				
			||||||
 | 
					    session['time'] = 1
 | 
				
			||||||
 | 
					    return redirect(url_for('userpage', username=username))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.route("/<username>/<word>/familiar", methods=['GET', 'POST'])
 | 
				
			||||||
 | 
					def familiar(username,word):
 | 
				
			||||||
 | 
					    user_freq_record = path_prefix + 'static/frequency/' + 'frequency_%s.pickle' % (username)
 | 
				
			||||||
 | 
					    pickle_idea.familiar(user_freq_record,word)
 | 
				
			||||||
 | 
					    session['thisWord'] = word  # 1. put a word into session
 | 
				
			||||||
 | 
					    session['time'] = 1
 | 
				
			||||||
 | 
					    return redirect(url_for('userpage', username=username))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.route("/<username>/<word>/del", methods=['GET', 'POST'])
 | 
				
			||||||
 | 
					def deleteword(username,word):
 | 
				
			||||||
 | 
					    user_freq_record = path_prefix + 'static/frequency/' + 'frequency_%s.pickle' % (username)
 | 
				
			||||||
 | 
					    pickle_idea2.deleteRecord(user_freq_record,word)
 | 
				
			||||||
 | 
					    flash(f'<strong>{word}</strong> is no longer in your word list.')
 | 
				
			||||||
 | 
					    return redirect(url_for('userpage', username=username))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.route("/<username>", methods=['GET', 'POST'])
 | 
				
			||||||
 | 
					def userpage(username):
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if not session.get('logged_in'):
 | 
				
			||||||
 | 
					        return '<p>请先<a href="/login">登录</a>。</p>'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    user_expiry_date = session.get('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>' % (username)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    username = session.get('username')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    user_freq_record = path_prefix + 'static/frequency/' +  'frequency_%s.pickle' % (username)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if request.method == 'POST':  # when we submit a form
 | 
				
			||||||
 | 
					        content = request.form['content']
 | 
				
			||||||
 | 
					        f = WordFreq(content)
 | 
				
			||||||
 | 
					        lst = f.get_freq()
 | 
				
			||||||
 | 
					        page = '<meta charset="UTF8">'        
 | 
				
			||||||
 | 
					        page += '<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=3.0, user-scalable=yes" />'        
 | 
				
			||||||
 | 
					        page += '<p>勾选不认识的单词</p>'
 | 
				
			||||||
 | 
					        page += '<form method="post" action="/%s/mark">\n' % (username)
 | 
				
			||||||
 | 
					        page += ' <input type="submit" name="add-btn" value="加入我的生词簿"/>\n'        
 | 
				
			||||||
 | 
					        count = 1
 | 
				
			||||||
 | 
					        words_tests_dict = pickle_idea.load_record(path_prefix + 'static/words_and_tests.p')        
 | 
				
			||||||
 | 
					        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' % (count, youdao_link(x[0]), appears_in_test(x[0], words_tests_dict), x[0], x[1], x[0])
 | 
				
			||||||
 | 
					            count += 1
 | 
				
			||||||
 | 
					        page += '</form>\n'
 | 
				
			||||||
 | 
					        return page
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    elif request.method == 'GET': # when we load a html page
 | 
					    elif request.method == 'GET': # when we load a html page
 | 
				
			||||||
        random_ads = get_random_ads()
 | 
					        page = '<meta charset="UTF8">\n'
 | 
				
			||||||
        number_of_essays = total_number_of_essays()
 | 
					        page += '<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=0.5, maximum-scale=3.0, user-scalable=yes" />\n'
 | 
				
			||||||
        d = load_freq_history(path_prefix + 'static/frequency/frequency.p')
 | 
					        page += '<meta name="format-detection" content="telephone=no" />\n' # forbid treating numbers as cell numbers in smart phones
 | 
				
			||||||
        d_len = len(d)
 | 
					        page += '<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">'
 | 
				
			||||||
        lst = sort_in_descending_order(pickle_idea.dict2lst(d))
 | 
					        page += '<title>EnglishPal Study Room for %s</title>' % (username)
 | 
				
			||||||
        return render_template('mainpage_get.html', random_ads=random_ads, number_of_essays=number_of_essays,
 | 
					        page += '<div class="container-fluid">'
 | 
				
			||||||
                               d_len=d_len, lst=lst, yml=Yaml.yml)
 | 
					        page += '<p><b>English Pal for <font color="red">%s</font></b> <a class="btn btn-secondary" href="/logout" role="button">登出</a></p>' % (username)
 | 
				
			||||||
 | 
					        page += get_flashed_messages_if_any()
 | 
				
			||||||
 | 
					        page += '<p><b>阅读文章并回答问题</b></p>\n'
 | 
				
			||||||
 | 
					        page += '<p><a class="btn btn-success" href="/%s/reset" role="button"> 下一篇 Next Article </a></p>' % (username)
 | 
				
			||||||
 | 
					        page += '<div id="text-content">%s</div>'  % (get_today_article(user_freq_record, session['articleID']))
 | 
				
			||||||
 | 
					        page += '<p><b>收集生词吧</b> (可以在正文中划词,也可以复制黏贴)</p>'
 | 
				
			||||||
 | 
					        page += '<form method="post" action="/%s">' % (username)
 | 
				
			||||||
 | 
					        page += ' <textarea name="content" id="selected-words" rows="10" cols="120"></textarea><br/>'
 | 
				
			||||||
 | 
					        page += ' <input type="submit" value="get 所有词的频率"/>'
 | 
				
			||||||
 | 
					        page += ' <input type="reset" value="清除"/>'
 | 
				
			||||||
 | 
					        page += '</form>\n'
 | 
				
			||||||
 | 
					        page += ''' 
 | 
				
			||||||
 | 
					                 <script>
 | 
				
			||||||
 | 
					                   function getWord(){ 
 | 
				
			||||||
 | 
					                       var word = window.getSelection?window.getSelection():document.selection.createRange().text;
 | 
				
			||||||
 | 
					                       return word;
 | 
				
			||||||
 | 
					                   }
 | 
				
			||||||
 | 
					                   function fillinWord(){
 | 
				
			||||||
 | 
					                       var element = document.getElementById("selected-words");
 | 
				
			||||||
 | 
					                       element.value = element.value + " " + getWord();
 | 
				
			||||||
 | 
					                   }
 | 
				
			||||||
 | 
					                   document.getElementById("text-content").addEventListener("click", fillinWord, false);
 | 
				
			||||||
 | 
					                   document.getElementById("text-content").addEventListener("touchstart", fillinWord, false);
 | 
				
			||||||
 | 
					                 </script>
 | 
				
			||||||
 | 
					                 '''
 | 
				
			||||||
 | 
					        if session.get('thisWord'):
 | 
				
			||||||
 | 
					            page += '''
 | 
				
			||||||
 | 
					                   <script type="text/javascript">
 | 
				
			||||||
 | 
					                        //point to the anchor in the page whose id is aaa if it exists
 | 
				
			||||||
 | 
					                        window.onload = function(){
 | 
				
			||||||
 | 
					                            var element = document.getElementsByName("aaa");
 | 
				
			||||||
 | 
					                            if (element != null)
 | 
				
			||||||
 | 
					                                document.getElementsByName("aaa")[0].scrollIntoView(true);
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
 | 
					                   </script> 
 | 
				
			||||||
 | 
					                   '''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        d = load_freq_history(user_freq_record)
 | 
				
			||||||
 | 
					        if len(d) > 0:
 | 
				
			||||||
 | 
					            page += '<p><b>我的生词簿</b></p>'
 | 
				
			||||||
 | 
					            lst = pickle_idea2.dict2lst(d)
 | 
				
			||||||
 | 
					            lst2 = []
 | 
				
			||||||
 | 
					            for t in lst:
 | 
				
			||||||
 | 
					                lst2.append((t[0], len(t[1])))
 | 
				
			||||||
 | 
					            for x in sort_in_descending_order(lst2):
 | 
				
			||||||
 | 
					                word = x[0]
 | 
				
			||||||
 | 
					                freq = x[1]
 | 
				
			||||||
 | 
					                if session.get('thisWord') == x[0] and session.get('time') == 1:
 | 
				
			||||||
 | 
					                    page += '<a name="aaa"></a>'    # 3. anchor
 | 
				
			||||||
 | 
					                    session['time'] = 0   # discard anchor
 | 
				
			||||||
 | 
					                if isinstance(d[word], list): # d[word] is a list of dates
 | 
				
			||||||
 | 
					                    if freq > 1:
 | 
				
			||||||
 | 
					                        page += '<p class="new-word"> <a class="btn btn-light" href="%s" role="button">%s</a>(<a title="%s">%d</a>) <a class="btn btn-success" href="%s/%s/familiar" role="button">熟悉</a> <a class="btn btn-warning" href="%s/%s/unfamiliar" role="button">不熟悉</a>  <a class="btn btn-danger" href="%s/%s/del" role="button">删除</a> </p>\n' % (youdao_link(word), word, '; '.join(d[word]), freq,username, word,username,word, username,word)
 | 
				
			||||||
 | 
					                    else:
 | 
				
			||||||
 | 
					                        page += '<p class="new-word"> <a class="btn btn-light" href="%s" role="button">%s</a>(<a title="%s">%d</a>) <a class="btn btn-success" href="%s/%s/familiar" role="button">熟悉</a> <a class="btn btn-warning" href="%s/%s/unfamiliar" role="button">不熟悉</a>  <a class="btn btn-danger" href="%s/%s/del" role="button">删除</a> </p>\n' % (youdao_link(word), word, '; '.join(d[word]), freq,username, word,username,word, username,word)
 | 
				
			||||||
 | 
					                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 += '<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>'
 | 
				
			||||||
 | 
					        page += '</div>'
 | 
				
			||||||
 | 
					        return page
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Sign-up, login, logout ###
 | 
				
			||||||
 | 
					@app.route("/signup", methods=['GET', 'POST'])
 | 
				
			||||||
 | 
					def signup():
 | 
				
			||||||
 | 
					    if request.method == 'GET':
 | 
				
			||||||
 | 
					        return render_template('signup.html')
 | 
				
			||||||
 | 
					    elif request.method == 'POST':
 | 
				
			||||||
 | 
					        username = request.form['username']
 | 
				
			||||||
 | 
					        password = request.form['password']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def check_number_exist(password_str):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    判断密码是否含有数字
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    for c in password_str:
 | 
				
			||||||
 | 
					        if c.isnumeric():
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					    return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def check_letter_exist(password_str):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    判断密码是否含有字母
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    for c in password_str:
 | 
				
			||||||
 | 
					        if c.isalpha():
 | 
				
			||||||
 | 
					            return True
 | 
				
			||||||
 | 
					    return False
 | 
				
			||||||
 | 
					#规则1:密码长度大于8
 | 
				
			||||||
 | 
					    if len(password) >= 8:
 | 
				
			||||||
 | 
					        strength_level += 1
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        print('密码强度要求至少8位')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #规则2:密码必须包含数字
 | 
				
			||||||
 | 
					    if check_number_exist(password):
 | 
				
			||||||
 | 
					        strength_level += 1
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        print('密码要求包含数字')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #规则3:密码必须包含字母
 | 
				
			||||||
 | 
					    if check_letter_exist(password):
 | 
				
			||||||
 | 
					        strength_level += 1
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        print('密码要求包含字母')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        available = check_username_availability(username)
 | 
				
			||||||
 | 
					        if not available:
 | 
				
			||||||
 | 
					            flash('用户名 %s 已经被注册。' % (username))
 | 
				
			||||||
 | 
					            return render_template('signup.html')
 | 
				
			||||||
 | 
					        elif len(password.strip()) < 4:
 | 
				
			||||||
 | 
					            return '密码过于简单。'
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            add_user(username, password)
 | 
				
			||||||
 | 
					            verified = verify_user(username, password)
 | 
				
			||||||
 | 
					            if verified:
 | 
				
			||||||
 | 
					                session['logged_in'] = True
 | 
				
			||||||
 | 
					                session[username] = username
 | 
				
			||||||
 | 
					                session['username'] = username
 | 
				
			||||||
 | 
					                session['expiry_date'] = get_expiry_date(username)
 | 
				
			||||||
 | 
					                session['articleID'] = None
 | 
				
			||||||
 | 
					                return '<p>恭喜,你已成功注册, 你的用户名是 <a href="%s">%s</a>。</p>\
 | 
				
			||||||
 | 
					                <p><a href="/%s">开始使用</a> <a href="/">返回首页</a><p/>' % (username, username, username)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return '用户名密码验证失败。'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.route("/login", methods=['GET', 'POST'])
 | 
				
			||||||
 | 
					def login():
 | 
				
			||||||
 | 
					    if request.method == 'GET':
 | 
				
			||||||
 | 
					        if not session.get('logged_in'):
 | 
				
			||||||
 | 
					            return render_template('login.html')
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return '你已登录 <a href="/%s">%s</a>。 登出点击<a href="/logout">这里</a>。' % (session['username'], session['username'])
 | 
				
			||||||
 | 
					    elif request.method == 'POST':
 | 
				
			||||||
 | 
					        # check database and verify user
 | 
				
			||||||
 | 
					        username = request.form['username']
 | 
				
			||||||
 | 
					        password = request.form['password']
 | 
				
			||||||
 | 
					        verified = verify_user(username, password)
 | 
				
			||||||
 | 
					        if verified:
 | 
				
			||||||
 | 
					            session['logged_in'] = True
 | 
				
			||||||
 | 
					            session[username] = username
 | 
				
			||||||
 | 
					            session['username'] = username
 | 
				
			||||||
 | 
					            user_expiry_date = get_expiry_date(username)
 | 
				
			||||||
 | 
					            session['expiry_date'] = user_expiry_date
 | 
				
			||||||
 | 
					            session['articleID'] = None
 | 
				
			||||||
 | 
					            return redirect(url_for('userpage', username=username))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return '无法通过验证。'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.route("/logout", methods=['GET', 'POST'])
 | 
				
			||||||
 | 
					def logout():
 | 
				
			||||||
 | 
					    session['logged_in'] = False
 | 
				
			||||||
 | 
					    return redirect(url_for('mainpage'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    '''
 | 
					    #app.secret_key = os.urandom(16)
 | 
				
			||||||
    运行程序
 | 
					    #app.run(debug=False, port='6000')
 | 
				
			||||||
    '''
 | 
					 | 
				
			||||||
    # app.secret_key = os.urandom(16)
 | 
					 | 
				
			||||||
    # app.run(debug=False, port='6000')
 | 
					 | 
				
			||||||
    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')
 | 
				
			||||||
    # print(mod5('123'))
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue