<center></center> This tutorial will explain how Steemconnect and Python can be used to build a back-end application that is used to perform voting. --- #### Repository https://github.com/steemit/steemconnect https://github.com/emre/steemconnect-python-client #### What will I learn - Storing access tokens - Retrieving access token en refreshing - Voting and response - Error handling #### Requirements - Python3.6 - MySQL - Steemconnect #### Difficulty - intermediate --- ### Tutorial #### Preface Python is a great language to build back-end applications that work great in conjunction with a front-end that is for example build with a framework like WordPress. This tutorial will look into how voting can be done by fetching `access_tokens` from a MySQL database. There are 3 files that are not set up to do anything in particular but include all the functions and database table structure to do so. [Github link](https://github.com/amosbastian/steempy-tutorials/tree/master/part_30). #### Install Steemconnect for Python A splendid Steemconnect written for Python by @emrebeyler. ``` pip3 install steemconnect ``` #### Setting up your Steemconnect app This tutorial requires access to a Steemconnect app. It is somewhat a continuation on the Steemconnect & WordPress tutorials [1](https://steemit.com/utopian-io/@steempytutorials/integrate-steemconnect-v2-user-authentication-into-any-wordpress-website) and [2](https://steemit.com/utopian-io/@steempytutorials/integrate-steemconnect-v2-user-authorisation-into-any-wordpress-website). However, they are not required for this tutorial. All Steemconnect actions are performed via the `Client` object. It takes the `client_id` and `client_secret` from your Steemconnect app. In addition it requires the `access_token` for the account that actions will be performed for. A separate `Client` is needed for each account, or the `access_token` has to be changed. ``` c = Client( client_id=CLIENT_ID, client_secret=CLIENT_SECRET, access_token=access_token, ) ``` The `client_id` and `client_secret` are declared outside of the function. This is also true for the database variables. They have to be configured for the code to work. #### Storing access tokens For the storing of the access tokens a MySQL database is used that has the following properties. This tutorial assumes that there is already a solution in place to obtain the initial access tokens and will look into how they can be used afterwards. ``` CREATE TABLE `steem_authorization` ( `id` int(11) NOT NULL, `access_token` text NOT NULL, `user_login` varchar(20) NOT NULL, `expires_in` datetime NOT NULL, `refresh_token` text NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1; ALTER TABLE `steem_authorization` ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `user_login` (`user_login`); ALTER TABLE `steem_authorization` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT; ``` There are 4 main attributes. The `access_token` itself, the `user_login`, which STEEM account is belongs to, `expires_in`, this is calculated when the access_token is created. And the `refresh_token`, this is given when offline access is requested and is used to refresh the `access token` when it expires. #### Retrieving access tokens and refreshing The query is relatively simple as there should only be 1 `access_token` per user in the database. If this is not the case the updating and or registering for the `access_token` is not dealt with properly. `get_data()` fetches all the rows and return them. ``` def get_user_auth(self, voter): query = ("SELECT `access_token`,`refresh_token`,`expires_in` FROM " + f"`steem_authorization` WHERE `user_login` = '{voter}'") return self.get_data(query) ``` <br> The access token is fetched from the database with its relevant data. The next step is to verify that the `access_token` is still valid, if not it must be renewed. **Note: This is only possible if the user gave authorisation for offline access.** ``` result = self.db.get_user_auth(voter) access_token, refresh_token, expire_on = result[0] dt = datetime.now() ``` <br> The current date is referenced against the date when the token expires. The `access_token` is then refreshed by calling the `refresh_access_token()` function inside Client. The new variables are then stored in the database. ``` # Verify access_token if dt > expire_on: result = c.refresh_access_token( refresh_token, "login,vote" # scopes ) # Retrieve new variables and store in DB access_token = result['access_token'] refresh_token = result['refresh_token'] expires_in = result['expires_in'] self.db.update_authentication_tokens( voter, access_token, refresh_token, expires_in, self.timestamp, ) ``` <br> The current timestamp is used to calculate the new date when the new `access_token` expires. ``` def update_authentication_tokens(self, voter, access_token, refresh_token, expires_in, timestamp): dt = datetime.strptime(timestamp, '%Y-%m-%dT%H:%M:%S') expires_in = dt + timedelta(seconds=expires_in) query = ("UPDATE `steem_authorization` SET `access_token` = " + f"'{access_token}', `expires_in` = '{expires_in}', " + f"`refresh_token` = '{refresh_token}' WHERE " + f"`user_login` = '{voter}';") self.post_data(query, 'steem_authorization') ``` #### Voting and response Voting is relatively simple as it just requires the parameters that make up the vote. ``` # Perform vote vote = Vote(voter, author, permlink, weight) ``` <br> The vote will return a response, if it succeeds or fails. ``` result = c.broadcast([vote.to_operation_structure()]) ``` <br> A successful example: ``` { 'result': { 'id': 'b0e79cc31de3d248d7a90406edadf9dc3e979e14', 'block_num': 24673233, 'trx_num': 21, 'expired': False, 'ref_block_num': 31679, 'ref_block_prefix': 3139963426, 'expiration': '2018-08-01T01:57:57', 'operations': [ ['vote', { 'voter': 'juliank', 'author': 'axeman', 'permlink': 'girls-n-cars-greta-vs-mb', 'weight': 1000 }] ], 'extensions': [], 'signatures': ['1f7b83bba9177a8f5c980e6185f7546134554ae6229363a1ef2986bdb29ba60d0b5b7e3cf6975e8d3d955a3274b2b8cbf526fd42b1b2f88ed0167c45296a50d15a'] } } ``` An example of an error: ``` { 'error': 'server_error', 'error_description': 'itr->vote_percent != o.weight: You have already voted in a similar way.' } ``` #### Error handling Error handling is done by just looking if there is an `error` key in the result. ``` if 'error' in result: message = result['error_description'] print(message) else: message = 'Succes' print(message) ``` <br> It is recommend to capture the `error` message and store this inside the database for manual review. This way the application can continue. ``` self.db.add_to_error_log( voter, author, permlink, weight, message, self.timestamp, def add_to_error_log(self, voter, author, permlink, weight, message, timestamp): query = ( 'INSERT INTO `error_log` (`id`, `voter`, `author`, ' + '`permlink`, `weight`, `error`, `timestamp`) VALUES ' + f'(NULL, "{voter}", "{author}", "{permlink}", ' + f'"{weight}", "{message}", "{timestamp}");') self.post_data(query, 'error_log') ``` --- The files are available on [Github](https://github.com/amosbastian/steempy-tutorials/tree/master/part_30). This tutorial was written by @juliank.
author | steempytutorials |
---|---|
permlink | how-to-use-python-to-interact-with-steemconnect-s-access-tokens-refresh-tokens-and-perform-voting |
category | utopian-io |
json_metadata | {"tags":["utopian-io","tutorials","programming","steem","steemconnect"],"users":["emrebeyler","juliank"],"image":["https://cdn.steemitimages.com/DQmaqmkNGUPGei1xJdTmHcqEotS9ac6oaigWg9AN2Zv4Eoz/banner.png"],"links":["https://github.com/steemit/steemconnect","https://github.com/emre/steemconnect-python-client","https://github.com/amosbastian/steempy-tutorials/tree/master/part_30","https://steemit.com/utopian-io/@steempytutorials/integrate-steemconnect-v2-user-authentication-into-any-wordpress-website","https://steemit.com/utopian-io/@steempytutorials/integrate-steemconnect-v2-user-authorisation-into-any-wordpress-website"],"app":"steemit/0.1","format":"markdown"} |
created | 2018-08-01 04:40:12 |
last_update | 2018-08-01 04:43:51 |
depth | 0 |
children | 4 |
last_payout | 2018-08-08 04:40:12 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 36.386 HBD |
curator_payout_value | 11.312 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 7,631 |
author_reputation | 31,094,047,689,691 |
root_title | "How To Use Python To Interact With Steemconnect's Access Tokens, Refresh Tokens And Perform Voting" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 66,715,800 |
net_rshares | 28,215,325,008,830 |
author_curate_reward | "" |
voter | weight | wgt% | rshares | pct | time |
---|---|---|---|---|---|
compumatrix | 0 | 0 | 100% | ||
ace108 | 0 | 75,185,243,952 | 5% | ||
cristi | 0 | 84,574,240,473 | 20% | ||
yuxi | 0 | 3,013,407,169 | 10% | ||
rach | 0 | 1,498,479,399 | 100% | ||
juliank | 0 | 141,140,259,602 | 50% | ||
aleister | 0 | 9,464,786,801 | 30% | ||
rafalski | 0 | 7,472,921,467 | 24% | ||
drorion | 0 | 692,214,816 | 100% | ||
scorer | 0 | 40,881,536,023 | 100% | ||
mcfarhat | 0 | 11,918,191,331 | 17% | ||
makerhacks | 0 | 34,198,238,277 | 20% | ||
jrawsthorne | 0 | 7,024,046,728 | 100% | ||
utopian-io | 0 | 27,459,705,225,290 | 17.8% | ||
emrebeyler | 0 | 190,347,733,436 | 100% | ||
finaldestination | 0 | 608,114,311 | 100% | ||
amosbastian | 0 | 18,493,218,849 | 32.38% | ||
rondras | 0 | 42,046,261,533 | 100% | ||
fisherck | 0 | 5,040,555,237 | 100% | ||
portugalcoin | 0 | 5,717,369,306 | 28% | ||
abandi | 0 | 3,525,860,454 | 100% | ||
photocontests3 | 0 | 13,177,789,724 | 100% | ||
steempytutorials | 0 | 11,357,055,769 | 100% | ||
midun | 0 | 12,959,351,486 | 100% | ||
polbot | 0 | 232,095,922 | 100% | ||
photocontests4 | 0 | 4,718,804,047 | 100% | ||
sereze | 0 | 398,703,953 | 50% | ||
happens | 0 | 0 | 100% | ||
adam-saudagar | 0 | 3,621,303,216 | 100% | ||
statsexpert | 0 | 1,853,678,986 | 40% | ||
ihalf2p | 0 | 137,916,479 | 100% | ||
gregjava | 0 | 797,418,418 | 100% | ||
codebull | 0 | 609,566,309 | 100% | ||
christophe51 | 0 | 0 | 100% | ||
tamaxadi | 0 | 445,711,583 | 100% | ||
artcreator | 0 | 391,044,538 | 100% | ||
mycryptostalker | 0 | 499,419,078 | 100% | ||
thememeguy | 0 | 705,635,568 | 100% | ||
cyberspacegod | 0 | 0 | 100% | ||
kamuoyu | 0 | 89,112,216 | 100% | ||
lucky-robin | 0 | 1,911,606,500 | 100% | ||
ceruleanblue | 0 | 1,112,998,014 | 100% | ||
iauns | 0 | 9,980,812,449 | 100% | ||
yollardannotlar | 0 | 845,713,627 | 50% | ||
zuur | 0 | 4,104,686,435 | 100% | ||
jacekw.dev | 0 | 1,005,539,573 | 100% | ||
torchweed | 0 | 90,944,411 | 100% | ||
ravigoyal1 | 0 | 252,388,276 | 100% | ||
luokai1992 | 0 | 595,996,750 | 100% | ||
ione.s86 | 0 | 267,590,377 | 100% | ||
tonino | 0 | 489,554,691 | 100% | ||
bhuiyansohel | 0 | 124,665,981 | 100% | ||
sozib.karmokar | 0 | 0 | 100% | ||
fikri02 | 0 | 0 | 100% | ||
lsn1406 | 0 | 0 | 100% |
Exactly what I needed to play with right now. Thanks a lot for this. However, can we get steemconnect and js version of this (if there is)? That will be also interesting to read (maybe even more interesting).
author | gregjava |
---|---|
permlink | re-steempytutorials-how-to-use-python-to-interact-with-steemconnect-s-access-tokens-refresh-tokens-and-perform-voting-20180801t050042374z |
category | utopian-io |
json_metadata | {"tags":["utopian-io"],"app":"steemit/0.1"} |
created | 2018-08-01 05:00:45 |
last_update | 2018-08-01 05:00:45 |
depth | 1 |
children | 1 |
last_payout | 2018-08-08 05:00:45 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 0.000 HBD |
curator_payout_value | 0.000 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 209 |
author_reputation | 407,441,374,496 |
root_title | "How To Use Python To Interact With Steemconnect's Access Tokens, Refresh Tokens And Perform Voting" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 66,717,250 |
net_rshares | 11,179,601,772 |
author_curate_reward | "" |
voter | weight | wgt% | rshares | pct | time |
---|---|---|---|---|---|
steempytutorials | 0 | 11,179,601,772 | 100% |
You can look around, maybe somebody else hopped on that bandwagon. I barely know js myself so I cannot help you with that. However, the idea stays the same, just different syntax.
author | steempytutorials |
---|---|
permlink | re-gregjava-re-steempytutorials-how-to-use-python-to-interact-with-steemconnect-s-access-tokens-refresh-tokens-and-perform-voting-20180801t051329172z |
category | utopian-io |
json_metadata | {"tags":["utopian-io"],"app":"steemit/0.1"} |
created | 2018-08-01 05:13:30 |
last_update | 2018-08-01 05:48:06 |
depth | 2 |
children | 0 |
last_payout | 2018-08-08 05:13:30 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 0.000 HBD |
curator_payout_value | 0.000 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 179 |
author_reputation | 31,094,047,689,691 |
root_title | "How To Use Python To Interact With Steemconnect's Access Tokens, Refresh Tokens And Perform Voting" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 66,718,237 |
net_rshares | 0 |
Thank you for your contribution. - As always an interesting tutorial. Thank you and good work. Your contribution has been evaluated according to [Utopian policies and guidelines](https://join.utopian.io/guidelines), as well as a predefined set of questions pertaining to the category. To view those questions and the relevant answers related to your post, [click here](https://review.utopian.io/result/8/11334113). ---- Need help? Write a ticket on https://support.utopian.io/. Chat with us on [Discord](https://discord.gg/uTyJkNm). [[utopian-moderator]](https://join.utopian.io/)
author | portugalcoin |
---|---|
permlink | re-steempytutorials-how-to-use-python-to-interact-with-steemconnect-s-access-tokens-refresh-tokens-and-perform-voting-20180801t211648217z |
category | utopian-io |
json_metadata | {"tags":["utopian-io"],"links":["https://join.utopian.io/guidelines","https://review.utopian.io/result/8/11334113","https://support.utopian.io/","https://discord.gg/uTyJkNm","https://join.utopian.io/"],"app":"steemit/0.1"} |
created | 2018-08-01 21:16:48 |
last_update | 2018-08-01 21:16:48 |
depth | 1 |
children | 0 |
last_payout | 2018-08-08 21:16:48 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 0.022 HBD |
curator_payout_value | 0.005 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 587 |
author_reputation | 599,460,589,822,571 |
root_title | "How To Use Python To Interact With Steemconnect's Access Tokens, Refresh Tokens And Perform Voting" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 66,803,844 |
net_rshares | 17,357,960,160 |
author_curate_reward | "" |
voter | weight | wgt% | rshares | pct | time |
---|---|---|---|---|---|
espoem | 0 | 17,021,257,979 | 15% | ||
mops2e | 0 | 336,702,181 | 10% |
Hey @steempytutorials **Thanks for contributing on Utopian**. Weβre already looking forward to your next contribution! **Want to chat? Join us on Discord https://discord.gg/h52nFrV.** <a href='https://v2.steemconnect.com/sign/account-witness-vote?witness=utopian-io&approve=1'>Vote for Utopian Witness!</a>
author | utopian-io |
---|---|
permlink | re-how-to-use-python-to-interact-with-steemconnect-s-access-tokens-refresh-tokens-and-perform-voting-20180805t180508z |
category | utopian-io |
json_metadata | "{"app": "beem/0.19.42"}" |
created | 2018-08-05 18:05:09 |
last_update | 2018-08-05 18:05:09 |
depth | 1 |
children | 0 |
last_payout | 2018-08-12 18:05:09 |
cashout_time | 1969-12-31 23:59:59 |
total_payout_value | 0.000 HBD |
curator_payout_value | 0.000 HBD |
pending_payout_value | 0.000 HBD |
promoted | 0.000 HBD |
body_length | 308 |
author_reputation | 152,955,367,999,756 |
root_title | "How To Use Python To Interact With Steemconnect's Access Tokens, Refresh Tokens And Perform Voting" |
beneficiaries | [] |
max_accepted_payout | 1,000,000.000 HBD |
percent_hbd | 10,000 |
post_id | 67,214,443 |
net_rshares | 0 |