Commit 58966b03 authored by Jens Reidel's avatar Jens Reidel
Browse files

Merge branch 'experiments' into 'v4'

v4.9.0

See merge request Kenvyra/IdleRPG!629
parents 9a6655ab 8f44f2fa
Pipeline #1776 passed with stages
in 2 minutes and 44 seconds
{{ range .Versions }}
<a name="{{ .Tag.Name }}"></a>
## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }}
> {{ datetime "2006-01-02" .Tag.Date }}
{{ range .CommitGroups -}}
### {{ .Title }}
{{ range .Commits -}}
- {{ .Subject }}
{{ end }}
{{ end -}}
* {{ .Subject }}
{{ end }}
{{ end -}}
{{- if .RevertCommits -}}
### Reverts
{{ range .RevertCommits -}}
- {{ .Revert.Header }}
{{ end }}
{{ end -}}
* {{ .Revert.Header }}
{{ end }}
{{ end -}}
{{- if .MergeCommits -}}
### Merge Requests
{{ range .MergeCommits -}}
- {{ .Header }}
{{ end }}
{{ end -}}
* {{ .Header }}
{{ end }}
{{ end -}}
{{- if .NoteGroups -}}
{{ range .NoteGroups -}}
### {{ .Title }}
{{ range .Notes }}
......@@ -45,4 +37,4 @@
{{ end }}
{{ end -}}
{{ end -}}
{{ end -}}
{{ end -}}
\ No newline at end of file
......@@ -5,12 +5,12 @@ info:
repository_url: https://git.travitia.xyz/Kenvyra/IdleRPG
options:
commits:
# filters:
# Type:
# - feat
# - fix
# - perf
# - refactor
# filters:
# Type:
# - feat
# - fix
# - perf
# - refactor
commit_groups:
# title_maps:
# feat: Features
......@@ -24,4 +24,4 @@ options:
- Type
notes:
keywords:
- BREAKING CHANGE
- BREAKING CHANGE
\ No newline at end of file
Dockerfile
schema.sql
requirements.txt
setup.cfg
requirements-dev.txt
LICENSE
......
......@@ -2,9 +2,11 @@ image: "gelbpunkt/python:ci"
before_script:
- python --version
- echo "https://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories && apk add podman
stages:
- Static Analysis
- Test Podman Build
black:
stage: Static Analysis
......@@ -25,3 +27,9 @@ flake8:
script:
- flake8 --version
- flake8
build:
stage: Test Podman Build
script:
- podman --version
- podman build --storage-driver vfs --runtime runc -t idlerpg:latest .
arch: amd64
language: shell
os: linux
dist: focal
jobs:
include:
- name: "x86_64 Ubuntu 20.04"
os: linux
dist: focal
arch: amd64
- name: "aarch64 Ubuntu 20.04"
os: linux
dist: focal
arch: arm64
allow_failures:
- name: "aarch64 Ubuntu 20.04"
before_install:
- . /etc/os-release
- sudo sh -c "echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list"
- curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key | sudo apt-key add -
- sudo apt update
- sudo apt -y install podman uidmap
script:
- |
if [ $TRAVIS_BRANCH == "v4" ]; then
podman build --cgroup-manager=cgroupfs -t gelbpunkt/idlerpg:latest .;
else
podman build --cgroup-manager=cgroupfs -t gelbpunkt/idlerpg:latest --build-arg beta=true .;
fi
<a name="v4.9.0"></a>
## [v4.9.0](https://git.travitia.xyz/Kenvyra/IdleRPG/compare/v4.8.0...v4.9.0)
> 2020-08-06
### New features
* Reminders using [aioscheduler](https://github.com/Gelbpunkt/aioscheduler), a library built by us for this purpose. `$remind 3min do your homework`, `$remind cancel` and `$remind list`
* Embed in `$status` message instead of text
* `$werewolf` had a rather big update with new game modes and time variants, please check it out
* The maximum guild bank size is now $2,500,000, i.e. further `$guild upgrade`s are available
### Fixes
* After a long revision time, `$trade` is available again and unexploitable. Many thanks go to my Dad for precious SQL knowledge
* All inconsistencies with the 4.8.0 release and the new caching metholodgy should be resolved
* Several potential exploit fixes that I discovered when redoing `$trade`
### Internal changes
* We moved CI builds from Travis to Gitlab CI entirely
* The entire build now uses a custom package index rather than hacky GitHub-hosted index files
### Removals
* Removed Ikhdosa raid
### Translations
* Brazilian and French have been revised and updated
### Merge Requests
* Merge branch 'scheduler' into 'experiments'
* Merge branch 'patch-22' into 'experiments'
* Merge branch 'patch-21' into 'experiments'
* Merge branch 'patch-1' into 'v4'
* Merge branch 'raid-rm' into 'v4'
* Merge branch 'patch-20' into 'experiments'
* Merge branch 'patch-19' into 'experiments'
* Merge branch 'patch-18' into 'experiments'
* Merge branch 'patch-1' into 'v4'
* Merge branch 'trade-text' into 'experiments'
* Merge branch 'patch-15' into 'v4'
* Merge branch 'patch-17' into 'v4'
* Merge branch 'typo-patch' into 'v4'
* Merge branch 'patch-1' into 'v4'
* Merge branch 'patch-1' into 'v4'
* Merge branch 'help' into 'v4'
* Merge branch 'patch-2' into 'v4'
* Merge branch 'patch-16' into 'v4'
* Merge branch 'patch-1' into 'v4'
* Merge branch 'patch-1' into 'v4'
* Merge branch 'patch-1' into 'v4'
<a name="v4.8.0"></a>
## [v4.8.0](https://git.travitia.xyz/Kenvyra/IdleRPG/compare/v4.7.0...v4.8.0)
......
FROM gelbpunkt/python:gcc10
FROM docker.io/gelbpunkt/python:gcc10
ARG beta
RUN if [ -z "$beta" ]; then \
echo "INFO: Building release version!"; \
else \
echo "INFO: Building beta version!"; \
fi && \
sleep 3 && \
set -ex && \
adduser -S idle && \
RUN adduser -S idle && \
apk upgrade --no-cache && \
apk add --no-cache --virtual .fetch-deps curl && \
if [[ "$(uname -m)" = "x86_64" && "$beta" ]]; then \
BRANCH="3.9-x86_64-beta"; \
elif [ "$(uname -m)" = "x86_64" ]; then \
BRANCH="3.9-x86_64"; \
elif [ "$(uname -m)" = "aarch64" ]; then \
BRANCH="3.9-aarch64"; \
else \
echo "Unsupport architecture" && exit 1; \
fi && \
curl -sL "https://raw.githubusercontent.com/Gelbpunkt/alpine-python-wheels/$BRANCH/index-order" \
| while read p; do \
pip install --no-deps --no-cache-dir "https://raw.githubusercontent.com/Gelbpunkt/alpine-python-wheels/$BRANCH/wheels/$p"; \
done && \
apk del .fetch-deps --no-network && \
apk add --no-cache git libgcc
USER idle
WORKDIR /idlerpg
COPY . .
COPY requirements.txt /idlerpg/
RUN git remote set-url origin https://git.travitia.xyz/Kenvyra/IdleRPG.git && \
chown -R idle:nogroup .
RUN pip install --no-cache-dir -i https://packages.travitia.xyz/root/idle/+simple/ --no-warn-script-location --pre --use-feature=2020-resolver -r requirements.txt
USER idle
COPY . /idlerpg/
RUN git remote set-url origin https://git.travitia.xyz/Kenvyra/IdleRPG.git
CMD python launcher.py
# IdleRPG
[![Build Status](https://api.travis-ci.com/Gelbpunkt/IdleRPG.svg)](https://travis-ci.com/Gelbpunkt/IdleRPG)
[![CI](https://git.travitia.xyz/Kenvyra/IdleRPG/badges/v4/pipeline.svg)](https://git.travitia.xyz/Kenvyra/IdleRPG)
[![Dockerhub](https://img.shields.io/badge/Pull%20IdleRPG-from%20Dockerhub-orange)](https://hub.docker.com/r/gelbpunkt/idlerpg)
[![okapi](https://img.shields.io/badge/Pull%20okapi-from%20Dockerhub-black)](https://hub.docker.com/r/gelbpunkt/okapi)
[![teatro](https://img.shields.io/badge/Pull%20teatro-from%20Dockerhub-green)](https://hub.docker.com/r/gelbpunkt/teatro)
......
......@@ -32,6 +32,7 @@ import asyncpg
import discord
import fantasy_names as fn
from aioscheduler import TimedScheduler
from discord.ext import commands
import config
......@@ -56,6 +57,7 @@ class Bot(commands.AutoShardedBot):
) # we overwrite the prefix when it is connected
# setup stuff
self.queue = asyncio.Queue() # global queue for ordered tasks
self.schedule_manager = TimedScheduler()
self.config = config
self.version = config.version
self.paginator = paginator
......@@ -162,7 +164,7 @@ class Bot(commands.AutoShardedBot):
async def invoke(self, ctx):
"""Handler for i18n, executes before any other commands or checks run"""
locale = await self.get_cog("Locale").locale(ctx.message)
locale = await self.get_cog("Locale").locale(ctx.message.author.id)
i18n.current_locale.set(locale)
await super().invoke(ctx)
......@@ -648,14 +650,6 @@ class Bot(commands.AutoShardedBot):
"clear_donator_cache", 0, args={"user_id": user}
)
async def start_transaction(self, user):
user = user if isinstance(user, int) else user.id
await self.cogs["Sharding"].handler("temp_ban", 0, args={"user_id": user})
async def end_transaction(self, user):
user = user if isinstance(user, int) else user.id
await self.cogs["Sharding"].handler("temp_unban", 0, args={"user_id": user})
@cache(maxsize=8096)
async def get_donator_rank(self, user_id):
try:
......
......@@ -113,6 +113,15 @@ class DateOutOfRange(commands.BadArgument):
self.min_ = min_
class InvalidTime(commands.BadArgument):
def __init__(self, text: str) -> None:
self.text = text
class InvalidWerewolfMode(commands.BadArgument):
pass
class User(commands.UserConverter):
@cache(maxsize=8096)
async def convert(self, ctx: Context, argument: str) -> discord.User:
......@@ -222,3 +231,52 @@ class DateNewerThan(commands.Converter):
if date < self.min_date or date > datetime.date.today():
raise DateOutOfRange(self.min_date)
return date
def parse_date(date_string):
return dateparser.parse(
date_string,
settings={
"TO_TIMEZONE": "UTC",
"PREFER_DATES_FROM": "future",
"RETURN_AS_TIMEZONE_AWARE": False,
},
languages=["en"],
)
class DateTimeScheduler(commands.Converter):
async def convert(self, ctx, content):
if content.startswith("me"):
content = content.replace("me", "", 1).strip()
# catches "remind me"
if time := parse_date(content):
subject = _("something")
else:
stuff = content.split()
worked = False
for i in range(len(stuff) - 1, -1, -1):
time, subject = " ".join(stuff[:i]), " ".join(stuff[i:])
if time := parse_date(time):
worked = True
break
if not worked:
raise InvalidTime(_("Could not determine a time from this."))
if time < datetime.datetime.utcnow():
raise InvalidTime(_("That time is in the past."))
return time + datetime.timedelta(seconds=1), subject
class WerewolfMode(commands.Converter):
async def convert(self, ctx, arg):
mode = arg.title()
game_modes = [
"Classic",
"Imbalanced",
"Huntergame",
"Villagergame",
"Valentines",
]
if mode not in game_modes:
raise InvalidWerewolfMode()
return mode
......@@ -538,6 +538,7 @@ class Adventure(commands.Cog):
minvalue=round(num * luck_multiply),
maxvalue=round(num * 50 * luck_multiply),
owner=ctx.author,
conn=conn,
)
storage_type = "inventory"
......
......@@ -33,6 +33,7 @@ from classes.converters import (
DateOutOfRange,
InvalidCoinSide,
InvalidCrateRarity,
InvalidTime,
NotInRange,
UserHasNoChar,
)
......@@ -119,6 +120,8 @@ class Errorhandler(commands.Cog):
" than {date}."
).format(date=error.min_)
)
elif isinstance(error, InvalidTime):
await ctx.send(error.text)
else:
await ctx.send(_("You used a malformed argument!"))
elif isinstance(error, GlobalCooldown):
......
......@@ -16,6 +16,7 @@ You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import asyncio
import datetime
import discord
......@@ -23,6 +24,8 @@ from discord import utils
from discord.ext import commands
from classes.converters import MemberConverter, User
from utils import i18n
from utils.i18n import _
from utils.loops import queue_manager
......@@ -60,6 +63,8 @@ class GlobalEvents(commands.Cog):
self.bot.loop.create_task(queue_manager(self.bot, self.bot.queue))
await self.bot.is_owner(self.bot.user) # force getting the owners
await self.status_updater()
await self.reschedule_reminders()
self.bot.schedule_manager.start()
else:
self.bot.logger.warning("[INFO] Discord fired on_ready...")
......@@ -223,6 +228,43 @@ class GlobalEvents(commands.Cog):
)
}
async def reschedule_reminders(self):
valid_channels = [channel.id for channel in self.bot.get_all_channels()]
all_reminders = await self.bot.pool.fetch("SELECT * FROM reminders;")
now = datetime.datetime.utcnow()
invalid_reminders = []
new_reminders = {}
for reminder in all_reminders:
if reminder["end"] < now:
invalid_reminders.append(reminder["id"])
elif reminder["channel"] not in valid_channels:
pass # don't schedule channels that the bot won't be able to send to
else:
locale = await self.bot.get_cog("Locale").locale(reminder["user"])
i18n.current_locale.set(locale)
task = self.bot.schedule_manager.schedule(
self.bot.get_channel(reminder["channel"]).send(
_(
"{user}, you wanted to be reminded about {subject} {diff}"
" ago."
).format(
user=f"<@{reminder['user']}>",
subject=reminder["content"],
diff=str(reminder["end"] - reminder["start"]).split(".")[0],
)
),
reminder["end"],
)
new_reminders.update({reminder["id"]: task.uuid})
async with self.bot.pool.acquire() as conn:
await conn.execute(
'DELETE FROM reminders WHERE "id"=ANY($1);', invalid_reminders
)
await conn.executemany(
'UPDATE reminders SET "internal_id"=$2 WHERE "id"=$1',
new_reminders.items(),
)
def cog_unload(self):
self.stats_updates.cancel()
......
......@@ -36,6 +36,7 @@ class Gods(commands.Cog):
@has_god()
@has_char()
@user_cooldown(180, identifier="sacrificeexchange")
@commands.command(brief=_("Sacrifice loot for favor"))
@locale_doc
async def sacrifice(self, ctx, *loot_ids: int):
......@@ -49,17 +50,10 @@ class Gods(commands.Cog):
Only players, who follow a God can use this command."""
)
if await self.bot.redis.execute("GET", f"cd:{ctx.author.id}:exchange"):
return await ctx.send(
_(
"You cannot sacrifice while already exchanging loot. Please finish"
" exchanging first, then try again."
)
)
async with self.bot.pool.acquire() as conn:
if len(loot_ids) == 0:
if not loot_ids:
value, count = await conn.fetchval(
'SELECT (SUM("value"), COUNT(*)) FROM loot WHERE "user"=$1',
'SELECT (SUM("value"), COUNT(*)) FROM loot WHERE "user"=$1;',
ctx.author.id,
)
if count == 0:
......
......@@ -947,7 +947,7 @@ class Guild(commands.Cog):
_(
"""Upgrade your guild's bank, adding space for $250,000 each time.
Guilds can be upgraded 4 times which sets them to a maximum of $1,000,000.
Guilds can be upgraded 9 times which sets them to a maximum of $2,500,000.
Patrons will be able to upgrade their guild further:
- Silver donors can double their maximum bank space
- Gold donors can quintuple (x5) their maximum bank space
......@@ -962,7 +962,7 @@ class Guild(commands.Cog):
)
currentlimit = guild["banklimit"]
newlimit = (guild["upgrade"] + 1) * 250000
if guild["upgrade"] == 4:
if guild["upgrade"] == 10:
return await ctx.send(
_("Your guild already reached the maximum upgrade.")
)
......
......@@ -53,16 +53,15 @@ class Locale(commands.Cog):
async def get_locale(self, user):
"""Gets the locale for a user from DB."""
return await self.bot.pool.fetchval(
'SELECT "locale" FROM user_settings WHERE "user"=$1;', user.id
'SELECT "locale" FROM user_settings WHERE "user"=$1;', user
)
async def locale(self, message):
user = message.author
lang = self.bot.locale_cache.get(user.id, None)
async def locale(self, user):
lang = self.bot.locale_cache.get(user, None)
if lang:
return lang
lang = await self.get_locale(user)
self.bot.locale_cache[user.id] = lang
self.bot.locale_cache[user] = lang
return lang
@commands.group(
......
......@@ -445,38 +445,36 @@ Average hours of work: **{hours}**"""
_("""Shows you the bots current version along with its major updates.""")
await ctx.send(
"""\
**v4.8.0**
https://git.travitia.xyz/Kenvyra/IdleRPG/compare/v4.7.0...v4.8.0
> 2020-07-13
**Changes**
- 24h cooldown on alliance attacks
- Added more music error handling
- Enhanced HTML generation
- Fixed cache wiping, many thanks to Danny, ImRock and Luke, you guys *rock*
- Fixed Travis
- Clarified `$color` and `$loop`
- Cooldown to crate opening
- Many database optimizations using indexes
- A minor exploit fix
- Lots of translation updates, thanks guys!
- Fixed `$alliance attack` logic
- `$merchall` is available again
- Automatic raid outcome announcements
- Fix typos for help info of `$pet play` and `$pet cuddle`
- Fix insanity wave for Guilt
- Fix command access logic for game master and owner commands
- Prohibit rgb values over 255
**Additions**
- Added `$markethistory` to search past market sales
- Added options to `$draw` to play a draw game with someone for money
- Allow opening up to 100 crates at once using `$open rarity amount`
- New command `$offercrate` to offer crates safely
- New profile data caching in Redis to increase performance"""
**v4.9.0**
https://git.travitia.xyz/Kenvyra/IdleRPG/compare/v4.8.0...v4.9.0
> 2020-08-06
**New features**
- Reminders using aioscheduler, a library built by us for this purpose. `$remind 3min do your homework`, `$remind cancel` and `$remind list`
- Embed in `$status` message instead of text
- `$werewolf` had a rather big update with new game modes and time variants, please check it out
- The maximum guild bank size is now $2,500,000, i.e. further `$guild upgrade`s are available
**Fixes**
- After a long revision time, `$trade` is available again and unexploitable. Many thanks go to my Dad for precious SQL knowledge
- All inconsistencies with the 4.8.0 release and the new caching metholodgy should be resolved
- Several potential exploit fixes that I discovered when redoing `$trade`
**Internal changes**
- We moved CI builds from Travis to Gitlab CI entirely
- The entire build now uses a custom package index rather than hacky GitHub-hosted index files
**Removals**
- Removed Ikhdosa raid
**Translations**
- Brazilian and French have been revised and updated"""