Compare commits
	
		
			No commits in common. "8c19088640635c804bfe349b89a86ccfc63d3c2e" and "d1416d3706c70ea82c5335d2c357cc1b8be129bd" have entirely different histories.
		
	
	
		
			8c19088640
			...
			d1416d3706
		
	
		
							
								
								
									
										23
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								README.md
									
									
									
									
									
								
							| @ -265,16 +265,6 @@ python -m flask refresh-milestones | |||||||
| ``` | ``` | ||||||
| Running this command shouldn't reset progress on milestones that are already in the database | Running this command shouldn't reset progress on milestones that are already in the database | ||||||
| and are still in the redeems file. | 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 | ||||||
| Configuration files should be in the instance folder. For folder installation of tlapbot, | Configuration files should be in the instance folder. For folder installation of tlapbot, | ||||||
| that's `instance/` from the root of the Github repository. | that's `instance/` from the root of the Github repository. | ||||||
| @ -323,21 +313,18 @@ REDEEMS={ | |||||||
|     "lurk": {"price": 1, "type": "counter", "info": "Let us know you're going to lurk."}, |     "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."}, |     "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."}, |     "request": {"price": 100, "type": "note", "info": "Request a level, gamemode, skin, etc."}, | ||||||
|     "go_nap": {"goal": 1000, "type": "milestone", "info": "Streamer will go nap when the goal is reached."}, |     "go_nap": {"price": 1, "type": "milestone", "info": "Streamer will go nap when the goal is reached.", "goal": 1000}, | ||||||
|     "inactive": {"price": 100, "type": "note", "info": "Example redeem that is inactive by default", "category": ["inactive"]} |     "inactive": {"price": 100, "type": "note", "info": "Example redeem that is inactive by default", "category": ["inactive"]} | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
| #### File format | #### File format | ||||||
| `redeems.py` is a config file with just a `REDEEMS` key, that assigns a dictionary of redeems to it. | `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. | 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. | ||||||
| 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. Milestone redeems don't use the `"price"` value, they instead need to have a `"goal"`. | - `"price"` value should be an integer that decides how many points the redeem will cost. For milestone redeems, `"price"` determines minimum bid. | ||||||
| - `"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. | - `"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). | - `"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). | ||||||
|  | - `"goal"` is a required field for milestone goals. It should be an integer, deciding the amount of points required to complete the milestone. | ||||||
| - `"category"` is an optional list of strings, the categories the redeem is in. | - `"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`, | 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 | 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( | setup( | ||||||
|     name='tlapbot', |     name='tlapbot', | ||||||
|     version='1.2.1', |     version='1.2.0', | ||||||
|     packages=find_packages(), |     packages=find_packages(), | ||||||
|     include_package_data=True, |     include_package_data=True, | ||||||
|     install_requires=[ |     install_requires=[ | ||||||
|  | |||||||
| @ -49,8 +49,6 @@ def create_app(test_config=None): | |||||||
|     app.cli.add_command(db.refresh_counters_command) |     app.cli.add_command(db.refresh_counters_command) | ||||||
|     app.cli.add_command(db.refresh_and_clear_command) |     app.cli.add_command(db.refresh_and_clear_command) | ||||||
|     app.cli.add_command(db.refresh_milestones_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 |     # scheduler job for giving points to users | ||||||
|     def proxy_job(): |     def proxy_job(): | ||||||
|  | |||||||
| @ -35,8 +35,6 @@ def insert_counters(db): | |||||||
|                 db.commit() |                 db.commit() | ||||||
|             except sqlite3.Error as e: |             except sqlite3.Error as e: | ||||||
|                 print("Failed inserting counters to db:", e.args[0]) |                 print("Failed inserting counters to db:", e.args[0]) | ||||||
|                 return False |  | ||||||
|     return True |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def init_db(): | def init_db(): | ||||||
| @ -45,8 +43,7 @@ def init_db(): | |||||||
|     with current_app.open_resource('schema.sql') as f: |     with current_app.open_resource('schema.sql') as f: | ||||||
|         db.executescript(f.read().decode('utf8')) |         db.executescript(f.read().decode('utf8')) | ||||||
| 
 | 
 | ||||||
|     if insert_counters(db): |     insert_counters(db) | ||||||
|         return True |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def clear_redeem_queue(): | def clear_redeem_queue(): | ||||||
| @ -62,8 +59,6 @@ def clear_redeem_queue(): | |||||||
|         db.commit() |         db.commit() | ||||||
|     except sqlite3.Error as e: |     except sqlite3.Error as e: | ||||||
|         print("Error occured deleting redeem queue:", e.args[0]) |         print("Error occured deleting redeem queue:", e.args[0]) | ||||||
|         return False |  | ||||||
|     return True |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def refresh_counters(): | def refresh_counters(): | ||||||
| @ -74,9 +69,7 @@ def refresh_counters(): | |||||||
|         db.commit() |         db.commit() | ||||||
|     except sqlite3.Error as e: |     except sqlite3.Error as e: | ||||||
|         print("Error occured deleting old counters:", e.args[0]) |         print("Error occured deleting old counters:", e.args[0]) | ||||||
|         return False |     insert_counters(db) | ||||||
|     if insert_counters(db): |  | ||||||
|         return True |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def refresh_milestones(): | def refresh_milestones(): | ||||||
| @ -97,7 +90,6 @@ def refresh_milestones(): | |||||||
|         db.commit() |         db.commit() | ||||||
|     except sqlite3.Error as e: |     except sqlite3.Error as e: | ||||||
|         print("Failed deleting old milestones from db:", e.args[0]) |         print("Failed deleting old milestones from db:", e.args[0]) | ||||||
|         return False |  | ||||||
| 
 | 
 | ||||||
|     # add new milestones |     # add new milestones | ||||||
|     try: |     try: | ||||||
| @ -122,29 +114,26 @@ def refresh_milestones(): | |||||||
|         db.commit() |         db.commit() | ||||||
|     except sqlite3.Error as e: |     except sqlite3.Error as e: | ||||||
|         print("Failed inserting milestones to db:", e.args[0]) |         print("Failed inserting milestones to db:", e.args[0]) | ||||||
|         return False |  | ||||||
|     return True |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| def reset_milestone(milestone): | def reset_milestone(milestone): | ||||||
|     if not milestone in current_app.config['REDEEMS']: |     if not redeem_name in current_app.config['REDEEMS']: | ||||||
|         print(f"Failed resetting milestone, {milestone} not in redeems file.") |         print(f"Failed resetting milestone, {milestone} not in redeems file.") | ||||||
|         return False |         return None | ||||||
|     try: |     try: | ||||||
|         db = get_db() |  | ||||||
|         db.execute( |         db.execute( | ||||||
|             "DELETE FROM milestones WHERE name = ?", |             "DELETE FROM milestones WHERE name = ?", | ||||||
|             (milestone,) |             (milestone,) | ||||||
|         ) |         ) | ||||||
|         db.execute( |         db.execute( | ||||||
|             "INSERT INTO milestones(name, progress, goal, complete) VALUES(?, ?, ?, FALSE)", |             "INSERT INTO milestones(name, progress, goal) VALUES(?, ?, ?)", | ||||||
|             (milestone, 0, current_app.config['REDEEMS'][milestone]['goal']) |             (milestone, 0, current_app.config['REDEEMS'][milestone]['goal']) | ||||||
|         ) |         ) | ||||||
|         db.commit() |         db.commit() | ||||||
|         return True |         return True | ||||||
|     except sqlite3.Error as e: |     except Error as e: | ||||||
|         current_app.logger.error(f"Error occured adding a milestone: {e.args[0]}") |         current_app.logger.error(f"Error occured adding a milestone: {e.args[0]}") | ||||||
|         return False |         return None | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @ -152,16 +141,16 @@ def reset_milestone(milestone): | |||||||
| @with_appcontext | @with_appcontext | ||||||
| def init_db_command(): | def init_db_command(): | ||||||
|     """Clear the existing data and create new tables.""" |     """Clear the existing data and create new tables.""" | ||||||
|     if init_db(): |     init_db() | ||||||
|         click.echo('Initialized the database.') |     click.echo('Initialized the database.') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @click.command('clear-queue') | @click.command('clear-queue') | ||||||
| @with_appcontext | @with_appcontext | ||||||
| def clear_queue_command(): | def clear_queue_command(): | ||||||
|     """Remove all redeems from the redeem queue.""" |     """Remove all redeems from the redeem queue.""" | ||||||
|     if clear_redeem_queue(): |     clear_redeem_queue() | ||||||
|         click.echo('Cleared redeem queue.') |     click.echo('Cleared redeem queue.') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @click.command('refresh-counters') | @click.command('refresh-counters') | ||||||
| @ -169,16 +158,17 @@ def clear_queue_command(): | |||||||
| def refresh_counters_command(): | def refresh_counters_command(): | ||||||
|     """Refresh counters from current config file. |     """Refresh counters from current config file. | ||||||
|     (Remove old ones, add new ones.)""" |     (Remove old ones, add new ones.)""" | ||||||
|     if refresh_counters(): |     refresh_counters() | ||||||
|         click.echo('Counters refreshed.') |     click.echo('Counters refreshed.') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @click.command('clear-refresh') | @click.command('clear-refresh') | ||||||
| @with_appcontext | @with_appcontext | ||||||
| def refresh_and_clear_command(): | def refresh_and_clear_command(): | ||||||
|     """Refresh counters and clear queue.""" |     """Refresh counters and clear queue.""" | ||||||
|     if refresh_counters() and clear_redeem_queue(): |     refresh_counters() | ||||||
|         click.echo('Counters refreshed and queue cleared.') |     clear_redeem_queue() | ||||||
|  |     click.echo('Counters refreshed and queue cleared.') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @click.command('refresh-milestones') | @click.command('refresh-milestones') | ||||||
| @ -186,29 +176,31 @@ def refresh_and_clear_command(): | |||||||
| def refresh_milestones_command(): | def refresh_milestones_command(): | ||||||
|     """Initialize all milestones from the redeems file,  |     """Initialize all milestones from the redeems file,  | ||||||
|     delete milestones not in redeem file.""" |     delete milestones not in redeem file.""" | ||||||
|     if refresh_milestones(): |     refresh_milestones() | ||||||
|         click.echo('Refreshed milestones.') |     click.echo('Refreshed milestones.') | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| @click.command('reset-milestone') | @click.command('reset-milestone') | ||||||
| @click.argument('milestone') | @click.argument('milestone') | ||||||
| def reset_milestone_command(milestone): | def reset_milestone_command(milestone): | ||||||
|     """Resets a completed milestone back to zero.""" |     """Resets a completed milestone back to zero.""" | ||||||
|     if milestone_complete(get_db(), milestone): |     if milestone_complete(milestone): | ||||||
|         if reset_milestone(milestone): |         if reset_milestone(milestone): | ||||||
|             click.echo(f"Reset milestone {milestone}.") |             click.echo(f"Reset milestone {milestone}.") | ||||||
|  |         else: | ||||||
|  |             click.echo(f"Resetting milestone {milestone} failed.") | ||||||
|     else: |     else: | ||||||
|         click.echo(f"Could not reset milestone {milestone}, milestone not completed.") |         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.echo("(You can hard-reset-milestone if you really want to reset it.)") | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| @click.command('hard-reset-milestone') | @click.command('hard-reset-milestone') | ||||||
| @click.argument('milestone') | @click.argument('milestone') | ||||||
| def hard_reset_milestone_command(milestone): | def hard_reset_milestone_command(milestone): | ||||||
|     """Resets any milestone back to zero.""" |     """Resets any milestone back to zero.""" | ||||||
|     if reset_milestone(milestone): |     if reset_milestone(milestone): | ||||||
|         click.echo(f"Hard reset milestone {milestone}.") |             click.echo(f"Hard reset milestone {milestone}.") | ||||||
| 
 |         else: | ||||||
|  |             click.echo(f"Hard resetting milestone {milestone} failed.") | ||||||
| 
 | 
 | ||||||
| def init_app(app): | def init_app(app): | ||||||
|     app.teardown_appcontext(close_db) |     app.teardown_appcontext(close_db) | ||||||
|  | |||||||
| @ -3,6 +3,6 @@ REDEEMS={ | |||||||
|     "lurk": {"price": 1, "type": "counter", "info": "Let us know you're going to lurk."}, |     "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."}, |     "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."}, |     "request": {"price": 100, "type": "note", "info": "Request a level, gamemode, skin, etc."}, | ||||||
|     "go_nap": {"goal": 1000, "type": "milestone", "info": "Streamer will go nap when the goal is reached."}, |     "go_nap": {"type": "milestone", "info": "Streamer will go nap when the goal is reached.", "goal": 1000}, | ||||||
|     "inactive": {"price": 100, "type": "note", "info": "Example redeem that is inactive by default", "category": ["inactive"]} |     "inactive": {"price": 100, "type": "note", "info": "Example redeem that is inactive by default", "category": ["inactive"]} | ||||||
| } | } | ||||||
| @ -22,29 +22,10 @@ def handle_redeem(message, user_id): | |||||||
|         return |         return | ||||||
| 
 | 
 | ||||||
|     db = get_db() |     db = get_db() | ||||||
|  |     price = current_app.config['REDEEMS'][redeem]["price"] | ||||||
|     redeem_type = current_app.config['REDEEMS'][redeem]["type"] |     redeem_type = current_app.config['REDEEMS'][redeem]["type"] | ||||||
|     points = read_users_points(db, user_id) |     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: |     if not points or points < price: | ||||||
|         send_chat(f"Can't redeem {redeem}, you don't have enough points.") |         send_chat(f"Can't redeem {redeem}, you don't have enough points.") | ||||||
|         return |         return | ||||||
| @ -69,5 +50,20 @@ def handle_redeem(message, user_id): | |||||||
|             send_chat(f"{redeem} redeemed for {price} points.") |             send_chat(f"{redeem} redeemed for {price} points.") | ||||||
|         else: |         else: | ||||||
|             send_chat(f"Redeeming {redeem} failed.") |             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: |     else: | ||||||
|         send_chat(f"{redeem} not redeemed, type of redeem not found.") |         send_chat(f"{redeem} not redeemed, type of redeem not found.") | ||||||
|  | |||||||
| @ -139,11 +139,7 @@ | |||||||
|                 {% for redeem, redeem_info in redeems.items() %} |                 {% for redeem, redeem_info in redeems.items() %} | ||||||
|                 <tbody> |                 <tbody> | ||||||
|                     <td>{{ prefix }}{{ redeem }}</td> |                     <td>{{ prefix }}{{ redeem }}</td> | ||||||
|                     {% if redeem_info["type"] == "milestone" %} |  | ||||||
|                     <td></td> |  | ||||||
|                     {% else %} |  | ||||||
|                     <td>{{ redeem_info["price"] }}</td> |                     <td>{{ redeem_info["price"] }}</td> | ||||||
|                     {% endif %} |  | ||||||
|                     <td>{{ redeem_info["type"] }}</td> |                     <td>{{ redeem_info["type"] }}</td> | ||||||
|                     {% if redeem_info["info"] %} |                     {% if redeem_info["info"] %} | ||||||
|                     <td>{{ redeem_info["info"] }}</td> |                     <td>{{ redeem_info["info"] }}</td> | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user