Using Flask and LeanCloud to build a backend of Wechat Official Account

[Prerequisites: Master of Chinese and English reading]

ofobicycle

During the last month, a lot of “Yellow bike” the name of which is “ofobicycle” have been sent into the campus to serve us, students, on debt. Since each bicycle possesses one fixed password to unlock, which means the best situation is that you obtain all the codes and passwords and use them as you wish, my partner and I try to do a project to get this feature.(All the contents here are just for entertainment and study, which means you can not use them in commercial affairs and please obey the law in local areas and the ToS of “ofobicycle”.)

The first thing to do is choose one language to develop this project and my partner littermonster was on duty, as our plan instructs. He use PHP and mysql to build two apis and a matrics-based database(as we desire, a lot of people can join in our project when they are using our service, which means they can add records and give feedbacks to the database to make the data more accurate, that means we should build a matrics-based database to assign this feature to this database, due to the requirements are not that complex, so we can make this feature realized). So, the last revealed result is two links:

Query:
http://bike.littermonster.net/get.php?src=app&bike_code={bike_code}

Add:
http://bike.littermonster.net/add.php?src=app&bike_password={code_password}&bike_code={bike_code}

A lot of work done by littermonster after which means this project just has to be boxed and displayed to the users. But in my opinion, the api is not regulated and beautiful, so I rewrite this two links into this form:

Query:

http://somedomain.com/api/v1.0/code_pass_query/<code>

Add:

http://somedomain.com/api/v1.0/code_pass_setter/<code>/<password>

You can easily build up a Flask App or another way(which is followed to be stated).

And the main flask code are:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Rewrite and format the Monster Apis [GETTER]
@app.route('/api/v1.0/code_pass_query/<code>', methods=['GET'])
def get_code(code):
formatted_url = 'http://bike.littermonster.net/get.php?src=app&bike_code=%s'
r = requests.get(formatted_url % code)
if r.status_code == 200:
return make_response(r.content)
# Rewrite and format the Monster Apis [GETTER]
@app.route('/api/v1.0/code_pass_setter/<code>/<password>', methods=['GET'])
def set_code(code, password):
formatted_url = 'http://bike.littermonster.net/add.php?src=app&bike_password=%s&bike_code=%s'
r = requests.get(formatted_url % (password, code))
if r.status_code == 200:
return make_response(r.content)

Then we can start the simple application to feed them some testing cases.
We can use curl command to get it.

And we can add some new codes and passes.

And sometimes the pass can be same so the matrics should be updated!

Okay, I just want to assume this feature is done.

And when this two Apis are ready, the next thing to be done is build a webpage to give the entry to the users to look for the code and add the passwords. The work is also done by littermonster, you can visit bikecode to find out how it looks like. It uses JQuery to give users best experience.

After this, you may say, Okay, there is nothing we can do any more, so let’s just go back home and sleep! No no, this is not the right thing, it can be easier and more convenient, which means it should be more easy-accessable and easy-to-use. So He gave me one suggestion, why not build a wechat official account and realize these features? If so, we can easily look for the codes and add them just in the software wechat, there will be no necessaries for us to open another application(for example, a browser, just reply on wechat). I thought that was a intelligent idea and it must be put into practice. Therefore, I went to the official document:

Official Document

Before this, the first problem I have to deal with is one server, as the program developed as plan, I have to deploy this web app on one server and make it running correctly. But my private server is LEMP-based environment, I just don’t want to make any changes to this stable environment, so, I have to choose one reliable service provider. First IBM Bluemix came to my mind, And it’s easy to use, but I didn’t want to install any softwares on my laptop, As bluemix have to install two strange softwares called CF-xxxxt to imitate the server environment. I’ve given it a try, but it was not running as expected, so I uninstalled them. After the uninstallation, I chose one service call LeanCloud(which was previously called AVOSCloud [AVOS Systems is an Internet company led by YouTube co-founders Chad Hurley and Steve Chen] , as you know, it was the child company responsible for AVOS System in China) They provide one service named lean engine, and the application maybe a little complex and troublesome, as the company have to obey China’s laws(for example, real-name confirmation). Let’s just omit the details, I was so tired of them.

I just want to assume that you have installed the python environment and Lean Environment correctly(for example python 2.7.12, pip et cetera, the details you should google it or refer to the leancloud docs) Just remember, all the things you want to do relies on a lot of documents(official or not official, which means you have to read the documents or instructions carefully, over and over again and think over and over again, then you will find how to solve the present problem,for example, you have to install the Leancloud Environment which may require to install homebrew firston your desktop or laptop, et cetera. In fact, here will be more than these things to do, e.g., install pyenv and virtualenv in which case to work together with pyenv, you have to install pyenv-virtualenv which install virtualenv as a plugin into pyenv, to make the dev environment isolated, and nvm to set up the node environment. Therefore, the next post I desire to write will state the things I did after installing OSX EI Capitan 10.11.4, so, just keep waiting!)

Then, go to your working directory and make one directory.

mkdir -p /Volume/Work/Leancloud/Wechat-example && /Volume/Work/Leancloud/Wechat-example

After this, we have to new one leancloud app.

Due to we want to build one python web app, so just choose option 1.

Open the project directory, I prefer to use Pycharm.

Find the app.py, the main code are contained in this file.

So, first thing is just finish the logical authentication of wechat, which means when the wechat server post one formatted data package(In POST Method and you should check if the token is valid, if so, you should return one response, return back one random string.)

1
2
3
4
5
6
7
8
9
10
11
12
@app.route('/weixin', methods=['GET', 'POST'])
def weixinBot():
if request.method == 'GET':
token = 'hacktheofobicycle'
query = request.args
signature = query.get('signature', '')
timestamp = query.get('timestamp', '')
nonce = query.get('nonce', '')
echostr = query.get('echostr', '')
if funcs.check_signatrue(signature, timestamp, nonce) == True:
return make_response(echostr)
return make_response('{"status":200, "message": "success"}')
1
2
3
4
5
6
7
8
9
def check_signatrue(signature, timestamp, nonce):
token = 'hacktheofobicycle'
s = [timestamp, nonce, token]
s.sort()
s = ''.join(s)
if (hashlib.sha1(s).hexdigest() == signature):
return True
else:
return False

And when completing this piece of code, you can easily use the command lean up in the working directory to run the program offline, and open terminal in one new window, to imitate POST request. However, this authentication is complex as there will be token and random string and timestamp, it’s quite hard to imitate this POST request. Also, I did not store the post-data of wechat server authentication, so I did not know what the post-data is. But this snippet is so easy that almost there will not be errors, maybe you can first deploy it to LeanEngine and get the customized domain authenticated.

First, you have to set up this domain, which can be your preference, but before you setting up the domain, you just have to do Real-name confirmation, as the picture shows. Also, you can use your own domain to, just make sure that your domain is safe and have been signed up in the Ministry of Industry and Information Technology of People’s Republic of China ICP/IP System. It depends on which server provider is, as to me, this server is hosted on Aliyun, so I just have to go to Aliyun to finish the sign up. And then, you just have to send an email to the Leancloud Support(support@leancloud.cn), which may looks like:

After receiving confirmation email from the staff of LeanCloud, they will tell you to set one CNAME record at your DNS provider to point to leanapp.cn, in my case, I have to set one CNAME record of code_pass.fairvalue.cc to leanapp.cn.

After that, we can easily use our own domain. For example, you can visit this for testing. (I highly recommend you to bind your own domain due to wechat may ban the leanapp.cn irregularly due to others’ illegal behaviour on wechat in which case their program is also hosted on LeanEngine. )

Then, we can go to the wechat dashboard to set the connection to our program.

After this, we can start writing some interesting codes.

As a matter of fact, this summer we borrow the laboratory from our teacher for reviewing for the Chinese postgraduate qualifying examination and the teacher required us to sign in and sign out every day.

Therefore, one idea came to my mind: why not use wechat to make this process smoother and easier? So, I have to write one program to make it done.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@app.route('/weixin', methods=['GET', 'POST'])
def weixinBot():
# we have to judge the request method to classify which method it is, when GET(due to the signature validation
# process of wechat is using GET method, but the other behaviour are using POST method, so thre is one IF statement)
# For valication, When GET
if request.method == 'GET':
token = 'hacktheofobicycle'
query = request.args
signature = query.get('signature', '')
timestamp = query.get('timestamp', '')
nonce = query.get('nonce', '')
echostr = query.get('echostr', '')
if funcs.check_signatrue(signature, timestamp, nonce) == True:
return make_response(echostr)
return make_response('{"status":200, "message": "success"}')
else:

I have to interrupt you at this position, I have to state that the wechat server will post data to our server when the user do some operations, e.g. subscribe, send one message, click the menu and et cetera.

Let’s jump into one case, when the user subscribe to your Wechat official account, the wechat server will post the following data to our server. Here is one example:

1
2
3
4
5
6
7
8
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[o8n1StyVuGGgp2Nj7GGg_0L8Flr8]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Content><![CDATA[a+50680]]></Content>
<Event><![CDATA[reply]]></Event>
</xml>

Use this data we can easily imitate the POST procedure, in that case, we can add one trigger, which means when the user subscribe to this account, we send one preserved message to show to him/her, tell her something about the account.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# For other behaviours, When POST
import time
timeseconds = time.time()
# Basic Information Getter
# In general, there will be five parameter in the post data, among which are ToUserName, FromUserName, Content,
# MsgType, Event, that's what we have to extra from post data
xml_recv = ET.fromstring(request.data)
ToUserName = xml_recv.find("ToUserName")
FromUserName = xml_recv.find("FromUserName")
Content = xml_recv.find("Content")
MessageType = xml_recv.find('MsgType')
MsgEvent = xml_recv.find('Event')
if ToUserName is not None:
ToUserName = ToUserName.text
else:
ToUserName = ''
if FromUserName is not None:
FromUserName = FromUserName.text
else:
FromUserName = ''
if Content is not None:
Content = Content.text
else:
Content = ''
if MessageType is not None:
MessageType = MessageType.text
else:
MessageType = ''
if MsgEvent is not None:
MsgEvent = MsgEvent.text
else:
MsgEvent = ''
# To split the command line into serveral single commands to make the program regcognized easily and
# The separator is '+'
listofcommands = Content.split('+')

Use the snippet above, we can extra the parameters we need to judge the type of the event and the kinda things about what the user’s account is, what official account is, what the message the user sends to our account, et cetera. Use the last command we can split the command line into separate command, in which case we desire the command should in this format:

  • reg+{name} (to register in this signin system)
  • s+{comments} (to sign in and add some comments)
  • e+{comments} (to sign out and add some comments)
  • {5-digit/6-digit number, code} (to query the code and get its pass)
  • a+{5-digit/6-digit number, code}+{4-digit number, pass} (to add the pass of the code)
  • {5-digit/6-digit number, code}-{4-digit number, pass}(to add the pass of the code)
  • /h (help manual)

Register module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# User register module
# This is for register, reg+{name}, check if the name is in the list Guys, then query the database to check
# if the name has been used for register, then prompt the user that the name he used to register has been taken
# by another man.
if 'reg' == listofcommands[0]:
# Check if the name is valid name and count in the valid list
# The name is read as Unicode in the RAM, so we have to encode the name into utf-8 format, then it can be recognized by
# recognized by the system.
if (listofcommands[1].encode('utf-8') in valid_names) == True:
# The fixed syntax of LeanEngine of python
Guys = leancloud.Object.extend('Guys')
query = Guys.query
# Check if the name among the list has been used to register
try:
hasoneuserreg = len(query.equal_to('name', listofcommands[1]).descending('createAt').find())
except leancloud.LeanCloudError, e:
if e.code == 101: # 服务端对应的 Class 还没创建
hasoneuserreg = 0
else:
raise e
if hasoneuserreg != 0:
reply_message = 'Your name has already been used to registered!'
else:
# Reset the query conditions
query = Guys.query
# Check if the user is using another valid name to register, this statement uses the user's wechat
# openid to judge if the user has been registered, even he did not use his own name
try:
secondtimereg = len(
query.equal_to('openidfromuser', FromUserName).descending('createAt').find())
except leancloud.LeanCloudError, e:
if e.code == 101: # 服务端对应的 Class 还没创建
secondtimereg = 0
else:
raise e
if secondtimereg != 0:
reply_message = 'You have already registered!'
else:
# Create user record in the user database
guys = Guys()
guys.set('openidfromuser', FromUserName)
guys.set('openidtouser', ToUserName)
guys.set('name', listofcommands[1])
guys.save()
reply_message = listofcommands[1] + u', Happy to tell you Register Success!'
else:
# Error message, indicating that the user is not a valid user
reply_message = 'Your name is not in the list!'
# Encode the message and return to the wechat server to send back the user
response = make_response(
reply_template % (FromUserName, ToUserName, str(int(timeseconds)),
(reply_message).encode('utf-8')))
response.content_type = 'application/xml'
return response

Check in module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# Checkin Checkout module
if 's' == listofcommands[0]:
hasnouser = False
# Check if the user has been registered!
Guys = leancloud.Object.extend('Guys')
query = Guys.query
try:
name = query.equal_to('openidfromuser', FromUserName).descending('createAt').find()[0].get('name')
except leancloud.LeanCloudError, e:
if e.code == 101: # 服务端对应的 Class 还没创建
hasnouser = True
else:
raise e
# If True, means the user has not been registered, then prompt he to register first
if hasnouser:
reply_message = 'Sorry, No such user has been registered! Please register first!([reg+yourname])'
response = make_response(
reply_template % (FromUserName, ToUserName, str(int(timeseconds)),
(reply_message)))
response.content_type = 'application/xml'
return response
# Else, add the checkin record in the database
Checkincheckout = leancloud.Object.extend('Checkincheckout')
query = Checkincheckout.query
# Fetch the time of {201x-xx-xx} formatted, to make a wild query about if there were checkin records within
# this day, which means one user cannot check in for a twice time within a single day
dateoftoday = str(datetime.now())[:11]
query.contains('intime', dateoftoday)
query.equal_to('name', name)
query.equal_to('type', types[0])
try:
if len(query.descending('createAt').find()) == 1:
reply_message = "Sorry! You can not check in for more than two times within a day! "
response = make_response(
reply_template % (FromUserName, ToUserName, str(int(timeseconds)),
(reply_message)))
response.content_type = 'application/xml'
return response
except leancloud.LeanCloudError, e:
if e.code == 101: # 服务端对应的 Class 还没创建
pass
else:
raise e
# Prepare for add record in the database for checkin
checkincheckout = Checkincheckout()
checkincheckout.set('name', name)
checkincheckout.set('type', types[0])
checkincheckout.set('intime', str(datetime.now()))
# if the count of single commands is less than 2, it means he did not write a comment, then make a common
# comment, else set the user's preferred comment
if len(listofcommands) == 2:
checkincheckout.set('statements', listofcommands[1])
else:
checkincheckout.set('statements', 'abbreviation')
checkincheckout.save()
reply_message = "Congratulations, %s! You've checked in successfully!" % name
response = make_response(
reply_template % (FromUserName, ToUserName, str(int(timeseconds)),
(reply_message)))
response.content_type = 'application/xml'
return response

Check out module

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# Check out module
if 'e' == listofcommands[0]:
# Judge if the user has registered
hasnouser = False
Guys = leancloud.Object.extend('Guys')
query = Guys.query
try:
name = query.equal_to('openidfromuser', FromUserName).descending('createAt').find()[0].get('name')
except leancloud.LeanCloudError, e:
if e.code == 101: # 服务端对应的 Class 还没创建
hasnouser = True
else:
raise e
if hasnouser:
reply_message = 'Sorry, No such user has been registered! Please register first!([reg+yourname])'
response = make_response(
reply_template % (FromUserName, ToUserName, str(int(timeseconds)),
(reply_message)))
response.content_type = 'application/xml'
return response
# Check if the user has checked out for more than one times within a day
dateoftoday = str(datetime.now())[:11]
Checkincheckout = leancloud.Object.extend('Checkincheckout')
query = Checkincheckout.query
query.contains('intime', dateoftoday)
query.equal_to('name', name)
query.equal_to('type', types[1])
try:
if len(query.descending('createAt').find()) == 1:
reply_message = "Sorry! You can not check out for more than two times within a day! "
response = make_response(
reply_template % (FromUserName, ToUserName, str(int(timeseconds)),
(reply_message)))
response.content_type = 'application/xml'
return response
except leancloud.LeanCloudError, e:
if e.code == 101: # 服务端对应的 Class 还没创建
pass
else:
raise e
# Check if the user has checked in, if not, prompt he to check in first, or add one check out record
checkincheckout = Checkincheckout()
query = Checkincheckout.query
query.contains('intime', dateoftoday)
query.equal_to('name', name)
query.equal_to('type', types[0])
try:
if len(query.descending('createAt').find()) == 1:
checkincheckout.set('name', name)
checkincheckout.set('type', types[1])
checkincheckout.set('intime', str(datetime.now()))
if len(listofcommands) == 2:
checkincheckout.set('statements', listofcommands[1])
else:
checkincheckout.set('statements', 'abbreviation')
checkincheckout.save()
reply_message = 'Congratulations, %s! You have been checked out successfully!' % name
response = make_response(
reply_template % (FromUserName, ToUserName, str(int(timeseconds)),
(reply_message)))
response.content_type = 'application/xml'
return response
else:
reply_message = 'Sorry, You have not been checked in! Please checkin first!([s+abbreviation])'
response = make_response(
reply_template % (FromUserName, ToUserName, str(int(timeseconds)),
(reply_message)))
response.content_type = 'application/xml'
return response
except leancloud.LeanCloudError, e:
if e.code == 101: # 服务端对应的 Class 还没创建
pass
else:
raise e

After all this completed, we can use lean up to run it, then I will show you how to tell locally.

New one terminal window, cd to the working directory, new one plain file and add some statements and save it as for example, “post-data”:

1
2
3
4
5
6
7
8
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[o8n1StyVuGGgp2Nj7GGg_0L8Flr8]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[event]]></MsgType>
<Content><![CDATA[a+50680]]></Content>
<Event><![CDATA[subscribe]]></Event>
</xml>

Use this command will be a better choice:
curl -H "Content-Type: applicaition/json" -d @post-data -X POST http://localhost:3000/weixin
or cat post-data | curl -H "Content-Type: applicaition/json" -d @- -X POST http://localhost:3000/weixin

And here is another third method to post the data, after the "-d " which means "–data " parameter, you can put all the post data in multiple lines, but that was more complex, so I prefer not to.

If you think the information are not verbose enough, you can easily use the “trace-ascii” parameter to print more information.

We by modify the contents of the post file, we do some more tests.

1
2
3
4
5
6
7
8
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[o8n1StyVuGGgp2Nj7GGg_0L8Flr9]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[reply]]></MsgType>
<Content><![CDATA[reg+test]]></Content>
<Event><![CDATA[subscribe]]></Event>
</xml>

I modify the FromUserName and add one user named ‘test’ in the validation list to avoid conflicts.

Then check in and check out.

1
2
3
4
5
6
7
8
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[o8n1StyVuGGgp2Nj7GGg_0L8Flr9]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[reply]]></MsgType>
<Content><![CDATA[s+htest for checkin]]></Content>
<Event><![CDATA[subscribe]]></Event>
</xml>

1
2
3
4
5
6
7
8
<xml>
<ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[o8n1StyVuGGgp2Nj7GGg_0L8Flr9]]></FromUserName>
<CreateTime>123456789</CreateTime>
<MsgType><![CDATA[reply]]></MsgType>
<Content><![CDATA[e+htest for checkout]]></Content>
<Event><![CDATA[subscribe]]></Event>
</xml>

And up to here, we have finished the signin system. Whereas, can we go a little further? The answer is Yeah! We could do it! Still remember the ofobicycle? The best method to hack its passwords is collecting all the passes and store them into one database and if needed, just query! But, how can we get some many passes? That’s called “crowdsourcing”. We can invite a lot of people to join us and help us complete this job!

So, we just have to expose our Query and Add apis. Jus keep in mind, currently we have two apis:

  • http://code_pass.fairvalue.cc/api/v1.0/code_pass_query/{code}
  • http://code_pass.fairvalue.cc/api/v1.0/code_pass_setter/{code}/{pass}

We can also use curl command to GET the content:

If not found:

Use GET to add a completely new pass:

In addition, we can update the existed pass:

You can easily find that the response is a json file, and it always have one status word and message word, so we can extract the json file to get the status, if it is 200 or 205, it means the addition is successful! When it is 404, then it means no such passes and waiting for you to add.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# Interpret the json and get the passes
def password_getter(parsed_json):
code_list = list()
#if parsed_json['status'] == 200:
if parsed_json['message'] == 'OK':
data = parsed_json['data']
for i in range(len(data)):
code_list.append(data[i]['password'])
code_list.sort()
return code_list
# else:
return []
# Judge if the command is for code_pass addition and query
elif listofcommands[0] == 'a':
# index out of range bug to be fixed
# The command is not valid, return error message
if len(listofcommands) < 3:
rContent = error_message
response = make_response(reply_template % (FromUserName, ToUserName, str(int(timeseconds)), rContent))
response.content_type = 'application/xml'
return response
# The formatted command is "a+{5-digit}+{4-digit}", so we have to check if the parameters are such numbers
if len(listofcommands[1]) == 5 and len(listofcommands[2]) == 4:
flag = True
for i in listofcommands[1]:
# The command contains more than one non-digit character
if i not in tuple_numbers:
flag = False
for i in listofcommands[2]:
if i not in tuple_numbers:
flag = False
# If the command is valid, just call the api to add the code and pass
if flag == True:
myrequestjson = requests.get('http://code_pass.fairvalue.cc/api/v1.0/code_pass_setter/%s/%s' % (
listofcommands[1], listofcommands[2])).json()
# Get the status code to judge if the code has been added successfully
if myrequestjson['status'] == 205 or myrequestjson['status'] == 200:
rContent = '添加成功!\n'
else:
rContent = '添加失败!请重新尝试添加!\n'
else:
rContent = error_message
# The command is not the valid command, not in the format "a+{5-digit}+{4-digit}" then return the error message
else:
rContent = error_message
response = make_response(reply_template % (FromUserName, ToUserName, str(int(timeseconds)), rContent))
response.content_type = 'application/xml'
return response
else:
# use the Monster Api to get information
rContent = error_message
flag = True
for i in Content:
if i not in tuple_numbers:
flag = False
# If the command has only numbers and the length is 5
if flag == True and len(Content) == 5:
rContent = "5位数字是: " + Content + ", 4位数字可能是(按权值排名): \n"
# rContent = Content
myrequest = requests.get('http://code_pass.fairvalue.cc/api/v1.0/code_pass_query/%s' % Content)
if myrequest.status_code == 200:
reList = funcs.password_getter(myrequest.json());
if len(reList) == 0:
rContent = '没有查询到相关结果!';
else:
for item in reList:
rContent = rContent + (str(item)) + " "
response = make_response(reply_template % (FromUserName, ToUserName, str(int(timeseconds)), rContent))
response.content_type = 'application/xml'
return response

The complete code:

In spite of that feature, my friends asked me to make the system to checkout automatically, luckily, leanengine supports cron tasks. We have to add the following snippet to cloud.py and add the function to leanengine crontask through its dashboard.

Which means when 23:30:15 everyday, the program will call the function “autocheckinandout” in cloud.py.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@engine.define
def autocheckinandout():
dayoftoday = str(datetime.now())[:11]
Checkinandout = leancloud.Object.extend('Checkincheckout')
query = Checkinandout.query
query.contains('intime', dayoftoday)
# First we have to get the person who checked in already, so that he/she can check out
resultsoftoday = query.descending('name').find()
for i in resultsoftoday:
name = i.get('name')
querycheckout = Checkinandout.query
querycheckout.contains('intime', dayoftoday)
querycheckout.equal_to('name', name)
querycheckout.equal_to('type', 'CHECKOUT')
if len(querycheckout.find()) == 0:
checkinandout = Checkinandout()
intime = str(datetime.now())
# Generate a minute numeber n ( n >= 0 and n <= 59)
randNum = randint(0, 59)
if randNum < 10:
randNumStr = '0' + str(randNum)
else:
randNumStr = str(randNum)
# Replace the {HOUR}:{MINUTE}:{SECOND} scope to the minute we'd like to make the checkout record more natural
checkinandout.set('intime', intime.replace(intime[13:17], (':' + randNumStr + ':')))
checkinandout.set('name', name)
checkinandout.set('type', 'CHECKOUT')
checkinandout.set('statements', 'abbreviation')
checkinandout.save()
return 'Auto Checkout complete!'

And this project is hosted on Coding.net

So, above are almost all the things I am trying to state. Maybe there are some refers I have not marked, I will add some time later.

And if you are interested in my work or you just want to test my code, welcome use your wechat client so scan the following QRcode to follow my official account “Townes”.

Refer:

微信公众平台后台接入简明指南
How do I POST XML data with curl
How can I see the request headers made by curl when sending a request to the server