Compare commits
10 Commits
d1416d3706
...
8c19088640
Author | SHA1 | Date |
---|---|---|
Lili (Tlapka) | 8c19088640 | |
Lili (Tlapka) | 5316f7e205 | |
Lili (Tlapka) | 31426fd851 | |
Lili (Tlapka) | 8d5a3cda42 | |
Lili (Tlapka) | e237e7f885 | |
Lili (Tlapka) | 80037593a9 | |
Lili (Tlapka) | d484a0a363 | |
Lili (Tlapka) | 348e674f74 | |
Lili (Tlapka) | ca9aa6d79d | |
Lili (Tlapka) | 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
|
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.
|
||||||
|
@ -313,18 +323,21 @@ 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": {"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"]}
|
"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. 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.
|
- `"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"`.
|
||||||
- `"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).
|
|
||||||
- `"goal"` is a required field for milestone goals. It should be an integer, deciding the amount of points required to complete the milestone.
|
- `"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.
|
- `"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.0',
|
version='1.2.1',
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
install_requires=[
|
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_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,6 +35,8 @@ 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():
|
||||||
|
@ -43,7 +45,8 @@ 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'))
|
||||||
|
|
||||||
insert_counters(db)
|
if insert_counters(db):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def clear_redeem_queue():
|
def clear_redeem_queue():
|
||||||
|
@ -59,6 +62,8 @@ 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():
|
||||||
|
@ -69,7 +74,9 @@ 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])
|
||||||
insert_counters(db)
|
return False
|
||||||
|
if insert_counters(db):
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def refresh_milestones():
|
def refresh_milestones():
|
||||||
|
@ -90,6 +97,7 @@ 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:
|
||||||
|
@ -114,26 +122,29 @@ 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 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.")
|
print(f"Failed resetting milestone, {milestone} not in redeems file.")
|
||||||
return None
|
return False
|
||||||
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) VALUES(?, ?, ?)",
|
"INSERT INTO milestones(name, progress, goal, complete) VALUES(?, ?, ?, FALSE)",
|
||||||
(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 Error as e:
|
except sqlite3.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 None
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -141,16 +152,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."""
|
||||||
init_db()
|
if 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."""
|
||||||
clear_redeem_queue()
|
if clear_redeem_queue():
|
||||||
click.echo('Cleared redeem queue.')
|
click.echo('Cleared redeem queue.')
|
||||||
|
|
||||||
|
|
||||||
@click.command('refresh-counters')
|
@click.command('refresh-counters')
|
||||||
|
@ -158,17 +169,16 @@ 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.)"""
|
||||||
refresh_counters()
|
if 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."""
|
||||||
refresh_counters()
|
if refresh_counters() and clear_redeem_queue():
|
||||||
clear_redeem_queue()
|
click.echo('Counters refreshed and queue cleared.')
|
||||||
click.echo('Counters refreshed and queue cleared.')
|
|
||||||
|
|
||||||
|
|
||||||
@click.command('refresh-milestones')
|
@click.command('refresh-milestones')
|
||||||
|
@ -176,31 +186,29 @@ 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."""
|
||||||
refresh_milestones()
|
if 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(milestone):
|
if milestone_complete(get_db(), 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": {"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"]}
|
"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
|
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
|
||||||
|
@ -50,20 +69,5 @@ 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,7 +139,11 @@
|
||||||
{% 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…
Reference in New Issue