Compare commits
	
		
			10 Commits
		
	
	
		
			d1416d3706
			...
			8c19088640
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8c19088640 | |||
| 5316f7e205 | |||
| 31426fd851 | |||
| 8d5a3cda42 | |||
| e237e7f885 | |||
| 80037593a9 | |||
| d484a0a363 | |||
| 348e674f74 | |||
| ca9aa6d79d | |||
| ae42a052de | 
							
								
								
									
										23
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								README.md
									
									
									
									
									
								
							| @ -265,6 +265,16 @@ python -m flask refresh-milestones | ||||
| ``` | ||||
| Running this command shouldn't reset progress on milestones that are already in the database | ||||
| and are still in the redeems file. | ||||
| #### reset-milestone | ||||
| Resets progress on a milestone, but only if the milestone had been completed. | ||||
| ```bash | ||||
| python -m flask reset-milestone milestone | ||||
| ``` | ||||
| #### hard-reset-milestone | ||||
| Resets progress on a milestone, regardless of completion status. | ||||
| ```bash | ||||
| python -m flask hard-reset-milestone milestone | ||||
| ``` | ||||
| ## Configuration files | ||||
| Configuration files should be in the instance folder. For folder installation of tlapbot, | ||||
| that's `instance/` from the root of the Github repository. | ||||
| @ -313,18 +323,21 @@ REDEEMS={ | ||||
|     "lurk": {"price": 1, "type": "counter", "info": "Let us know you're going to lurk."}, | ||||
|     "react": {"price": 200, "type": "note", "info": "Attach link to a video for me to react to."}, | ||||
|     "request": {"price": 100, "type": "note", "info": "Request a level, gamemode, skin, etc."}, | ||||
|     "go_nap": {"price": 1, "type": "milestone", "info": "Streamer will go nap when the goal is reached.", "goal": 1000}, | ||||
|     "go_nap": {"goal": 1000, "type": "milestone", "info": "Streamer will go nap when the goal is reached."}, | ||||
|     "inactive": {"price": 100, "type": "note", "info": "Example redeem that is inactive by default", "category": ["inactive"]} | ||||
| } | ||||
| ``` | ||||
| #### File format | ||||
| `redeems.py` is a config file with just a `REDEEMS` key, that assigns a dictionary of redeems to it. | ||||
| Each dictionary entry is a redeem, and the dictionary keys are strings that decides the chat command for the redeem. The value is another dictionary that needs to have entries for `"price"`, `"type"` and optionally `"info"` and `"category"`. If the `"type"` is `"milestone"`, there's an additional required `"goal"` field as well. | ||||
| Each dictionary entry is a redeem, and the dictionary keys are strings that decides the chat command for the redeem. | ||||
| The value is another dictionary that needs to have an entry for `"type"` and | ||||
| an entry for `"price"` for non-milestones or `"goal"` for milestones. | ||||
| Optionally, each redeem can also have `"info"` and `"category"` entries. | ||||
| 
 | ||||
| - `"price"` value should be an integer that decides how many points the redeem will cost. For milestone redeems, `"price"` determines minimum bid. | ||||
| - `"type"` value should be either `"list"`, `"counter"`, `"note"` or `"milestone"`. This decided the redeem's type, and whether it will show up as a counter at the top of the dashboard or as an entry in the "recent redeems" chart. | ||||
| - `"info"` value should be a string that describes what the command does. It's optional, but I recommend writing one for all `"list"` and `"note"` redeems (so that chatters know that they should write a note). | ||||
| - `"price"` value should be an integer that decides how many points the redeem will cost. Milestone redeems don't use the `"price"` value, they instead need to have a `"goal"`. | ||||
| - `"goal"` is a required field for milestone goals. It should be an integer, deciding the amount of points required to complete the milestone. | ||||
| - `"type"` value should be either `"list"`, `"counter"`, `"note"` or `"milestone"`. This decided the redeem's type, and whether it will show up as a counter at the top of the dashboard or as an entry in the "recent redeems" chart. | ||||
| - `"info"` value should be a string that describes what the command does. It's optional, but I recommend writing one for all `"list"`, `"note"` and `"milestone"` redeems (so that chatters know what they're redeeming and whether they should leave a note). | ||||
| - `"category"` is an optional list of strings, the categories the redeem is in. | ||||
| If a category from the list is in `ACTIVE_CATEGORIES` from `config.py`, | ||||
| then the redeem will be active. It will not be active if none of the categories | ||||
|  | ||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							| @ -2,7 +2,7 @@ from setuptools import find_packages, setup | ||||
| 
 | ||||
| setup( | ||||
|     name='tlapbot', | ||||
|     version='1.2.0', | ||||
|     version='1.2.1', | ||||
|     packages=find_packages(), | ||||
|     include_package_data=True, | ||||
|     install_requires=[ | ||||
|  | ||||
| @ -49,6 +49,8 @@ def create_app(test_config=None): | ||||
|     app.cli.add_command(db.refresh_counters_command) | ||||
|     app.cli.add_command(db.refresh_and_clear_command) | ||||
|     app.cli.add_command(db.refresh_milestones_command) | ||||
|     app.cli.add_command(db.reset_milestone_command) | ||||
|     app.cli.add_command(db.hard_reset_milestone_command) | ||||
|      | ||||
|     # scheduler job for giving points to users | ||||
|     def proxy_job(): | ||||
|  | ||||
| @ -35,6 +35,8 @@ def insert_counters(db): | ||||
|                 db.commit() | ||||
|             except sqlite3.Error as e: | ||||
|                 print("Failed inserting counters to db:", e.args[0]) | ||||
|                 return False | ||||
|     return True | ||||
| 
 | ||||
| 
 | ||||
| def init_db(): | ||||
| @ -43,7 +45,8 @@ def init_db(): | ||||
|     with current_app.open_resource('schema.sql') as f: | ||||
|         db.executescript(f.read().decode('utf8')) | ||||
| 
 | ||||
|     insert_counters(db) | ||||
|     if insert_counters(db): | ||||
|         return True | ||||
| 
 | ||||
| 
 | ||||
| def clear_redeem_queue(): | ||||
| @ -59,6 +62,8 @@ def clear_redeem_queue(): | ||||
|         db.commit() | ||||
|     except sqlite3.Error as e: | ||||
|         print("Error occured deleting redeem queue:", e.args[0]) | ||||
|         return False | ||||
|     return True | ||||
| 
 | ||||
| 
 | ||||
| def refresh_counters(): | ||||
| @ -69,7 +74,9 @@ def refresh_counters(): | ||||
|         db.commit() | ||||
|     except sqlite3.Error as e: | ||||
|         print("Error occured deleting old counters:", e.args[0]) | ||||
|     insert_counters(db) | ||||
|         return False | ||||
|     if insert_counters(db): | ||||
|         return True | ||||
| 
 | ||||
| 
 | ||||
| def refresh_milestones(): | ||||
| @ -90,6 +97,7 @@ def refresh_milestones(): | ||||
|         db.commit() | ||||
|     except sqlite3.Error as e: | ||||
|         print("Failed deleting old milestones from db:", e.args[0]) | ||||
|         return False | ||||
| 
 | ||||
|     # add new milestones | ||||
|     try: | ||||
| @ -114,26 +122,29 @@ def refresh_milestones(): | ||||
|         db.commit() | ||||
|     except sqlite3.Error as e: | ||||
|         print("Failed inserting milestones to db:", e.args[0]) | ||||
|         return False | ||||
|     return True | ||||
| 
 | ||||
| 
 | ||||
| def reset_milestone(milestone): | ||||
|     if not redeem_name in current_app.config['REDEEMS']: | ||||
|     if not milestone in current_app.config['REDEEMS']: | ||||
|         print(f"Failed resetting milestone, {milestone} not in redeems file.") | ||||
|         return None | ||||
|         return False | ||||
|     try: | ||||
|         db = get_db() | ||||
|         db.execute( | ||||
|             "DELETE FROM milestones WHERE name = ?", | ||||
|             (milestone,) | ||||
|         ) | ||||
|         db.execute( | ||||
|             "INSERT INTO milestones(name, progress, goal) VALUES(?, ?, ?)", | ||||
|             "INSERT INTO milestones(name, progress, goal, complete) VALUES(?, ?, ?, FALSE)", | ||||
|             (milestone, 0, current_app.config['REDEEMS'][milestone]['goal']) | ||||
|         ) | ||||
|         db.commit() | ||||
|         return True | ||||
|     except Error as e: | ||||
|     except sqlite3.Error as e: | ||||
|         current_app.logger.error(f"Error occured adding a milestone: {e.args[0]}") | ||||
|         return None | ||||
|         return False | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| @ -141,7 +152,7 @@ def reset_milestone(milestone): | ||||
| @with_appcontext | ||||
| def init_db_command(): | ||||
|     """Clear the existing data and create new tables.""" | ||||
|     init_db() | ||||
|     if init_db(): | ||||
|         click.echo('Initialized the database.') | ||||
| 
 | ||||
| 
 | ||||
| @ -149,7 +160,7 @@ def init_db_command(): | ||||
| @with_appcontext | ||||
| def clear_queue_command(): | ||||
|     """Remove all redeems from the redeem queue.""" | ||||
|     clear_redeem_queue() | ||||
|     if clear_redeem_queue(): | ||||
|         click.echo('Cleared redeem queue.') | ||||
| 
 | ||||
| 
 | ||||
| @ -158,7 +169,7 @@ def clear_queue_command(): | ||||
| def refresh_counters_command(): | ||||
|     """Refresh counters from current config file. | ||||
|     (Remove old ones, add new ones.)""" | ||||
|     refresh_counters() | ||||
|     if refresh_counters(): | ||||
|         click.echo('Counters refreshed.') | ||||
| 
 | ||||
| 
 | ||||
| @ -166,8 +177,7 @@ def refresh_counters_command(): | ||||
| @with_appcontext | ||||
| def refresh_and_clear_command(): | ||||
|     """Refresh counters and clear queue.""" | ||||
|     refresh_counters() | ||||
|     clear_redeem_queue() | ||||
|     if refresh_counters() and clear_redeem_queue(): | ||||
|         click.echo('Counters refreshed and queue cleared.') | ||||
| 
 | ||||
| 
 | ||||
| @ -176,7 +186,7 @@ def refresh_and_clear_command(): | ||||
| def refresh_milestones_command(): | ||||
|     """Initialize all milestones from the redeems file,  | ||||
|     delete milestones not in redeem file.""" | ||||
|     refresh_milestones() | ||||
|     if refresh_milestones(): | ||||
|         click.echo('Refreshed milestones.') | ||||
| 
 | ||||
| 
 | ||||
| @ -184,23 +194,21 @@ def refresh_milestones_command(): | ||||
| @click.argument('milestone') | ||||
| def reset_milestone_command(milestone): | ||||
|     """Resets a completed milestone back to zero.""" | ||||
|     if milestone_complete(milestone): | ||||
|     if milestone_complete(get_db(), milestone): | ||||
|         if reset_milestone(milestone): | ||||
|             click.echo(f"Reset milestone {milestone}.") | ||||
|         else: | ||||
|             click.echo(f"Resetting milestone {milestone} failed.") | ||||
|     else: | ||||
|         click.echo(f"Could not reset milestone {milestone}, milestone not completed.") | ||||
|         click.echo("(You can hard-reset-milestone if you really want to reset it.)") | ||||
| 
 | ||||
| 
 | ||||
| @click.command('hard-reset-milestone') | ||||
| @click.argument('milestone') | ||||
| def hard_reset_milestone_command(milestone): | ||||
|     """Resets any milestone back to zero.""" | ||||
|     if reset_milestone(milestone): | ||||
|         click.echo(f"Hard reset milestone {milestone}.") | ||||
|         else: | ||||
|             click.echo(f"Hard resetting milestone {milestone} failed.") | ||||
| 
 | ||||
| 
 | ||||
| def init_app(app): | ||||
|     app.teardown_appcontext(close_db) | ||||
|  | ||||
| @ -3,6 +3,6 @@ REDEEMS={ | ||||
|     "lurk": {"price": 1, "type": "counter", "info": "Let us know you're going to lurk."}, | ||||
|     "react": {"price": 200, "type": "note", "info": "Attach link to a video for me to react to."}, | ||||
|     "request": {"price": 100, "type": "note", "info": "Request a level, gamemode, skin, etc."}, | ||||
|     "go_nap": {"type": "milestone", "info": "Streamer will go nap when the goal is reached.", "goal": 1000}, | ||||
|     "go_nap": {"goal": 1000, "type": "milestone", "info": "Streamer will go nap when the goal is reached."}, | ||||
|     "inactive": {"price": 100, "type": "note", "info": "Example redeem that is inactive by default", "category": ["inactive"]} | ||||
| } | ||||
| @ -22,10 +22,29 @@ def handle_redeem(message, user_id): | ||||
|         return | ||||
| 
 | ||||
|     db = get_db() | ||||
|     price = current_app.config['REDEEMS'][redeem]["price"] | ||||
|     redeem_type = current_app.config['REDEEMS'][redeem]["type"] | ||||
|     points = read_users_points(db, user_id) | ||||
| 
 | ||||
|     # handle milestone first because it doesn't have a price | ||||
|     if redeem_type == "milestone": | ||||
|         if milestone_complete(db, redeem): | ||||
|             send_chat(f"Can't redeem {redeem}, that milestone was already completed!") | ||||
|         elif not note: | ||||
|             send_chat(f"Cannot redeem {redeem}, no amount of points specified.") | ||||
|         elif not note.isdigit(): | ||||
|             send_chat(f"Cannot redeem {redeem}, amount of points is not an integer.") | ||||
|         elif int(note) > points: | ||||
|             send_chat(f"Can't redeem {redeem}, you're donating more points than you have.") | ||||
|         elif add_to_milestone(db, user_id, redeem, int(note)): | ||||
|             send_chat(f"Succesfully donated to {redeem} milestone!") | ||||
|             if check_apply_milestone_completion(db, redeem): | ||||
|                 send_chat(f"Milestone goal {redeem} complete!") | ||||
|         else: | ||||
|             send_chat(f"Redeeming milestone {redeem} failed.") | ||||
|         return | ||||
|      | ||||
|     # handle redeems with price argument | ||||
|     price = current_app.config['REDEEMS'][redeem]["price"] | ||||
|     if not points or points < price: | ||||
|         send_chat(f"Can't redeem {redeem}, you don't have enough points.") | ||||
|         return | ||||
| @ -50,20 +69,5 @@ def handle_redeem(message, user_id): | ||||
|             send_chat(f"{redeem} redeemed for {price} points.") | ||||
|         else: | ||||
|             send_chat(f"Redeeming {redeem} failed.") | ||||
|     elif redeem_type == "milestone": | ||||
|         if milestone_complete(db, redeem): | ||||
|             send_chat(f"Can't redeem {redeem}, that milestone was already completed!") | ||||
|         elif not note: | ||||
|             send_chat(f"Cannot redeem {redeem}, no amount of points specified.") | ||||
|         elif not note.isdigit(): | ||||
|             send_chat(f"Cannot redeem {redeem}, amount of points is not an integer.") | ||||
|         elif int(note) > points: | ||||
|             send_chat(f"Can't redeem {redeem}, you're donating more points than you have.") | ||||
|         elif add_to_milestone(db, user_id, redeem, int(note)): | ||||
|             send_chat(f"Succesfully donated to {redeem} milestone!") | ||||
|             if check_apply_milestone_completion(db, redeem): | ||||
|                 send_chat(f"Milestone goal {redeem} complete!") | ||||
|         else: | ||||
|             send_chat(f"Redeeming {redeem} failed.") | ||||
|     else: | ||||
|         send_chat(f"{redeem} not redeemed, type of redeem not found.") | ||||
|  | ||||
| @ -139,7 +139,11 @@ | ||||
|                 {% for redeem, redeem_info in redeems.items() %} | ||||
|                 <tbody> | ||||
|                     <td>{{ prefix }}{{ redeem }}</td> | ||||
|                     {% if redeem_info["type"] == "milestone" %} | ||||
|                     <td></td> | ||||
|                     {% else %} | ||||
|                     <td>{{ redeem_info["price"] }}</td> | ||||
|                     {% endif %} | ||||
|                     <td>{{ redeem_info["type"] }}</td> | ||||
|                     {% if redeem_info["info"] %} | ||||
|                     <td>{{ redeem_info["info"] }}</td> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user