Compare commits

..

22 Commits

Author SHA1 Message Date
c4f598c1ba Bump version: 0.14.7 → 0.15.0 2019-07-30 10:22:38 +03:00
c48d90dec3 First step towards removing manual response parsing in Citizen class 2019-07-30 10:22:29 +03:00
953902476f Bump version: 0.14.6.1 → 0.14.7 2019-07-30 09:32:10 +03:00
156cbbb61c Typehinting changes 2019-07-30 09:32:03 +03:00
b72039c865 PyPi needs new version number, even if accidentaly published version has been removed 2019-07-29 15:17:14 +03:00
9587538fdc Merge branch 'master' of github.com:eeriks/erepublik_script
* 'master' of github.com:eeriks/erepublik_script:
  Bump version: 0.14.5 → 0.14.6
2019-07-29 13:54:09 +03:00
e775679581 Bump version: 0.14.5 → 0.14.6 2019-07-29 13:53:17 +03:00
3aa305ea74 Switch from python-slugify to self hosted (Taken from Django 2.2.1 django.utils.text.slugify) 2019-07-29 13:52:33 +03:00
6b2e5ffb68 Bump version: 0.14.5 → 0.14.6 2019-07-29 13:33:02 +03:00
bb8634fe56 After deleting debug directory next request failed if SlowRequests.debug == True 2019-07-29 13:31:07 +03:00
25a0d8993e eRepublikAPI now has it's own token property 2019-07-29 13:19:19 +03:00
a1d10bb427 Bump version: 0.14.4 → 0.14.5 2019-07-23 17:55:08 +03:00
ec701396d9 project name migration 2019-07-23 17:55:04 +03:00
d8035b42e3 Underline too short 2019-07-23 17:53:00 +03:00
42320a14a4 no message 2019-07-23 17:50:14 +03:00
de4b059b7d Package name update: erepublik_script → eRepublik 2019-07-23 16:41:21 +03:00
dc106cc87d Bump version: 0.14.3 → 0.14.4 2019-07-23 14:37:35 +03:00
bb2c13d63a requirement update 2019-07-23 14:37:26 +03:00
ea48fbe7e1 Wall post comment creation endpoints 2019-07-23 14:37:07 +03:00
65a3a9f678 Possible memory leak addressed 2019-07-23 14:36:27 +03:00
0757345e17 . 2019-07-23 14:34:49 +03:00
6f4b32b12c code cleanup 2019-07-22 11:54:33 +03:00
20 changed files with 417 additions and 514 deletions

View File

@ -2,10 +2,8 @@
language: python language: python
python: python:
- 3.7
- 3.6 - 3.6
- 3.5
- 3.4
- 2.7
# Command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors # Command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
install: pip install -U tox-travis install: pip install -U tox-travis

View File

@ -57,7 +57,7 @@ If you are proposing a feature:
Get Started! Get Started!
------------ ------------
Ready to contribute? Here's how to set up `erepublik_script` for local development. Ready to contribute? Here's how to set up `erepublik` for local development.
1. Fork the `erepublik_script` repo on GitHub. 1. Fork the `erepublik_script` repo on GitHub.
2. Clone your fork locally:: 2. Clone your fork locally::
@ -66,8 +66,8 @@ Ready to contribute? Here's how to set up `erepublik_script` for local developme
3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: 3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development::
$ mkvirtualenv erepublik_script $ mkvirtualenv erepublik
$ cd erepublik_script/ $ cd erepublik/
$ python setup.py develop $ python setup.py develop
4. Create a branch for local development:: 4. Create a branch for local development::
@ -79,7 +79,7 @@ Ready to contribute? Here's how to set up `erepublik_script` for local developme
5. When you're done making changes, check that your changes pass flake8 and the 5. When you're done making changes, check that your changes pass flake8 and the
tests, including testing other Python versions with tox:: tests, including testing other Python versions with tox::
$ flake8 erepublik_script tests $ flake8 erepublik tests
$ python setup.py test or py.test $ python setup.py test or py.test
$ tox $ tox
@ -102,7 +102,7 @@ Before you submit a pull request, check that it meets these guidelines:
2. If the pull request adds functionality, the docs should be updated. Put 2. If the pull request adds functionality, the docs should be updated. Put
your new functionality into a function with a docstring, and add the your new functionality into a function with a docstring, and add the
feature to the list in README.rst. feature to the list in README.rst.
3. The pull request should work for Python 2.7, 3.4, 3.5 and 3.6, and for PyPy. Check 3. The pull request should work for Python 3.7.1. Check
https://travis-ci.org/eeriks/erepublik_script/pull_requests https://travis-ci.org/eeriks/erepublik_script/pull_requests
and make sure that the tests pass for all supported Python versions. and make sure that the tests pass for all supported Python versions.

View File

@ -2,6 +2,19 @@
History History
======= =======
0.15.0 (2019-07-30)
-------------------
* CitizenAPI class methods renamed to "private", they are intended to be used internally.
* TODO: None of the Citizen class's methods should return Response object - CitizenAPI is meant for that.
0.14.4 (2019-07-23)
-------------------
* Wall post comment endpoints updated with comment create endpoints.
0.1.0 (2019-07-19) 0.1.0 (2019-07-19)
------------------ ------------------

View File

@ -51,7 +51,7 @@ clean-test: ## remove test and coverage artifacts
rm -fr .pytest_cache rm -fr .pytest_cache
lint: ## check style with flake8 lint: ## check style with flake8
flake8 erepublik_script tests flake8 erepublik tests
test: ## run tests quickly with the default Python test: ## run tests quickly with the default Python
python setup.py test python setup.py test
@ -60,15 +60,15 @@ test-all: ## run tests on every Python version with tox
tox tox
coverage: ## check code coverage quickly with the default Python coverage: ## check code coverage quickly with the default Python
coverage run --source erepublik_script setup.py test coverage run --source erepublik setup.py test
coverage report -m coverage report -m
coverage html coverage html
$(BROWSER) htmlcov/index.html $(BROWSER) htmlcov/index.html
docs: ## generate Sphinx HTML documentation, including API docs docs: ## generate Sphinx HTML documentation, including API docs
rm -f docs/erepublik_script.rst rm -f docs/erepublik.rst
rm -f docs/modules.rst rm -f docs/modules.rst
sphinx-apidoc -o docs/ erepublik_script sphinx-apidoc -o docs/ erepublik
$(MAKE) -C docs clean $(MAKE) -C docs clean
$(MAKE) -C docs html $(MAKE) -C docs html
$(BROWSER) docs/_build/html/index.html $(BROWSER) docs/_build/html/index.html

View File

@ -3,11 +3,11 @@ eRepublik script
================ ================
.. image:: https://img.shields.io/pypi/v/erepublik_script.svg .. image:: https://img.shields.io/pypi/v/erepublik.svg
:target: https://pypi.python.org/pypi/erepublik_script :target: https://pypi.python.org/pypi/erepublik
.. image:: https://readthedocs.org/projects/erepublik-script/badge/?version=latest .. image:: https://readthedocs.org/projects/erepublik/badge/?version=latest
:target: https://erepublik-script.readthedocs.io/en/latest/?badge=latest :target: https://erepublik.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status :alt: Documentation Status
@ -15,7 +15,7 @@ Python package for automated eRepublik playing
* Free software: MIT license * Free software: MIT license
* Documentation: https://erepublik-script.readthedocs.io. * Documentation: https://erepublik.readthedocs.io.
Features Features

View File

@ -4,7 +4,7 @@
# You can set these variables from the command line. # You can set these variables from the command line.
SPHINXOPTS = SPHINXOPTS =
SPHINXBUILD = python -msphinx SPHINXBUILD = python -msphinx
SPHINXPROJ = erepublik_script SPHINXPROJ = erepublik
SOURCEDIR = . SOURCEDIR = .
BUILDDIR = _build BUILDDIR = _build

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# #
# erepublik_script documentation build configuration file, created by # erepublik documentation build configuration file, created by
# sphinx-quickstart on Fri Jun 9 13:47:02 2017. # sphinx-quickstart on Fri Jun 9 13:47:02 2017.
# #
# This file is execfile()d with the current directory set to its # This file is execfile()d with the current directory set to its
@ -22,7 +22,7 @@ import os
import sys import sys
sys.path.insert(0, os.path.abspath('..')) sys.path.insert(0, os.path.abspath('..'))
import erepublik_script import erepublik
# -- General configuration --------------------------------------------- # -- General configuration ---------------------------------------------
@ -56,9 +56,9 @@ author = u"Eriks Karls"
# the built documents. # the built documents.
# #
# The short X.Y version. # The short X.Y version.
version = erepublik_script.__version__ version = erepublik.__version__
# The full version, including alpha/beta/rc tags. # The full version, including alpha/beta/rc tags.
release = erepublik_script.__version__ release = erepublik.__version__
# The language for content autogenerated by Sphinx. Refer to documentation # The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages. # for a list of supported languages.
@ -101,7 +101,7 @@ html_static_path = ['_static']
# -- Options for HTMLHelp output --------------------------------------- # -- Options for HTMLHelp output ---------------------------------------
# Output file base name for HTML help builder. # Output file base name for HTML help builder.
htmlhelp_basename = 'erepublik_scriptdoc' htmlhelp_basename = 'erepublikdoc'
# -- Options for LaTeX output ------------------------------------------ # -- Options for LaTeX output ------------------------------------------
@ -128,7 +128,7 @@ latex_elements = {
# (source start file, target name, title, author, documentclass # (source start file, target name, title, author, documentclass
# [howto, manual, or own class]). # [howto, manual, or own class]).
latex_documents = [ latex_documents = [
(master_doc, 'erepublik_script.tex', (master_doc, 'erepublik.tex',
u'eRepublik script Documentation', u'eRepublik script Documentation',
u'Eriks Karls', 'manual'), u'Eriks Karls', 'manual'),
] ]
@ -139,7 +139,7 @@ latex_documents = [
# One entry per manual page. List of tuples # One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section). # (source start file, name, description, authors, manual section).
man_pages = [ man_pages = [
(master_doc, 'erepublik_script', (master_doc, 'erepublik',
u'eRepublik script Documentation', u'eRepublik script Documentation',
[author], 1) [author], 1)
] ]
@ -151,10 +151,10 @@ man_pages = [
# (source start file, target name, title, author, # (source start file, target name, title, author,
# dir menu entry, description, category) # dir menu entry, description, category)
texinfo_documents = [ texinfo_documents = [
(master_doc, 'erepublik_script', (master_doc, 'erepublik',
u'eRepublik script Documentation', u'eRepublik script Documentation',
author, author,
'erepublik_script', 'erepublik',
'One line description of project.', 'One line description of project.',
'Miscellaneous'), 'Miscellaneous'),
] ]

View File

@ -1,5 +1,5 @@
Welcome to eRepublik script's documentation! Welcome to eRepublik script's documentation!
====================================== ============================================
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2

View File

@ -12,7 +12,7 @@ To install eRepublik script, run this command in your terminal:
.. code-block:: console .. code-block:: console
$ pip install erepublik_script $ pip install erepublik
This is the preferred method to install eRepublik script, as it will always install the most recent stable release. This is the preferred method to install eRepublik script, as it will always install the most recent stable release.

View File

@ -4,4 +4,4 @@ Usage
To use eRepublik script in a project:: To use eRepublik script in a project::
import erepublik_script import erepublik

10
erepublik/__init__.py Normal file
View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
"""Top-level package for eRepublik script."""
__author__ = """Eriks Karls"""
__email__ = 'eriks@72.lv'
__version__ = '__version__ = '0.15.0''
from erepublik import classes, utils
from erepublik.citizen import Citizen

View File

@ -9,7 +9,7 @@ from typing import Dict, List, Tuple, Any, Union
import requests import requests
from requests import Response, RequestException from requests import Response, RequestException
from erepublik_script import classes, utils from erepublik import classes, utils
class Citizen(classes.CitizenAPI): class Citizen(classes.CitizenAPI):
@ -94,6 +94,8 @@ class Citizen(classes.CitizenAPI):
ret = super().__dict__.copy() ret = super().__dict__.copy()
ret.pop('reporter', None) ret.pop('reporter', None)
ret.pop('stop_threads', None) ret.pop('stop_threads', None)
ret.pop('_Citizen__last_war_update_data', None)
ret.update(all_battles=self.all_battles)
return ret return ret
@ -134,7 +136,7 @@ class Citizen(classes.CitizenAPI):
def _login(self): def _login(self):
# MUST BE CALLED TROUGH self.get_csrf_token() # MUST BE CALLED TROUGH self.get_csrf_token()
r = self.post_login(self.token, self.config.email, self.config.password) r = self._post_login(self.config.email, self.config.password)
self.r = r self.r = r
if r.url == "{}/login".format(self.url): if r.url == "{}/login".format(self.url):
@ -286,7 +288,7 @@ class Citizen(classes.CitizenAPI):
Gets main page and updates most information about player Gets main page and updates most information about player
""" """
if html is None: if html is None:
self.get_main() self._get_main()
html = self.r.text html = self.r.text
ugly_js = re.search(r"promotions: (\[{?.*}?]),\s+", html).group(1) ugly_js = re.search(r"promotions: (\[{?.*}?]),\s+", html).group(1)
promos = loads(utils.normalize_html_json(ugly_js)) promos = loads(utils.normalize_html_json(ugly_js))
@ -360,19 +362,19 @@ class Citizen(classes.CitizenAPI):
""" """
if currency not in [1, 62]: if currency not in [1, 62]:
currency = 62 currency = 62
resp = self.post_economy_exchange_retrieve(self.token, False, page, currency) resp = self._post_economy_exchange_retrieve(False, page, currency)
self.details.cc = float(resp.json().get("ecash").get("value")) self.details.cc = float(resp.json().get("ecash").get("value"))
self.details.gold = float(resp.json().get("gold").get("value")) self.details.gold = float(resp.json().get("gold").get("value"))
return resp return resp
def update_job_info(self): def update_job_info(self):
ot = self.get_job_data().json().get("overTime", {}) ot = self._get_job_data().json().get("overTime", {})
if ot: if ot:
self.my_companies.next_ot_time = utils.localize_timestamp(int(ot.get("nextOverTime", 0))) self.my_companies.next_ot_time = utils.localize_timestamp(int(ot.get("nextOverTime", 0)))
self.ot_points = ot.get("points", 0) self.ot_points = ot.get("points", 0)
def update_companies(self): def update_companies(self):
html = self.get_economy_my_companies().text html = self._get_economy_my_companies().text
page_details = loads(re.search(r"var pageDetails\s+= ({.*});", html).group(1)) page_details = loads(re.search(r"var pageDetails\s+= ({.*});", html).group(1))
self.my_companies.work_units = int(page_details.get("total_works", 0)) self.my_companies.work_units = int(page_details.get("total_works", 0))
@ -384,7 +386,7 @@ class Citizen(classes.CitizenAPI):
self.my_companies.update_holding_companies() self.my_companies.update_holding_companies()
def update_inventory(self) -> dict: def update_inventory(self) -> dict:
j = self.get_economy_inventory_items().json() j = self._get_economy_inventory_items().json()
self.inventory.update({"used": j.get("inventoryStatus").get("usedStorage"), self.inventory.update({"used": j.get("inventoryStatus").get("usedStorage"),
"total": j.get("inventoryStatus").get("totalStorage")}) "total": j.get("inventoryStatus").get("totalStorage")})
@ -416,7 +418,7 @@ class Citizen(classes.CitizenAPI):
return j return j
def update_weekly_challenge(self): def update_weekly_challenge(self):
data = self.get_weekly_challenge_data().json() data = self._get_weekly_challenge_data().json()
self.details.pp = data.get("player", {}).get("prestigePoints", 0) self.details.pp = data.get("player", {}).get("prestigePoints", 0)
self.details.next_pp = [] self.details.next_pp = []
for reward in data.get("rewards", {}).get("normal", {}): for reward in data.get("rewards", {}).get("normal", {}):
@ -424,11 +426,7 @@ class Citizen(classes.CitizenAPI):
if status == "rewarded": if status == "rewarded":
continue continue
elif status == "completed": elif status == "completed":
data = { self._post_weekly_challenge_reward(reward.get("id", 0))
"_token": self.token,
"rewardId": reward.get("id", 0)
}
self.post_weekly_challenge_reward(self.token, reward.get("id", 0))
elif reward.get("icon", "") == "energy_booster": elif reward.get("icon", "") == "energy_booster":
pps = re.search(r"Reach (\d+) Prestige Points to unlock the following reward: \+1 Energy", pps = re.search(r"Reach (\d+) Prestige Points to unlock the following reward: \+1 Energy",
reward.get("tooltip", "")) reward.get("tooltip", ""))
@ -439,7 +437,8 @@ class Citizen(classes.CitizenAPI):
if not self.details.current_country: if not self.details.current_country:
self.update_citizen_info() self.update_citizen_info()
resp_json = self.get_military_campaigns().json() resp_json = self._get_military_campaigns().json()
self.all_battles = {}
if resp_json.get("countries"): if resp_json.get("countries"):
for c_id, c_data in resp_json.get("countries").items(): for c_id, c_data in resp_json.get("countries").items():
if int(c_id) not in self.countries: if int(c_id) not in self.countries:
@ -487,7 +486,7 @@ class Citizen(classes.CitizenAPI):
self.write_log(self.health_info) self.write_log(self.health_info)
def _eat(self, colour: str = "blue") -> Response: def _eat(self, colour: str = "blue") -> Response:
response = self.post_eat(self.token, colour) response = self._post_eat(colour)
r_json = response.json() r_json = response.json()
next_recovery = r_json.get("food_remaining_reset").split(":") next_recovery = r_json.get("food_remaining_reset").split(":")
self.energy.set_reference_time( self.energy.set_reference_time(
@ -619,10 +618,8 @@ class Citizen(classes.CitizenAPI):
battle_id = r.get("citizen_contribution")[0].get("battle_id", 0) battle_id = r.get("citizen_contribution")[0].get("battle_id", 0)
ret_battles.append(battle_id) ret_battles.append(battle_id)
ret_battles += (cs_battles_air + cs_battles_ground + ret_battles += cs_battles_air + cs_battles_ground + deployed_battles_air + deployed_battles_ground + \
deployed_battles_air + deployed_battles_ground + ally_battles_air + ally_battles_ground + other_battles_air + other_battles_ground
ally_battles_air + ally_battles_ground +
other_battles_air + other_battles_ground)
return ret_battles return ret_battles
@property @property
@ -643,8 +640,8 @@ class Citizen(classes.CitizenAPI):
if battle.is_rw: if battle.is_rw:
side_id = battle.defender.id if self.config.rw_def_side else battle.invader.id side_id = battle.defender.id if self.config.rw_def_side else battle.invader.id
else: else:
side_id = battle.defender.id if (self.details.current_country in battle.defender.allies + side = self.details.current_country in battle.defender.allies + [battle.defender.id, ]
[battle.defender.id, ]) else battle.invader.id side_id = battle.defender.id if side else battle.invader.id
try: try:
def_points = battle.div.get(div).dom_pts.get('def') def_points = battle.div.get(div).dom_pts.get('def')
inv_points = battle.div.get(div).dom_pts.get('inv') inv_points = battle.div.get(div).dom_pts.get('inv')
@ -689,7 +686,7 @@ class Citizen(classes.CitizenAPI):
break break
def fight(self, battle_id: int, side_id: int, is_air: bool = False, count: int = None): def fight(self, battle_id: int, side_id: int, is_air: bool = False, count: int = None):
data = dict(sideId=side_id, battleId=battle_id, _token=self.token) data = dict(sideId=side_id, battleId=battle_id)
error_count = 0 error_count = 0
ok_to_fight = True ok_to_fight = True
if count is None: if count is None:
@ -718,9 +715,9 @@ class Citizen(classes.CitizenAPI):
def _shoot(self, air: bool, data: dict): def _shoot(self, air: bool, data: dict):
if air: if air:
response = self.post_military_fight_air(self.token, data['battleId'], data['sideId']) response = self._post_military_fight_air(data['battleId'], data['sideId'])
else: else:
response = self.post_military_fight_ground(self.token, data['battleId'], data['sideId']) response = self._post_military_fight_ground(data['battleId'], data['sideId'])
if "Zone is not meant for " in response.text: if "Zone is not meant for " in response.text:
self.sleep(5) self.sleep(5)
@ -752,7 +749,7 @@ class Citizen(classes.CitizenAPI):
# I"m not checking for 1h cooldown. Beware of nightshift work, if calling more than once every 60min # I"m not checking for 1h cooldown. Beware of nightshift work, if calling more than once every 60min
self.update_job_info() self.update_job_info()
if self.ot_points >= 24 and self.energy.food_fights > 1: if self.ot_points >= 24 and self.energy.food_fights > 1:
r = self.post_economy_work_overtime(self.token) r = self._post_economy_work_overtime()
if not r.json().get("status") and r.json().get("message") == "money": if not r.json().get("status") and r.json().get("message") == "money":
self.resign() self.resign()
self.find_new_job() self.find_new_job()
@ -770,7 +767,7 @@ class Citizen(classes.CitizenAPI):
def work(self): def work(self):
if self.energy.food_fights >= 1: if self.energy.food_fights >= 1:
response = self.post_economy_work(self.token, "work") response = self._post_economy_work("work")
js = response.json() js = response.json()
good_msg = ["already_worked", "captcha"] good_msg = ["already_worked", "captcha"]
if not js.get("status") and not js.get("message") in good_msg: if not js.get("status") and not js.get("message") in good_msg:
@ -789,7 +786,7 @@ class Citizen(classes.CitizenAPI):
self.work() self.work()
def train(self): def train(self):
r = self.get_training_grounds_json() r = self._get_training_grounds_json()
tg_json = r.json() tg_json = r.json()
self.details.gold = tg_json["page_details"]["gold"] self.details.gold = tg_json["page_details"]["gold"]
self.tg_contract.update({"free_train": tg_json["hasFreeTrain"]}) self.tg_contract.update({"free_train": tg_json["hasFreeTrain"]})
@ -802,7 +799,7 @@ class Citizen(classes.CitizenAPI):
tgs.append(data["id"]) tgs.append(data["id"])
if tgs: if tgs:
if self.energy.food_fights >= len(tgs): if self.energy.food_fights >= len(tgs):
response = self.post_economy_train(self.token, tgs) response = self._post_economy_train(tgs)
if not response.json().get("status"): if not response.json().get("status"):
self.update_citizen_info() self.update_citizen_info()
self.train() self.train()
@ -868,7 +865,6 @@ class Citizen(classes.CitizenAPI):
employee_companies = {} employee_companies = {}
data = { data = {
"action_type": "production", "action_type": "production",
"_token": self.token,
} }
extra = {} extra = {}
wam_list = [] wam_list = []
@ -905,7 +901,7 @@ class Citizen(classes.CitizenAPI):
wam_holding = self.my_companies.holdings.get(wam_holding_id) wam_holding = self.my_companies.holdings.get(wam_holding_id)
if not self.details.current_region == wam_holding['region_id']: if not self.details.current_region == wam_holding['region_id']:
self.travel(holding_id=wam_holding_id, region_id=wam_holding['region_id']) self.travel(holding_id=wam_holding_id, region_id=wam_holding['region_id'])
response = self.post_economy_work(self.token, "production", wam=wam_list, employ=employee_companies).json() response = self._post_economy_work("production", wam=wam_list, employ=employee_companies).json()
self.reporter.report_action("WORK_WAM_EMPLOYEES", response) self.reporter.report_action("WORK_WAM_EMPLOYEES", response)
if response.get("status"): if response.get("status"):
if self.config.auto_sell: if self.config.auto_sell:
@ -973,7 +969,7 @@ class Citizen(classes.CitizenAPI):
if self.details.residence_country and res_r and not res_r == self.details.current_region: if self.details.residence_country and res_r and not res_r == self.details.current_region:
self._travel(self.details.residence_country, self.details.residence_region) self._travel(self.details.residence_country, self.details.residence_region)
def get_country_travel_region(self, country_id: int) -> int or None: def get_country_travel_region(self, country_id: int) -> int:
r = self.get_travel_regions(country_id=country_id).json() r = self.get_travel_regions(country_id=country_id).json()
regions = r.get("regions") regions = r.get("regions")
regs = [] regs = []
@ -984,7 +980,7 @@ class Citizen(classes.CitizenAPI):
if regs: if regs:
return min(regs, key=lambda _: int(_[1]))[0] return min(regs, key=lambda _: int(_[1]))[0]
else: else:
return None return 0
def travel(self, holding_id=0, battle_id=0, region_id=0): def travel(self, holding_id=0, battle_id=0, region_id=0):
r = self.get_travel_regions(holding_id, battle_id, region_id) r = self.get_travel_regions(holding_id, battle_id, region_id)
@ -1006,7 +1002,7 @@ class Citizen(classes.CitizenAPI):
"inRegionId": region_id, "inRegionId": region_id,
"battleId": 0, "battleId": 0,
} }
return self.post_travel(self.token, "moveAction", **data) return self._post_travel("moveAction", **data)
def get_travel_regions(self, holding_id: int = 0, battle_id: int = 0, region_id: int = 0, def get_travel_regions(self, holding_id: int = 0, battle_id: int = 0, region_id: int = 0,
country_id: int = 0) -> Response: country_id: int = 0) -> Response:
@ -1016,7 +1012,7 @@ class Citizen(classes.CitizenAPI):
"regionId": region_id, "regionId": region_id,
} }
data.update(countryId=country_id) data.update(countryId=country_id)
return self.post_travel_data(self.token, **data) return self._post_travel_data(**data)
def parse_notifications(self, page: int = 1) -> list: def parse_notifications(self, page: int = 1) -> list:
response = self.get_message_alerts(page) response = self.get_message_alerts(page)
@ -1029,23 +1025,23 @@ class Citizen(classes.CitizenAPI):
response = self.get_message_alerts() response = self.get_message_alerts()
while notification_ids(response.text): while notification_ids(response.text):
response = self.post_messages_alert(self.token, notification_ids(response.text)) response = self._post_messages_alert(notification_ids(response.text))
def collect_weekly_reward(self): def collect_weekly_reward(self):
self.update_weekly_challenge() self.update_weekly_challenge()
def collect_daily_task(self) -> Response or None: def collect_daily_task(self) -> None:
self.update_citizen_info() self.update_citizen_info()
if self.details.daily_task_done and not self.details.daily_task_reward: if self.details.daily_task_done and not self.details.daily_task_reward:
return self.post_daily_task_reward(self.token) self._post_daily_task_reward()
def send_mail_to_owner(self) -> Response or None: def send_mail_to_owner(self) -> None:
if not self.details.citizen_id == 1620414: if not self.details.citizen_id == 1620414:
self.send_mail("Started", "time {}".format(self.now.strftime("%Y-%m-%d %H-%M-%S")), [1620414, ]) self.send_mail("Started", "time {}".format(self.now.strftime("%Y-%m-%d %H-%M-%S")), [1620414, ])
self.sleep(1) self.sleep(1)
msg_id = re.search(r"<input type=\"hidden\" value=\"(\d+)\" " msg_id = re.search(r"<input type=\"hidden\" value=\"(\d+)\" "
r"id=\"delete_message_(\d+)\" name=\"delete_message\[]\">", self.r.text).group(1) r"id=\"delete_message_(\d+)\" name=\"delete_message\[]\">", self.r.text).group(1)
return self.post_delete_message(self.token, [msg_id]) self._post_delete_message([msg_id])
def get_market_offers(self, country_id: int = None, product: str = None, quality: int = None) -> dict: def get_market_offers(self, country_id: int = None, product: str = None, quality: int = None) -> dict:
ret = dict() ret = dict()
@ -1083,7 +1079,7 @@ class Citizen(classes.CitizenAPI):
str_q = "q%i" % q str_q = "q%i" % q
data = {'country': country, 'industry': self.available_industries[industry], 'quality': q} data = {'country': country, 'industry': self.available_industries[industry], 'quality': q}
r = self.post_economy_marketplace(self.token, **data) r = self._post_economy_marketplace(**data)
rjson = r.json() rjson = r.json()
obj = items[industry][str_q] obj = items[industry][str_q]
if not rjson.get("error", False): if not rjson.get("error", False):
@ -1112,7 +1108,7 @@ class Citizen(classes.CitizenAPI):
ret = items ret = items
return ret return ret
def buy_food(self) -> Response or None: def buy_food(self) -> None:
self.update_money() self.update_money()
hp_per_quality = {"q1": 2, "q2": 4, "q3": 6, "q4": 8, "q5": 10, "q6": 12, "q7": 20} hp_per_quality = {"q1": 2, "q2": 4, "q3": 6, "q4": 8, "q5": 10, "q6": 12, "q7": 20}
hp_needed = 24 * self.energy.interval * 10 - self.food["total"] hp_needed = 24 * self.energy.interval * 10 - self.food["total"]
@ -1129,14 +1125,13 @@ class Citizen(classes.CitizenAPI):
data = dict(offer=cheapest["offer_id"], amount=amount, price=cheapest["price"], data = dict(offer=cheapest["offer_id"], amount=amount, price=cheapest["price"],
cost=amount * cheapest["price"], quality=cheapest_q, energy=amount * hp_per_quality[cheapest_q]) cost=amount * cheapest["price"], quality=cheapest_q, energy=amount * hp_per_quality[cheapest_q])
self.reporter.report_action("BUY_FOOD", json_val=data) self.reporter.report_action("BUY_FOOD", json_val=data)
return self.buy_from_market(cheapest["offer_id"], amount) self.buy_from_market(cheapest["offer_id"], amount)
else: else:
s = "Don't have enough money! Needed: {}cc, Have: {}cc".format(amount * cheapest["price"], self.details.cc) s = "Don't have enough money! Needed: {}cc, Have: {}cc".format(amount * cheapest["price"], self.details.cc)
self.write_log(s) self.write_log(s)
self.reporter.report_action("BUY_FOOD", value=s) self.reporter.report_action("BUY_FOOD", value=s)
return None
def get_monetary_offers(self, currency: int = 62) -> list: def get_monetary_offers(self, currency: int = 62) -> List[Dict[str, Union[int, float]]]:
if currency not in [1, 62]: if currency not in [1, 62]:
currency = 62 currency = 62
resp = self.update_money(0, currency).json() resp = self.update_money(0, currency).json()
@ -1151,14 +1146,14 @@ class Citizen(classes.CitizenAPI):
return sorted(ret, key=lambda o: (o["price"], -o["amount"])) return sorted(ret, key=lambda o: (o["price"], -o["amount"]))
def buy_monetary_market_offer(self, offer: int, amount: float, currency: int) -> bool: def buy_monetary_market_offer(self, offer: int, amount: float, currency: int) -> bool:
response = self.post_economy_exchange_purchase(self.token, amount, currency, offer) response = self._post_economy_exchange_purchase(amount, currency, offer)
self.details.cc = float(response.json().get("ecash").get("value")) self.details.cc = float(response.json().get("ecash").get("value"))
self.details.gold = float(response.json().get("gold").get("value")) self.details.gold = float(response.json().get("gold").get("value"))
self.reporter.report_action("BUY_GOLD", json_val=response.json(), self.reporter.report_action("BUY_GOLD", json_val=response.json(),
value="New amount {o.cc}cc, {o.gold}g".format(o=self.details)) value="New amount {o.cc}cc, {o.gold}g".format(o=self.details))
return not response.json().get("error", False) return not response.json().get("error", False)
def activate_dmg_booster(self, battle_id: int) -> Response or None: def activate_dmg_booster(self, battle_id: int) -> None:
if self.config.boosters: if self.config.boosters:
duration = 0 duration = 0
if self.boosters.get("100_damageBoosters_5_600", 0) > 0: if self.boosters.get("100_damageBoosters_5_600", 0) > 0:
@ -1169,35 +1164,35 @@ class Citizen(classes.CitizenAPI):
duration = 28800 duration = 28800
elif self.boosters.get("100_damageBoosters_5_86400", 0) > 2: elif self.boosters.get("100_damageBoosters_5_86400", 0) > 2:
duration = 86400 duration = 86400
return self.post_fight_activate_booster(self.token, battle_id, 5, duration, "damage") self._post_fight_activate_booster(battle_id, 5, duration, "damage")
def activate_battle_effect(self, battle_id: int, kind: str): def activate_battle_effect(self, battle_id: int, kind: str) -> Response:
return self.post_activate_battle_effect(self.token, battle_id, kind, self.details.citizen_id) return self._post_activate_battle_effect(battle_id, kind, self.details.citizen_id)
def activate_pp_booster(self, battle_id: int): def activate_pp_booster(self, battle_id: int) -> Response:
return self.post_fight_activate_booster(self.token, battle_id, 1, 180, "prestige_points") return self._post_fight_activate_booster(battle_id, 1, 180, "prestige_points")
def donate_money(self, citizen_id: int = 1620414, amount: float = 0.0, currency: int = 62): def donate_money(self, citizen_id: int = 1620414, amount: float = 0.0, currency: int = 62) -> Response:
""" currency: gold = 62, cc = 1 """ """ currency: gold = 62, cc = 1 """
return self.post_economy_donate_money_action(self.token, citizen_id, amount, currency) return self._post_economy_donate_money_action(citizen_id, amount, currency)
def donate_items(self, citizen_id: int = 1620414, amount: int = 0, industry_id: int = 1, def donate_items(self, citizen_id: int = 1620414, amount: int = 0, industry_id: int = 1,
quality: int = 1) -> Response: quality: int = 1) -> Response:
ind = {v: k for k, v in self.available_industries.items()} ind = {v: k for k, v in self.available_industries.items()}
self.write_log("D,{},q{},{},{}".format(amount, quality, ind[industry_id], citizen_id)) self.write_log("D,{},q{},{},{}".format(amount, quality, ind[industry_id], citizen_id))
return self.post_economy_donate_items_action(self.token, citizen_id, amount, industry_id, quality) return self._post_economy_donate_items_action(citizen_id, amount, industry_id, quality)
def candidate_for_congress(self, presentation: str = "") -> Response: def candidate_for_congress(self, presentation: str = "") -> Response:
return self.post_candidate_for_congress(self.token, presentation) return self._post_candidate_for_congress(presentation)
def candidate_for_party_presidency(self) -> Response: def candidate_for_party_presidency(self) -> Response:
return self.get_candidate_party(self.politics.party_slug) return self._get_candidate_party(self.politics.party_slug)
def accept_money_donations(self): def accept_money_donations(self):
for notification in self.parse_notifications(): for notification in self.parse_notifications():
don_id = re.search(r"erepublik.functions.acceptRejectDonation\(\"accept\", (\d+)\)", notification) don_id = re.search(r"erepublik.functions.acceptRejectDonation\(\"accept\", (\d+)\)", notification)
if don_id: if don_id:
self.get_money_donation_accept(self.token, int(don_id.group(1))) self._get_money_donation_accept(int(don_id.group(1)))
self.sleep(5) self.sleep(5)
def reject_money_donations(self) -> int: def reject_money_donations(self) -> int:
@ -1206,7 +1201,7 @@ class Citizen(classes.CitizenAPI):
donation_ids = re.findall(r"erepublik.functions.acceptRejectDonation\(\"reject\", (\d+)\)", r.text) donation_ids = re.findall(r"erepublik.functions.acceptRejectDonation\(\"reject\", (\d+)\)", r.text)
while donation_ids: while donation_ids:
for don_id in donation_ids: for don_id in donation_ids:
self.get_money_donation_reject(self.token, int(don_id)) self._get_money_donation_reject(int(don_id))
count += 1 count += 1
self.sleep(5) self.sleep(5)
r = self.get_message_alerts() r = self.get_message_alerts()
@ -1214,7 +1209,7 @@ class Citizen(classes.CitizenAPI):
return count return count
def _rw_choose_side(self, battle_id: int, side_id: int) -> Response: def _rw_choose_side(self, battle_id: int, side_id: int) -> Response:
return self.get_battlefield_choose_side(battle_id, side_id) return self._get_battlefield_choose_side(battle_id, side_id)
def should_travel_to_fight(self) -> bool: def should_travel_to_fight(self) -> bool:
ret = False ret = False
@ -1285,12 +1280,12 @@ class Citizen(classes.CitizenAPI):
if count > 0 and not force_fight: if count > 0 and not force_fight:
if self.my_companies.ff_lockdown and self.details.pp > 75: if self.my_companies.ff_lockdown and self.details.pp > 75:
if self.energy.food_fights - self.my_companies.ff_lockdown > 0: if count - self.my_companies.ff_lockdown > 0:
log_msg = ("Fight count modified (old count: {} | FF: {} | " log_msg = ("Fight count modified (old count: {} | FF: {} | "
"WAM ff_lockdown: {} | New count: {})").format( "WAM ff_lockdown: {} | New count: {})").format(
count, self.energy.food_fights, self.my_companies.ff_lockdown, count, self.energy.food_fights, self.my_companies.ff_lockdown,
self.energy.food_fights - self.my_companies.ff_lockdown) count - self.my_companies.ff_lockdown)
count = self.energy.food_fights - self.my_companies.ff_lockdown count -= self.my_companies.ff_lockdown
else: else:
count = 0 count = 0
if count <= 0: if count <= 0:
@ -1375,8 +1370,8 @@ class Citizen(classes.CitizenAPI):
return self.energy.limit + self.details.xp_till_level_up * 10 <= self.energy.available return self.energy.limit + self.details.xp_till_level_up * 10 <= self.energy.available
return False return False
def get_article_comments(self, article_id: int = 2645676, page_id: int = 0): def get_article_comments(self, article_id: int = 2645676, page_id: int = 1) -> Response:
return self.post_article_comments(self.token, article_id, page_id) return self._post_article_comments(article_id, page_id)
def comment_article(self, article_id: int = 2645676, msg: str = None) -> Response: def comment_article(self, article_id: int = 2645676, msg: str = None) -> Response:
if msg is None: if msg is None:
@ -1388,15 +1383,15 @@ class Citizen(classes.CitizenAPI):
r = self.write_article_comment(msg, article_id) r = self.write_article_comment(msg, article_id)
return r return r
def write_article_comment(self, message: str, article_id: int, parent_id: int = None): def write_article_comment(self, message: str, article_id: int, parent_id: int = None) -> Response:
return self.post_article_comments_create(self.token, message, article_id, parent_id) return self._post_article_comments_create(message, article_id, parent_id)
def publish_article(self, title: str, content: str, kind: int): def publish_article(self, title: str, content: str, kind: int) -> Response:
kinds = {1: "First steps in eRepublik", 2: "Battle orders", 3: "Warfare analysis", kinds = {1: "First steps in eRepublik", 2: "Battle orders", 3: "Warfare analysis",
4: "Political debates and analysis", 5: "Financial business", 4: "Political debates and analysis", 5: "Financial business",
6: "Social interactions and entertainment"} 6: "Social interactions and entertainment"}
if kind in kinds: if kind in kinds:
return self.post_write_article(self.token, title, content, self.details.citizenship, kind) return self._post_write_article(title, content, self.details.citizenship, kind)
else: else:
raise classes.ErepublikException( raise classes.ErepublikException(
"Article kind must be one of:\n{}\n'{}' is not supported".format( "Article kind must be one of:\n{}\n'{}' is not supported".format(
@ -1410,7 +1405,6 @@ class Citizen(classes.CitizenAPI):
self.write_log("Trying to sell unsupported industry {}".format(industry)) self.write_log("Trying to sell unsupported industry {}".format(industry))
data = { data = {
"token": self.token,
"country": self.details.citizenship, "country": self.details.citizenship,
"industry": industry, "industry": industry,
"quality": quality, "quality": quality,
@ -1418,12 +1412,12 @@ class Citizen(classes.CitizenAPI):
"price": price, "price": price,
"buy": False, "buy": False,
} }
ret = self.post_economy_marketplace_actions(**data) ret = self._post_economy_marketplace_actions(**data)
self.reporter.report_action("SELL_PRODUCT", ret.json()) self.reporter.report_action("SELL_PRODUCT", ret.json())
return ret return ret
def buy_from_market(self, offer: int, amount: int) -> Response: def buy_from_market(self, offer: int, amount: int) -> Response:
ret = self.post_economy_marketplace_actions(self.token, amount, True, offer=offer) ret = self._post_economy_marketplace_actions(amount, True, offer=offer)
json_ret = ret.json() json_ret = ret.json()
if json_ret.get('error'): if json_ret.get('error'):
return ret return ret
@ -1446,11 +1440,12 @@ class Citizen(classes.CitizenAPI):
raw = wrm raw = wrm
else: else:
continue continue
effective_bonus = cdata["effective_bonus"]
base_prod = float(cdata["base_production"])
if cdata["is_raw"]: if cdata["is_raw"]:
raw += float(cdata["base_production"]) * cdata["effective_bonus"] / 100 raw += base_prod * effective_bonus / 100
else: else:
raw -= cdata["effective_bonus"] / 100 * cdata["base_production"] * \ raw -= effective_bonus / 100 * base_prod * cdata["upgrades"][str(cdata["quality"])]["raw_usage"]
cdata["upgrades"][str(cdata["quality"])]["raw_usage"]
if cdata["industry_token"] == "FOOD": if cdata["industry_token"] == "FOOD":
frm = raw frm = raw
elif cdata["industry_token"] == "WEAPON": elif cdata["industry_token"] == "WEAPON":
@ -1460,14 +1455,11 @@ class Citizen(classes.CitizenAPI):
def assign_factory_to_holding(self, factory_id: int, holding_id: int) -> Response: def assign_factory_to_holding(self, factory_id: int, holding_id: int) -> Response:
""" """
Assigns factory to new holding Assigns factory to new holding
:type factory_id: int
:type holding_id: int
:return: Response object
""" """
return self.post_economy_assign_to_holding(self.token, factory_id, holding_id) return self._post_economy_assign_to_holding(factory_id, holding_id)
def upgrade_factory(self, factory_id: int, level: int) -> Response: def upgrade_factory(self, factory_id: int, level: int) -> Response:
return self.post_economy_upgrade_company(self.token, factory_id, level, self.details.pin) return self._post_economy_upgrade_company(factory_id, level, self.details.pin)
def create_factory(self, industry_id: int, building_type: int = 1) -> Response: def create_factory(self, industry_id: int, building_type: int = 1) -> Response:
""" """
@ -1477,10 +1469,10 @@ class Citizen(classes.CitizenAPI):
Storage={1000: 1, 2000: 2} <- Building_type 2 Storage={1000: 1, 2000: 2} <- Building_type 2
""" """
return self.post_economy_create_company(self.token, industry_id, building_type) return self._post_economy_create_company(industry_id, building_type)
def dissolve_factory(self, factory_id: int) -> Response: def dissolve_factory(self, factory_id: int) -> Response:
return self.post_economy_sell_company(self.token, factory_id, self.details.pin, sell=False) return self._post_economy_sell_company(factory_id, self.details.pin, sell=False)
@property @property
def available_industries(self) -> Dict[str, int]: def available_industries(self) -> Dict[str, int]:
@ -1500,21 +1492,22 @@ class Citizen(classes.CitizenAPI):
return self.available_industries.get(industry_name, 0) return self.available_industries.get(industry_name, 0)
def buy_tg_contract(self) -> Response: def buy_tg_contract(self) -> Response:
ret = self.post_buy_gold_items(self.token, 'gold', "TrainingContract2", 1) ret = self._post_buy_gold_items('gold', "TrainingContract2", 1)
self.reporter.report_action("BUY_TG_CONTRACT", ret.json()) self.reporter.report_action("BUY_TG_CONTRACT", ret.json())
return ret return ret
def resign(self) -> Response or None: def resign(self) -> bool:
self.update_job_info() self.update_job_info()
if self.r.json().get("isEmployee"): if self.r.json().get("isEmployee"):
self.reporter.report_action("RESIGN", self.r.json()) self.reporter.report_action("RESIGN", self.r.json())
return self.post_economy_resign(self.token) self._post_economy_resign()
return None return True
return False
def find_new_job(self) -> Response: def find_new_job(self) -> Response:
r = self.get_economy_job_market_json(self.details.current_country) r = self._get_economy_job_market_json(self.details.current_country)
jobs = r.json().get("jobs") jobs = r.json().get("jobs")
data = dict(token=self.token, citizen=0, salary=10) data = dict(citizen=0, salary=10)
for posting in jobs: for posting in jobs:
salary = posting.get("netSalary") salary = posting.get("netSalary")
limit = posting.get("salaryLimit", 0) limit = posting.get("salaryLimit", 0)
@ -1523,13 +1516,13 @@ class Citizen(classes.CitizenAPI):
if (not limit or salary * 3 < limit) and salary > data["salary"]: if (not limit or salary * 3 < limit) and salary > data["salary"]:
data.update({"citizen": userid, "salary": salary}) data.update({"citizen": userid, "salary": salary})
self.reporter.report_action("APPLYING_FOR_JOB", jobs, str(data['citizen'])) self.reporter.report_action("APPLYING_FOR_JOB", jobs, str(data['citizen']))
return self.post_economy_job_market_apply(**data) return self._post_economy_job_market_apply(**data)
def add_friend(self, player_id: int) -> Response: def add_friend(self, player_id: int) -> Response:
resp = self.get_citizen_hovercard(player_id) resp = self._get_citizen_hovercard(player_id)
rjson = resp.json() rjson = resp.json()
if not any([rjson["isBanned"], rjson["isDead"], rjson["isFriend"], rjson["isOrg"], rjson["isSelf"]]): if not any([rjson["isBanned"], rjson["isDead"], rjson["isFriend"], rjson["isOrg"], rjson["isSelf"]]):
r = self.post_citizen_add_remove_friend(self.token, int(player_id), True) r = self._post_citizen_add_remove_friend(int(player_id), True)
self.write_log("{:<64} (id:{:>11}) added as friend".format(rjson["name"], player_id)) self.write_log("{:<64} (id:{:>11}) added as friend".format(rjson["name"], player_id))
return r return r
return resp return resp
@ -1537,15 +1530,15 @@ class Citizen(classes.CitizenAPI):
def get_country_parties(self, country_id: int = None) -> dict: def get_country_parties(self, country_id: int = None) -> dict:
if country_id is None: if country_id is None:
country_id = self.details.citizenship country_id = self.details.citizenship
r = self.get_rankings_parties(country_id) r = self._get_rankings_parties(country_id)
ret = {} ret = {}
for name, id_ in re.findall(r'<a class="dotted" title="([^"]+)" href="/en/party/[\w\d-]+-(\d+)/1">', r.text): for name, id_ in re.findall(r'<a class="dotted" title="([^"]+)" href="/en/party/[\w\d-]+-(\d+)/1">', r.text):
ret.update({int(id_): name}) ret.update({int(id_): name})
return ret return ret
def get_party_members(self, party_id: int) -> Dict[int, str]: def _get_party_members(self, party_id: int) -> Dict[int, str]:
ret = {} ret = {}
r = super().get_party_members(party_id) r = super()._get_party_members(party_id)
for id_, name in re.findall(r'<a href="//www.erepublik.com/en/main/messages-compose/(\d+)" ' for id_, name in re.findall(r'<a href="//www.erepublik.com/en/main/messages-compose/(\d+)" '
r'title="([\w\d_ .]+)">', r.text): r'title="([\w\d_ .]+)">', r.text):
ret.update({id_: name}) ret.update({id_: name})
@ -1553,11 +1546,11 @@ class Citizen(classes.CitizenAPI):
def get_country_mus(self, country_id: int) -> Dict[int, str]: def get_country_mus(self, country_id: int) -> Dict[int, str]:
ret = {} ret = {}
r = self.get_leaderboards_damage_rankings(country_id) r = self._get_leaderboards_damage_rankings(country_id)
for data in r.json()["mu_filter"]: for data in r.json()["mu_filter"]:
if data["id"]: if data["id"]:
ret.update({data["id"]: data["name"]}) ret.update({data["id"]: data["name"]})
r = self.get_leaderboards_damage_aircraft_rankings(country_id) r = self._get_leaderboards_damage_aircraft_rankings(country_id)
for data in r.json()["mu_filter"]: for data in r.json()["mu_filter"]:
if data["id"]: if data["id"]:
ret.update({data["id"]: data["name"]}) ret.update({data["id"]: data["name"]})
@ -1565,10 +1558,10 @@ class Citizen(classes.CitizenAPI):
def get_mu_members(self, mu_id: int) -> Dict[int, str]: def get_mu_members(self, mu_id: int) -> Dict[int, str]:
ret = {} ret = {}
r = self.get_military_unit_data(mu_id) r = self._get_military_unit_data(mu_id)
for page in range(1, int(r.json()["panelContents"]["pages"]) + 1): for page in range(1, int(r.json()["panelContents"]["pages"]) + 1):
r = self.get_military_unit_data(mu_id, page) r = self._get_military_unit_data(mu_id, page)
for user in r.json()["panelContents"]["members"]: for user in r.json()["panelContents"]["members"]:
if not user["isDead"]: if not user["isDead"]:
ret.update({user["citizenId"]: user["name"]}) ret.update({user["citizenId"]: user["name"]})
@ -1578,13 +1571,13 @@ class Citizen(classes.CitizenAPI):
if ids is None: if ids is None:
ids = [1620414, ] ids = [1620414, ]
for player_id in ids: for player_id in ids:
self.post_messages_compose(self.token, subject, msg, [player_id]) self._post_messages_compose(subject, msg, [player_id])
def add_every_player_as_friend(self): def add_every_player_as_friend(self):
cities = [] cities = []
cities_dict = {} cities_dict = {}
self.write_log("WARNING! This will take a lot of time.") self.write_log("WARNING! This will take a lot of time.")
rj = self.post_travel_data(self.token, regionId=662, check="getCountryRegions").json() rj = self._post_travel_data(regionId=662, check="getCountryRegions").json()
for region_data in rj.get("regions", {}).values(): for region_data in rj.get("regions", {}).values():
cities.append(region_data['cityId']) cities.append(region_data['cityId'])
cities_dict.update({region_data['cityId']: region_data['cityName']}) cities_dict.update({region_data['cityId']: region_data['cityName']})
@ -1592,11 +1585,11 @@ class Citizen(classes.CitizenAPI):
cities.sort(key=int) cities.sort(key=int)
for city_id in cities: for city_id in cities:
self.write_log("Adding friends from {} (id: {})".format(cities_dict[city_id], city_id)) self.write_log("Adding friends from {} (id: {})".format(cities_dict[city_id], city_id))
resp = self.get_city_data_residents(city_id).json() resp = self._get_city_data_residents(city_id).json()
for resident in resp["widgets"]["residents"]["residents"]: for resident in resp["widgets"]["residents"]["residents"]:
self.add_friend(resident["citizenId"]) self.add_friend(resident["citizenId"])
for page in range(2, resp["widgets"]["residents"]["numResults"] // 10 + 2): for page in range(2, resp["widgets"]["residents"]["numResults"] // 10 + 2):
r = self.get_city_data_residents(city_id, page) r = self._get_city_data_residents(city_id, page)
resp = r.json() resp = r.json()
for resident in resp["widgets"]["residents"]["residents"]: for resident in resp["widgets"]["residents"]["residents"]:
self.add_friend(resident["citizenId"]) self.add_friend(resident["citizenId"])
@ -1608,11 +1601,11 @@ class Citizen(classes.CitizenAPI):
self._launch_battle(war_id, region_id) self._launch_battle(war_id, region_id)
def get_active_wars_with_regions(self): def get_active_wars_with_regions(self):
self.get_country_military(self.countries.get(self.details.citizen_id)["name"]) self._get_country_military(self.countries.get(self.details.citizen_id)["name"])
raise NotImplementedError raise NotImplementedError
def _launch_battle(self, war_id: int, region_id: int) -> Response: def _launch_battle(self, war_id: int, region_id: int) -> Response:
return self.post_wars_attack_region(self.token, war_id, region_id) return self._post_wars_attack_region(war_id, region_id)
def state_update_repeater(self): def state_update_repeater(self):
try: try:
@ -1724,31 +1717,31 @@ class Citizen(classes.CitizenAPI):
def activate_house(self, quality: int) -> datetime.datetime: def activate_house(self, quality: int) -> datetime.datetime:
active_until = self.now active_until = self.now
r = self.post_economy_activate_house(self.token, quality) r = self._post_economy_activate_house(quality)
if r.json().get("status") and not r.json().get("error"): if r.json().get("status") and not r.json().get("error"):
house = r.json()["inventoryItems"]["activeEnhancements"]["items"]["4_%i_active" % quality] house = r.json()["inventoryItems"]["activeEnhancements"]["items"]["4_%i_active" % quality]
active_until = utils.good_timedelta(active_until, datetime.timedelta(seconds=house["active"]["time_left"])) active_until = utils.good_timedelta(active_until, datetime.timedelta(seconds=house["active"]["time_left"]))
return active_until return active_until
def collect_anniversary_reward(self) -> Response: def collect_anniversary_reward(self) -> Response:
return self.post_collect_anniversary_reward(self.token) return self._post_collect_anniversary_reward()
def get_battle_round_data(self, battle_id: int, round_id: int, division: int = None) -> dict: def get_battle_round_data(self, battle_id: int, round_id: int, division: int = None) -> dict:
battle = self.all_battles.get(battle_id) battle = self.all_battles.get(battle_id)
if not battle: if not battle:
return {} return {}
r = self.post_battle_console(self.token, battle_id, battle.zone_id, round_id, division, 1, True) r = self._post_battle_console(battle_id, battle.zone_id, round_id, division, 1, True)
return {battle.invader.id: r.json().get(str(battle.invader.id)).get("fighterData"), return {battle.invader.id: r.json().get(str(battle.invader.id)).get("fighterData"),
battle.defender.id: r.json().get(str(battle.defender.id)).get("fighterData")} battle.defender.id: r.json().get(str(battle.defender.id)).get("fighterData")}
def contribute_cc_to_country(self, amount: int or float = 0) -> bool: def contribute_cc_to_country(self, amount=0.) -> bool:
self.update_money() self.update_money()
amount = int(amount) amount = int(amount)
if self.details.cc < amount or amount < 20: if self.details.cc < amount or amount < 20:
return False return False
json = dict(country=71, action='currency', value=amount) data = dict(country=71, action='currency', value=amount)
self.reporter.report_action("CONTRIBUTE_CC", json) self.reporter.report_action("CONTRIBUTE_CC", data)
r = self.post_country_donate(self.token, **json) r = self._post_country_donate(**data)
return r.json().get('status') or not r.json().get('error') return r.json().get('status') or not r.json().get('error')
def contribute_food_to_country(self, amount: int = 0, quality: int = 1) -> bool: def contribute_food_to_country(self, amount: int = 0, quality: int = 1) -> bool:
@ -1756,9 +1749,9 @@ class Citizen(classes.CitizenAPI):
amount = amount // 1 amount = amount // 1
if self.food["q" + str(quality)] < amount or amount < 10: if self.food["q" + str(quality)] < amount or amount < 10:
return False return False
json = dict(country=71, action='food', value=amount, quality=quality) data = dict(country=71, action='food', value=amount, quality=quality)
self.reporter.report_action("CONTRIBUTE_FOOD", json) self.reporter.report_action("CONTRIBUTE_FOOD", data)
r = self.post_country_donate(self.token, **json) r = self._post_country_donate(**data)
return r.json().get('status') or not r.json().get('error') return r.json().get('status') or not r.json().get('error')
def contribute_gold_to_country(self, amount: int) -> bool: def contribute_gold_to_country(self, amount: int) -> bool:
@ -1766,17 +1759,17 @@ class Citizen(classes.CitizenAPI):
if self.details.cc < amount: if self.details.cc < amount:
return False return False
json = dict(country=71, action='gold', value=amount) data = dict(country=71, action='gold', value=amount)
self.reporter.report_action("CONTRIBUTE_GOLD", json) self.reporter.report_action("CONTRIBUTE_GOLD", data)
r = self.post_country_donate(self.token, **json) r = self._post_country_donate(**data)
return r.json().get('status') or not r.json().get('error') return r.json().get('status') or not r.json().get('error')
def write_on_country_wall(self, message: str) -> bool: def write_on_country_wall(self, message: str) -> bool:
self.get_main() self._get_main()
post_to_wall_as = re.findall(r"""id="post_to_country_as".*?<option value="(.*?)">.*?</option>.*</select>""", post_to_wall_as = re.findall(r"""id="post_to_country_as".*?<option value="(.*?)">.*?</option>.*</select>""",
self.r.text, re.S | re.M) self.r.text, re.S | re.M)
if post_to_wall_as: if post_to_wall_as:
self.post_country_post_create(self.token, message, max(post_to_wall_as)) self._post_country_post_create(message, max(post_to_wall_as))
return True return True
return False return False
@ -1788,7 +1781,7 @@ class Citizen(classes.CitizenAPI):
round_id = battle.get('zone_id') round_id = battle.get('zone_id')
division = self.division if round_id % 4 else 11 division = self.division if round_id % 4 else 11
resp = self.post_military_battle_console(self.token, battle_id, round_id, division).json() resp = self._post_military_battle_console(battle_id, round_id, division).json()
resp.pop('rounds', None) resp.pop('rounds', None)
ret = dict() ret = dict()
for country_id, data in resp.items(): for country_id, data in resp.items():

View File

@ -1,4 +1,3 @@
# pylint: disable=fixme, line-too-long, missing-docstring, invalid-name
import datetime import datetime
import decimal import decimal
import hashlib import hashlib
@ -9,9 +8,8 @@ from json import JSONDecodeError, loads, JSONEncoder
from typing import Any, Dict, List, Union from typing import Any, Dict, List, Union
from requests import Response, Session from requests import Response, Session
from slugify import slugify
from erepublik_script import utils from erepublik import utils
class ErepublikException(Exception): class ErepublikException(Exception):
@ -223,12 +221,12 @@ class SlowRequests(Session):
body = "[{dt}]\tURL: '{url}'\tMETHOD: {met}\tARGS: {args}\n".format(dt=utils.now().strftime("%F %T"), body = "[{dt}]\tURL: '{url}'\tMETHOD: {met}\tARGS: {args}\n".format(dt=utils.now().strftime("%F %T"),
url=url, met=method, args=args) url=url, met=method, args=args)
utils.get_file(self.request_log_name)
with open(self.request_log_name, 'ab') as file: with open(self.request_log_name, 'ab') as file:
file.write(body.encode("UTF-8")) file.write(body.encode("UTF-8"))
def _log_response(self, url, resp, redirect: bool = False): def _log_response(self, url, resp, redirect: bool = False):
from erepublik_script import Citizen from erepublik import Citizen
if self.debug: if self.debug:
if resp.history and not redirect: if resp.history and not redirect:
for hist_resp in resp.history: for hist_resp in resp.history:
@ -239,7 +237,7 @@ class SlowRequests(Session):
file_data = { file_data = {
"path": 'debug/requests', "path": 'debug/requests',
"time": self.last_time.strftime('%Y-%m-%d_%H-%M-%S'), "time": self.last_time.strftime('%Y-%m-%d_%H-%M-%S'),
"name": slugify(url[len(Citizen.url):]), "name": utils.slugify(url[len(Citizen.url):]),
"extra": "_REDIRECT" if redirect else "" "extra": "_REDIRECT" if redirect else ""
} }
@ -358,6 +356,7 @@ class Energy:
def available(self): def available(self):
return self.recovered + self.recoverable return self.recovered + self.recoverable
@property
def __dict__(self): def __dict__(self):
return dict( return dict(
limit=self.limit, limit=self.limit,
@ -437,10 +436,14 @@ class House(object):
class CitizenAPI: class CitizenAPI:
url = "https://www.erepublik.com/en" url: str = "https://www.erepublik.com/en"
_req = SlowRequests _req: SlowRequests = None
token: str = ""
def __init__(self): def __init__(self):
"""
Class for unifying eRepublik known endpoints and their required/optional parameters
"""
self._req = SlowRequests() self._req = SlowRequests()
def post(self, url: str, *args, **kwargs) -> Response: def post(self, url: str, *args, **kwargs) -> Response:
@ -449,112 +452,123 @@ class CitizenAPI:
def get(self, url: str, **kwargs) -> Response: def get(self, url: str, **kwargs) -> Response:
return self._req.get(url, **kwargs) return self._req.get(url, **kwargs)
def get_article_json(self, article_id: int) -> Response: def _get_article_json(self, article_id: int) -> Response:
return self.get("{}/main/articleJson/{}".format(self.url, article_id)) return self.get("{}/main/articleJson/{}".format(self.url, article_id))
def get_battlefield_choose_side(self, battle: int, side: int) -> Response: def _get_battlefield_choose_side(self, battle: int, side: int) -> Response:
return self.get("{}/military/battlefield-choose-side/{}/{}".format(self.url, battle, side)) return self.get("{}/military/battlefield-choose-side/{}/{}".format(self.url, battle, side))
def get_candidate_party(self, party_slug: str) -> Response: def _get_candidate_party(self, party_slug: str) -> Response:
return self.post("{}/candidate/{}".format(self.url, party_slug)) return self.post("{}/candidate/{}".format(self.url, party_slug))
def get_citizen_hovercard(self, citizen: int) -> Response: def _get_citizen_hovercard(self, citizen: int) -> Response:
return self.get("{}/main/citizen-hovercard/{}".format(self.url, citizen)) return self.get("{}/main/citizen-hovercard/{}".format(self.url, citizen))
def get_citizen_profile(self, player_id: int): def _get_citizen_profile(self, player_id: int) -> Response:
return self.get("{}/main/citizen-profile-json/{}".format(self.url, player_id)) return self.get("{}/main/citizen-profile-json/{}".format(self.url, player_id))
def get_citizen_daily_assistant(self): def _get_citizen_daily_assistant(self) -> Response:
return self.get("{}/main/citizenDailyAssistant".format(self.url)) return self.get("{}/main/citizenDailyAssistant".format(self.url))
def get_city_data_residents(self, city: int, page: int = 1, params: Dict[str, Any] = {}): def _get_city_data_residents(self, city: int, page: int = 1, params: Dict[str, Any] = None) -> Response:
if params is None:
params = {}
return self.get("{}/main/city-data/{}/residents".format(self.url, city), params={"currentPage": page, **params}) return self.get("{}/main/city-data/{}/residents".format(self.url, city), params={"currentPage": page, **params})
def get_country_military(self, country: str) -> Response: def _get_country_military(self, country: str) -> Response:
return self.get("{}/country/military/{}".format(self.url, country)) return self.get("{}/country/military/{}".format(self.url, country))
def get_economy_inventory_items(self) -> Response: def _get_economy_inventory_items(self) -> Response:
return self.get("{}/economy/inventory-items/".format(self.url)) return self.get("{}/economy/inventory-items/".format(self.url))
def get_economy_job_market_json(self, country: int) -> Response: def _get_economy_job_market_json(self, country: int) -> Response:
return self.get("{}/economy/job-market-json/{}/1/desc".format(self.url, country)) return self.get("{}/economy/job-market-json/{}/1/desc".format(self.url, country))
def get_economy_my_companies(self) -> Response: def _get_economy_my_companies(self) -> Response:
return self.get("{}/economy/myCompanies".format(self.url)) return self.get("{}/economy/myCompanies".format(self.url))
def get_economy_my_market_offers(self) -> Response: def _get_economy_my_market_offers(self) -> Response:
return self.get("{}/economy/myMarketOffers".format(self.url)) return self.get("{}/economy/myMarketOffers".format(self.url))
def get_job_data(self) -> Response: def _get_job_data(self) -> Response:
return self.get("{}/main/job-data".format(self.url)) return self.get("{}/main/job-data".format(self.url))
def get_leaderboards_damage_aircraft_rankings(self, country: int, weeks: int = 0, mu: int = 0) -> Response: def _get_leaderboards_damage_aircraft_rankings(self, country: int, weeks: int = 0, mu: int = 0) -> Response:
data = (country, weeks, mu) data = (country, weeks, mu)
return self.get("{}/main/leaderboards-damage-aircraft-rankings/{}/{}/{}/0".format(self.url, *data)) return self.get("{}/main/leaderboards-damage-aircraft-rankings/{}/{}/{}/0".format(self.url, *data))
def get_leaderboards_damage_rankings(self, country: int, weeks: int = 0, mu: int = 0, div: int = 0) -> Response: def _get_leaderboards_damage_rankings(self, country: int, weeks: int = 0, mu: int = 0, div: int = 0) -> Response:
data = (country, weeks, mu, div) data = (country, weeks, mu, div)
return self.get("{}/main/leaderboards-damage-rankings/{}/{}/{}/{}".format(self.url, *data)) return self.get("{}/main/leaderboards-damage-rankings/{}/{}/{}/{}".format(self.url, *data))
def get_leaderboards_kills_aircraft_rankings(self, country: int, weeks: int = 0, mu: int = 0) -> Response: def _get_leaderboards_kills_aircraft_rankings(self, country: int, weeks: int = 0, mu: int = 0) -> Response:
data = (country, weeks, mu) data = (country, weeks, mu)
return self.get("{}/main/leaderboards-kills-aircraft-rankings/{}/{}/{}/0".format(self.url, *data)) return self.get("{}/main/leaderboards-kills-aircraft-rankings/{}/{}/{}/0".format(self.url, *data))
def get_leaderboards_kills_rankings(self, country: int, weeks: int = 0, mu: int = 0, div: int = 0) -> Response: def _get_leaderboards_kills_rankings(self, country: int, weeks: int = 0, mu: int = 0, div: int = 0) -> Response:
data = (country, weeks, mu, div) data = (country, weeks, mu, div)
return self.get("{}/main/leaderboards-kills-rankings/{}/{}/{}/{}".format(self.url, *data)) return self.get("{}/main/leaderboards-kills-rankings/{}/{}/{}/{}".format(self.url, *data))
def get_main(self): def _get_main(self) -> Response:
return self.get(self.url) return self.get(self.url)
def get_message_alerts(self, page: int = 1) -> Response: def _get_messages(self, page: int = 1) -> Response:
return self.get_message_alerts(page) return self.get("{}/main/messages-paginated/{}".format(self.url, page))
def get_military_campaigns(self) -> Response: def _get_military_campaigns(self) -> Response:
return self.get("{}/military/campaigns-new/".format(self.url)) return self.get("{}/military/campaigns-new/".format(self.url))
def get_military_unit_data(self, unit_id: int, page: int = 1) -> Response: def _get_military_unit_data(self, unit_id: int, **kwargs) -> Response:
params = {"groupId": unit_id, "panel": "members", "currentPage": page} params = {"groupId": unit_id, "panel": "members", **kwargs}
return self.get("{}/military/military-unit-data/".format(self.url), params=params) return self.get("{}/military/military-unit-data/".format(self.url), params=params)
def get_money_donation_accept(self, token: str, donation_id: int) -> Response: def _get_money_donation_accept(self, donation_id: int) -> Response:
return self.get("{}/main/money-donation/accept/{}".format(self.url, donation_id), params={"_token": token}) return self.get("{}/main/money-donation/accept/{}".format(self.url, donation_id), params={"_token": self.token})
def get_money_donation_reject(self, token: str, donation_id: int) -> Response: def _get_money_donation_reject(self, donation_id: int) -> Response:
return self.get("{}/main/money-donation/reject/{}".format(self.url, donation_id), params={"_token": token}) return self.get("{}/main/money-donation/reject/{}".format(self.url, donation_id), params={"_token": self.token})
def get_party_members(self, party: int) -> Response: def _get_notifications_ajax_community(self, page: int = 1) -> Response:
return self.get("{}/main/notificationsAjax/community/{}".format(self.url, page))
def _get_notifications_ajax_system(self, page: int = 1) -> Response:
return self.get("{}/main/notificationsAjax/system/{}".format(self.url, page))
def _get_notifications_ajax_report(self, page: int = 1) -> Response:
return self.get("{}/main/notificationsAjax/report/{}".format(self.url, page))
def _get_party_members(self, party: int) -> Response:
return self.get("{}/main/party-members/{}".format(self.url, party)) return self.get("{}/main/party-members/{}".format(self.url, party))
def get_rankings_parties(self, country: int) -> Response: def _get_rankings_parties(self, country: int) -> Response:
return self.get("{}/main/rankings-parties/1/{}".format(self.url, country)) return self.get("{}/main/rankings-parties/1/{}".format(self.url, country))
def get_training_grounds_json(self) -> Response: def _get_training_grounds_json(self) -> Response:
return self.get("{}/main/training-grounds-json".format(self.url)) return self.get("{}/main/training-grounds-json".format(self.url))
def get_weekly_challenge_data(self) -> Response: def _get_weekly_challenge_data(self) -> Response:
return self.get("{}/main/weekly-challenge-data".format(self.url)) return self.get("{}/main/weekly-challenge-data".format(self.url))
def post_activate_battle_effect(self, token: str, battle: int, kind: str, citizen_id: int) -> Response: def _post_activate_battle_effect(self, battle: int, kind: str, citizen_id: int) -> Response:
data = dict(battleId=battle, citizenId=citizen_id, type=kind, _token=token) data = dict(battleId=battle, citizenId=citizen_id, type=kind, _token=self.token)
return self.post("{}/main/fight-activateBattleEffect".format(self.url), data=data) return self.post("{}/main/fight-activateBattleEffect".format(self.url), data=data)
def post_article_comments(self, token: str, article: int, page: int = 0) -> Response: def _post_article_comments(self, article: int, page: int = 1) -> Response:
data = dict(_token=token, articleId=article, page=page) data = dict(_token=self.token, articleId=article, page=page)
if page: if page:
data.update({'page': page}) data.update({'page': page})
return self.post("{}/main/articleComments".format(self.url), data=data) return self.post("{}/main/articleComments".format(self.url), data=data)
def post_article_comments_create(self, token: str, message: str, article: int, parent: int = 0) -> Response: def _post_article_comments_create(self, message: str, article: int, parent: int = 0) -> Response:
data = dict(_token=token, message=message, articleId=article) data = dict(_token=self.token, message=message, articleId=article)
if parent: if parent:
data.update({"parentId": parent}) data.update({"parentId": parent})
return self.post("{}/main/articleComments/create".format(self.url), data=data) return self.post("{}/main/articleComments/create".format(self.url), data=data)
def post_battle_console(self, token: str, battle: int, zone: int, round_id: int, division: int, page: int, def _post_battle_console(self, battle: int, zone: int, round_id: int, division: int, page: int,
damage: bool) -> Response: damage: bool) -> Response:
data = dict(battleId=battle, zoneId=zone, action="battleStatistics", round=round_id, division=division, data = dict(battleId=battle, zoneId=zone, action="battleStatistics", round=round_id, division=division,
leftPage=page, rightPage=page, _token=token) leftPage=page, rightPage=page, _token=self.token)
if damage: if damage:
data.update({"type": "damage"}) data.update({"type": "damage"})
else: else:
@ -562,124 +576,125 @@ class CitizenAPI:
return self.post("{}/military/battle-console".format(self.url), data=data) return self.post("{}/military/battle-console".format(self.url), data=data)
def post_buy_gold_items(self, token: str, currency: str, item: str, amount: int) -> Response: def _post_buy_gold_items(self, currency: str, item: str, amount: int) -> Response:
data = dict(itemId=item, currency=currency, amount=amount, _token=token) data = dict(itemId=item, currency=currency, amount=amount, _token=self.token)
return self.post("{}/main/buyGoldItems".format(self.url), data=data) return self.post("{}/main/buyGoldItems".format(self.url), data=data)
def post_candidate_for_congress(self, token: str, presentation: str = "") -> Response: def _post_candidate_for_congress(self, presentation: str = "") -> Response:
data = dict(_token=token, presentation=presentation) data = dict(_token=self.token, presentation=presentation)
return self.post("{}/candidate-for-congress".format(self.url), data=data) return self.post("{}/candidate-for-congress".format(self.url), data=data)
def post_citizen_add_remove_friend(self, token: str, citizen: int, add: bool) -> Response: def _post_citizen_add_remove_friend(self, citizen: int, add: bool) -> Response:
data = dict(_token=token, citizenId=citizen, url="//www.erepublik.com/en/main/citizen-addRemoveFriend") data = dict(_token=self.token, citizenId=citizen, url="//www.erepublik.com/en/main/citizen-addRemoveFriend")
if add: if add:
data.update({"action": "addFriend"}) data.update({"action": "addFriend"})
else: else:
data.update({"action": "removeFriend"}) data.update({"action": "removeFriend"})
return self.post("{}/main/citizen-addRemoveFriend".format(self.url), data=data) return self.post("{}/main/citizen-addRemoveFriend".format(self.url), data=data)
def post_collect_anniversary_reward(self, token: str) -> Response: def _post_collect_anniversary_reward(self) -> Response:
return self.post("{}/main/collect-anniversary-reward".format(self.url), data={"_token": token}) return self.post("{}/main/collect-anniversary-reward".format(self.url), data={"_token": self.token})
def post_country_donate(self, token: str, country: int, action: str, value: Union[int, float], quality: int = None): def _post_country_donate(self, country: int, action: str, value: Union[int, float],
json = dict(countryId=country, action=action, _token=token, value=value, quality=quality) quality: int = None) -> Response:
json = dict(countryId=country, action=action, _token=self.token, value=value, quality=quality)
return self.post("{}/main/country-donate".format(self.url), data=json, return self.post("{}/main/country-donate".format(self.url), data=json,
headers={"Referer": "{}/country/economy/Latvia".format(self.url)}) headers={"Referer": "{}/country/economy/Latvia".format(self.url)})
def post_daily_task_reward(self, token: str) -> Response: def _post_daily_task_reward(self) -> Response:
return self.post("{}/main/daily-tasks-reward".format(self.url), data=dict(_token=token)) return self.post("{}/main/daily-tasks-reward".format(self.url), data=dict(_token=self.token))
def post_delete_message(self, token: str, msg_id: list) -> Response: def _post_delete_message(self, msg_id: list) -> Response:
data = {"_token": token, "delete_message[]": msg_id} data = {"_token": self.token, "delete_message[]": msg_id}
return self.post("{}/main/messages-delete".format(self.url), data) return self.post("{}/main/messages-delete".format(self.url), data)
def post_eat(self, token: str, color: str) -> Response: def _post_eat(self, color: str) -> Response:
data = dict(_token=token, buttonColor=color) data = dict(_token=self.token, buttonColor=color)
return self.post("{}/main/eat".format(self.url), params=data) return self.post("{}/main/eat".format(self.url), params=data)
def post_economy_activate_house(self, token: str, quality: int) -> Response: def _post_economy_activate_house(self, quality: int) -> Response:
data = {"action": "activate", "quality": quality, "type": "house", "_token": token} data = {"action": "activate", "quality": quality, "type": "house", "_token": self.token}
return self.post("{}/economy/activateHouse".format(self.url), data=data) return self.post("{}/economy/activateHouse".format(self.url), data=data)
def post_economy_assign_to_holding(self, token: str, factory: int, holding: int) -> Response: def _post_economy_assign_to_holding(self, factory: int, holding: int) -> Response:
data = dict(_token=token, factoryId=factory, action="assign", holdingCompanyId=holding) data = dict(_token=self.token, factoryId=factory, action="assign", holdingCompanyId=holding)
return self.post("{}/economy/assign-to-holding".format(self.url), data=data) return self.post("{}/economy/assign-to-holding".format(self.url), data=data)
def post_economy_create_company(self, token: str, industry: int, building_type: int = 1) -> Response: def _post_economy_create_company(self, industry: int, building_type: int = 1) -> Response:
data = {"_token": token, "company[industry_id]": industry, "company[building_type]": building_type} data = {"_token": self.token, "company[industry_id]": industry, "company[building_type]": building_type}
return self.post("{}/economy/create-company".format(self.url), data=data, return self.post("{}/economy/create-company".format(self.url), data=data,
headers={"Referer": "{}/economy/create-company".format(self.url)}) headers={"Referer": "{}/economy/create-company".format(self.url)})
def post_economy_donate_items_action(self, token: str, citizen: int, amount: int, industry: int, def _post_economy_donate_items_action(self, citizen: int, amount: int, industry: int,
quality: int) -> Response: quality: int) -> Response:
data = dict(citizen_id=citizen, amount=amount, industry_id=industry, quality=quality, _token=token) data = dict(citizen_id=citizen, amount=amount, industry_id=industry, quality=quality, _token=self.token)
return self.post("{}/economy/donate-items-action".format(self.url), data=data, return self.post("{}/economy/donate-items-action".format(self.url), data=data,
headers={"Referer": "{}/economy/donate-items/{}".format(self.url, citizen)}) headers={"Referer": "{}/economy/donate-items/{}".format(self.url, citizen)})
def post_economy_donate_money_action(self, token: str, citizen: int, amount: float = 0.0, def _post_economy_donate_money_action(self, citizen: int, amount: float = 0.0,
currency: int = 62) -> Response: currency: int = 62) -> Response:
data = dict(citizen_id=citizen, _token=token, currency_id=currency, amount=amount) data = dict(citizen_id=citizen, _token=self.token, currency_id=currency, amount=amount)
return self.post("{}/economy/donate-money-action".format(self.url), data=data, return self.post("{}/economy/donate-money-action".format(self.url), data=data,
headers={"Referer": "{}/economy/donate-money/{}".format(self.url, citizen)}) headers={"Referer": "{}/economy/donate-money/{}".format(self.url, citizen)})
def post_economy_exchange_purchase(self, token: str, amount: float, currency: int, offer: int) -> Response: def _post_economy_exchange_purchase(self, amount: float, currency: int, offer: int) -> Response:
data = dict(_token=token, amount=amount, currencyId=currency, offerId=offer) data = dict(_token=self.token, amount=amount, currencyId=currency, offerId=offer)
return self.post("{}/economy/exchange/purchase/".format(self.url), data=data) return self.post("{}/economy/exchange/purchase/".format(self.url), data=data)
def post_economy_exchange_retrieve(self, token: str, personal: bool, page: int, currency: int) -> Response: def _post_economy_exchange_retrieve(self, personal: bool, page: int, currency: int) -> Response:
data = dict(_token=token, personalOffers=int(personal), page=page, currencyId=currency) data = dict(_token=self.token, personalOffers=int(personal), page=page, currencyId=currency)
return self.post("{}/economy/exchange/retrieve/".format(self.url), data=data) return self.post("{}/economy/exchange/retrieve/".format(self.url), data=data)
def post_economy_job_market_apply(self, token: str, citizen: int, salary: int) -> Response: def _post_economy_job_market_apply(self, citizen: int, salary: int) -> Response:
data = dict(_token=token, citizenId=citizen, salary=salary) data = dict(_token=self.token, citizenId=citizen, salary=salary)
return self.post("{}/economy/job-market-apply".format(self.url), data=data) return self.post("{}/economy/job-market-apply".format(self.url), data=data)
def post_economy_marketplace(self, token: str, country: int, industry: int, quality: int, def _post_economy_marketplace(self, country: int, industry: int, quality: int,
order_asc: bool = True) -> Response: order_asc: bool = True) -> Response:
data = dict(countryId=country, industryId=industry, quality=quality, ajaxMarket=1, data = dict(countryId=country, industryId=industry, quality=quality, ajaxMarket=1,
orderBy="price_asc" if order_asc else "price_desc", _token=token) orderBy="price_asc" if order_asc else "price_desc", _token=self.token)
return self.post("{}/economy/marketplaceAjax".format(self.url), data=data) return self.post("{}/economy/marketplaceAjax".format(self.url), data=data)
def post_economy_marketplace_actions(self, token: str, amount: int, buy: bool = False, **kwargs) -> Response: def _post_economy_marketplace_actions(self, amount: int, buy: bool = False, **kwargs) -> Response:
if buy: if buy:
data = dict(_token=token, offerId=kwargs['offer'], amount=amount, orderBy="price_asc", currentPage=1, data = dict(_token=self.token, offerId=kwargs['offer'], amount=amount, orderBy="price_asc", currentPage=1,
buyAction=1) buyAction=1)
else: else:
data = dict(_token=token, countryId=kwargs["country"], price=kwargs["price"], industryId=kwargs["industry"], data = dict(_token=self.token, countryId=kwargs["country"], price=kwargs["price"],
quality=kwargs["quality"], amount=amount, sellAction='postOffer') industryId=kwargs["industry"], quality=kwargs["quality"], amount=amount, sellAction='postOffer')
return self.post("{}/economy/marketplaceActions".format(self.url), data=data) return self.post("{}/economy/marketplaceActions".format(self.url), data=data)
def post_economy_resign(self, token: str) -> Response: def _post_economy_resign(self) -> Response:
return self.post("{}/economy/resign".format(self.url), return self.post("{}/economy/resign".format(self.url),
headers={"Content-Type": "application/x-www-form-urlencoded"}, headers={"Content-Type": "application/x-www-form-urlencoded"},
data={"_token": token, "action_type": "resign"}) data={"_token": self.token, "action_type": "resign"})
def post_economy_sell_company(self, token: str, factory: int, pin: int = None, sell: bool = True) -> Response: def _post_economy_sell_company(self, factory: int, pin: int = None, sell: bool = True) -> Response:
url = "{}/economy/sell-company/{}".format(self.url, factory) url = "{}/economy/sell-company/{}".format(self.url, factory)
data = dict(_token=token, pin="" if pin is None else pin) data = dict(_token=self.token, pin="" if pin is None else pin)
if sell: if sell:
data.update({"sell": "sell"}) data.update({"sell": "sell"})
else: else:
data.update({"dissolve": factory}) data.update({"dissolve": factory})
return self.post(url, data=data, headers={"Referer": url}) return self.post(url, data=data, headers={"Referer": url})
def post_economy_train(self, token: str, tg_ids: List[int]) -> Response: def _post_economy_train(self, tg_ids: List[int]) -> Response:
data: Dict[str, Union[int, str]] = {} data: Dict[str, Union[int, str]] = {}
if not tg_ids: if not tg_ids:
return self.get_training_grounds_json() return self._get_training_grounds_json()
else: else:
for idx, tg_id in enumerate(tg_ids): for idx, tg_id in enumerate(tg_ids):
data["grounds[%i][id]" % idx] = tg_id data["grounds[%i][id]" % idx] = tg_id
data["grounds[%i][train]" % idx] = 1 data["grounds[%i][train]" % idx] = 1
if data: if data:
data['_token'] = token data['_token'] = self.token
return self.post("{}/economy/train".format(self.url), data=data) return self.post("{}/economy/train".format(self.url), data=data)
def post_economy_upgrade_company(self, token: str, factory: int, level: int, pin: str = None) -> Response: def _post_economy_upgrade_company(self, factory: int, level: int, pin: str = None) -> Response:
data = dict(_token=token, type="upgrade", companyId=factory, level=level, pin="" if pin is None else pin) data = dict(_token=self.token, type="upgrade", companyId=factory, level=level, pin="" if pin is None else pin)
return self.post("{}/economy/upgrade-company".format(self.url), data=data) return self.post("{}/economy/upgrade-company".format(self.url), data=data)
def post_economy_work(self, token: str, action_type: str, wam: List[int] = None, employ: Dict[int, int] = None): def _post_economy_work(self, action_type: str, wam: List[int] = None, employ: Dict[int, int] = None) -> Response:
""" """
:return: requests.Response or None :return: requests.Response or None
""" """
@ -687,147 +702,159 @@ class CitizenAPI:
employ = dict() employ = dict()
if wam is None: if wam is None:
wam = [] wam = []
data: Dict[str, Union[int, str]] = dict(action_type=action_type, _token=token) data: Dict[str, Union[int, str]] = dict(action_type=action_type, _token=self.token)
if action_type == "work": if action_type == "production":
return self.post("{}/economy/work".format(self.url), data=data)
elif action_type == "production":
max_idx = 0 max_idx = 0
for idx, company_id in enumerate(sorted(wam or [])): for company_id in sorted(wam or []):
data.update({ data.update({
"companies[%i][id]" % idx: company_id, "companies[%i][id]" % max_idx: company_id,
"companies[%i][employee_works]" % idx: employ.pop(company_id, 0), "companies[%i][employee_works]" % max_idx: employ.pop(company_id, 0),
"companies[%i][own_work]" % idx: 1 "companies[%i][own_work]" % max_idx: 1
}) })
max_idx = idx + 1 max_idx += 1
for idx, company_id in enumerate(sorted(employ or [])): for company_id in sorted(employ or []):
idx_ = idx + max_idx
data.update({ data.update({
"companies[%i][id]" % idx_: company_id, "companies[%i][id]" % max_idx: company_id,
"companies[%i][employee_works]" % idx_: employ.pop(company_id), "companies[%i][employee_works]" % max_idx: employ.pop(company_id),
"companies[%i][own_work]" % idx_: 0 "companies[%i][own_work]" % max_idx: 0
}) })
max_idx += 1
return self.post("{}/economy/work".format(self.url), data=data) return self.post("{}/economy/work".format(self.url), data=data)
else:
return
def post_economy_work_overtime(self, token: str) -> Response: def _post_economy_work_overtime(self) -> Response:
data = dict(action_type="workOvertime", _token=token) data = dict(action_type="workOvertime", _token=self.token)
return self.post("{}/economy/workOvertime".format(self.url), data=data) return self.post("{}/economy/workOvertime".format(self.url), data=data)
def post_forgot_password(self, token: str, email: str) -> Response: def _post_forgot_password(self, email: str) -> Response:
data = dict(_token=token, email=email, commit="Reset password") data = dict(_token=self.token, email=email, commit="Reset password")
return self.post("{}/forgot-password".format(self.url), data=data) return self.post("{}/forgot-password".format(self.url), data=data)
def post_fight_activate_booster(self, token: str, battle: int, quality: int, duration: int, kind: str) -> Response: def _post_fight_activate_booster(self, battle: int, quality: int, duration: int, kind: str) -> Response:
data = dict(type=kind, quality=quality, duration=duration, battleId=battle, _token=token) data = dict(type=kind, quality=quality, duration=duration, battleId=battle, _token=self.token)
return self.post("{}/military/fight-activateBooster".format(self.url), data=data) return self.post("{}/military/fight-activateBooster".format(self.url), data=data)
def post_login(self, token: str, email: str, password: str) -> Response: def _post_login(self, email: str, password: str) -> Response:
data = dict(csrf_token=token, citizen_email=email, citizen_password=password, remember='on') data = dict(csrf_token=self.token, citizen_email=email, citizen_password=password, remember='on')
return self.post("{}/login".format(self.url), data=data) return self.post("{}/login".format(self.url), data=data)
def post_messages_alert(self, token: str, notification_ids: list) -> Response: def _post_messages_alert(self, notification_ids: list) -> Response:
data = {"_token": token, "delete_alerts[]": notification_ids, "deleteAllAlerts": "1", "delete": "Delete"} data = {"_token": self.token, "delete_alerts[]": notification_ids, "deleteAllAlerts": "1", "delete": "Delete"}
return self.post("{}/main/messages-alerts/1".format(self.url), data=data) return self.post("{}/main/messages-alerts/1".format(self.url), data=data)
def post_messages_compose(self, token: str, subject: str, body: str, citizens: List[int]) -> Response: def _post_messages_compose(self, subject: str, body: str, citizens: List[int]) -> Response:
url_pk = 0 if len(citizens) > 1 else str(citizens[0]) url_pk = 0 if len(citizens) > 1 else str(citizens[0])
data = dict(citizen_name=",".join([str(x) for x in citizens]), data = dict(citizen_name=",".join([str(x) for x in citizens]),
citizen_subject=subject, _token=token, citizen_message=body) citizen_subject=subject, _token=self.token, citizen_message=body)
return self.post("{}/main/messages-compose/{}}".format(self.url, url_pk), data=data) return self.post("{}/main/messages-compose/{}}".format(self.url, url_pk), data=data)
def post_military_battle_console(self, token: str, battle_id: int, round_id: int, division: int) -> Response: def _post_military_battle_console(self, battle_id: int, round_id: int, division: int) -> Response:
data = dict(battleId=battle_id, zoneId=round_id, action="battleStatistics", round=round_id, division=division, data = dict(battleId=battle_id, zoneId=round_id, action="battleStatistics", round=round_id, division=division,
type="damage", leftPage=1, rightPage=1, _token=token) type="damage", leftPage=1, rightPage=1, _token=self.token)
return self.post("{}/military/battle-console".format(self.url, battle_id), data=data) return self.post("{}/military/battle-console".format(self.url, battle_id), data=data)
def post_military_fight_air(self, token: str, battle_id: int, side_id: int) -> Response: def _post_military_fight_air(self, battle_id: int, side_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=token) data = dict(sideId=side_id, battleId=battle_id, _token=self.token)
return self.post("{}/military/fight-shoooot/{}".format(self.url, battle_id), data=data) return self.post("{}/military/fight-shoooot/{}".format(self.url, battle_id), data=data)
def post_military_fight_ground(self, token: str, battle_id: int, side_id: int) -> Response: def _post_military_fight_ground(self, battle_id: int, side_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=token) data = dict(sideId=side_id, battleId=battle_id, _token=self.token)
return self.post("{}/military/fight-shooot/{}".format(self.url, battle_id), data=data) return self.post("{}/military/fight-shooot/{}".format(self.url, battle_id), data=data)
def post_military_group_missions(self, token: str) -> Response: def _post_military_group_missions(self) -> Response:
data = dict(action="check", _token=token) data = dict(action="check", _token=self.token)
return self.post("{}/military/group-missions".format(self.url), data=data) return self.post("{}/military/group-missions".format(self.url), data=data)
def post_travel(self, token: str, check: str, **kwargs) -> Response: def _post_travel(self, check: str, **kwargs) -> Response:
data = dict(_token=token, check=check, **kwargs) data = dict(_token=self.token, check=check, **kwargs)
return self.post("{}/main/travel".format(self.url), data=data) return self.post("{}/main/travel".format(self.url), data=data)
def post_travel_data(self, token: str, **kwargs) -> Response: def _post_travel_data(self, **kwargs) -> Response:
return self.post("{}/main/travelData".format(self.url), data=dict(_token=token, **kwargs)) return self.post("{}/main/travelData".format(self.url), data=dict(_token=self.token, **kwargs))
def post_wars_attack_region(self, token: str, war: int, region: int) -> Response: def _post_wars_attack_region(self, war: int, region: int) -> Response:
data = dict(_token=token) data = dict(_token=self.token)
return self.post("{}/wars/attack-region/{}/{}".format(self.url, war, region), data=data) return self.post("{}/wars/attack-region/{}/{}".format(self.url, war, region), data=data)
def post_weekly_challenge_reward(self, token: str, reward_id: int) -> Response: def _post_weekly_challenge_reward(self, reward_id: int) -> Response:
data = dict(_token=token, rewardId=reward_id) data = dict(_token=self.token, rewardId=reward_id)
return self.post("{}/main/weekly-challenge-collect-reward".format(self.url), data=data) return self.post("{}/main/weekly-challenge-collect-reward".format(self.url), data=data)
def post_write_article(self, token: str, title: str, content: str, location: int, kind: int) -> Response: def _post_write_article(self, title: str, content: str, location: int, kind: int) -> Response:
data = dict(_token=token, article_name=title, article_body=content, article_location=location, data = dict(_token=self.token, article_name=title, article_body=content, article_location=location,
article_category=kind) article_category=kind)
return self.post("{}/main/write-article".format(self.url), data=data) return self.post("{}/main/write-article".format(self.url), data=data)
# Wall Posts # Wall Posts
# ## Country # ## Country
def post_country_comment_retrieve(self, token: str, post_id: int): def _post_country_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": token, "postId": post_id} data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/country-comment/retrieve/json".format(self.url), data=data) return self.post("{}/main/country-comment/retrieve/json".format(self.url), data=data)
def post_country_post_create(self, token: str, body: str, post_as: int): def _post_country_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": token, "post_message": body, "post_as": post_as} data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/country-comment/create/json".format(self.url), data=data)
def _post_country_post_create(self, body: str, post_as: int) -> Response:
data = {"_token": self.token, "post_message": body, "post_as": post_as}
return self.post("{}/main/country-post/create/json".format(self.url), data=data) return self.post("{}/main/country-post/create/json".format(self.url), data=data)
def post_country_post_retrieve(self, token: str): def _post_country_post_retrieve(self) -> Response:
data = {"_token": token, "page": 1, "switchedFrom": False} data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/country-post/retrieve/json".format(self.url), data=data) return self.post("{}/main/country-post/retrieve/json".format(self.url), data=data)
# ## Military Unit # ## Military Unit
def post_military_unit_comment_retrieve(self, token: str, post_id: int): def _post_military_unit_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": token, "postId": post_id} data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/military-unit-comment/retrieve/json".format(self.url), data=data) return self.post("{}/main/military-unit-comment/retrieve/json".format(self.url), data=data)
def post_military_unit_post_create(self, token: str, body: str, post_as: int): def _post_military_unit_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": token, "post_message": body, "post_as": post_as} data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/military-unit-comment/create/json".format(self.url), data=data)
def _post_military_unit_post_create(self, body: str, post_as: int) -> Response:
data = {"_token": self.token, "post_message": body, "post_as": post_as}
return self.post("{}/main/military-unit-post/create/json".format(self.url), data=data) return self.post("{}/main/military-unit-post/create/json".format(self.url), data=data)
def post_military_unit_post_retrieve(self, token: str): def _post_military_unit_post_retrieve(self) -> Response:
data = {"_token": token, "page": 1, "switchedFrom": False} data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/military-unit-post/retrieve/json".format(self.url), data=data) return self.post("{}/main/military-unit-post/retrieve/json".format(self.url), data=data)
# ## Party # ## Party
def post_party_comment_retrieve(self, token: str, post_id: int): def _post_party_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": token, "postId": post_id} data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/party-comment/retrieve/json".format(self.url), data=data) return self.post("{}/main/party-comment/retrieve/json".format(self.url), data=data)
def post_party_post_create(self, token: str, body: str): def _post_party_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": token, "post_message": body} data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/party-comment/create/json".format(self.url), data=data)
def _post_party_post_create(self, body: str) -> Response:
data = {"_token": self.token, "post_message": body}
return self.post("{}/main/party-post/create/json".format(self.url), data=data) return self.post("{}/main/party-post/create/json".format(self.url), data=data)
def post_party_post_retrieve(self, token: str): def _post_party_post_retrieve(self) -> Response:
data = {"_token": token, "page": 1, "switchedFrom": False} data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/party-post/retrieve/json".format(self.url), data=data) return self.post("{}/main/party-post/retrieve/json".format(self.url), data=data)
# ## Friend's Wall # ## Friend's Wall
def post_wall_comment_retrieve(self, token: str, post_id: int): def _post_wall_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": token, "postId": post_id} data = {"_token": self.token, "postId": post_id}
return self.post("{}/main/wall-comment/retrieve/json".format(self.url), data=data) return self.post("{}/main/wall-comment/retrieve/json".format(self.url), data=data)
def post_wall_post_create(self, token: str, body: str): def _post_wall_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": token, "post_message": body} data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/wall-comment/create/json".format(self.url), data=data)
def _post_wall_post_create(self, body: str) -> Response:
data = {"_token": self.token, "post_message": body}
return self.post("{}/main/wall-post/create/json".format(self.url), data=data) return self.post("{}/main/wall-post/create/json".format(self.url), data=data)
def post_wall_post_retrieve(self, token: str): def _post_wall_post_retrieve(self) -> Response:
data = {"_token": token, "page": 1, "switchedFrom": False} data = {"_token": self.token, "page": 1, "switchedFrom": False}
return self.post("{}/main/wall-post/retrieve/json".format(self.url), data=data) return self.post("{}/main/wall-post/retrieve/json".format(self.url), data=data)
@ -921,7 +948,7 @@ class MyJSONEncoder(JSONEncoder):
return dict(__type__='timedelta', days=o.days, seconds=o.seconds, return dict(__type__='timedelta', days=o.days, seconds=o.seconds,
microseconds=o.microseconds, total_seconds=o.total_seconds()) microseconds=o.microseconds, total_seconds=o.total_seconds())
elif isinstance(o, Response): elif isinstance(o, Response):
return dict(_content=o._content.decode("UTF-8"), headers=o.headers.__dict__, url=o.url, text=o.text) return dict(headers=o.headers.__dict__, url=o.url, text=o.text)
elif hasattr(o, '__dict__'): elif hasattr(o, '__dict__'):
return o.__dict__ return o.__dict__
elif isinstance(o, deque): elif isinstance(o, deque):
@ -998,21 +1025,24 @@ class Battle(object):
else: else:
end = datetime.datetime.max end = datetime.datetime.max
self.div.update({div: BattleDivision(end, data.get('epic_type') in [1, 5], battle_div = BattleDivision(
data.get('dom_pts').get("inv"), data.get('dom_pts').get("def"), end=end, epic=data.get('epic_type') in [1, 5],
data.get('wall').get("for"), data.get('wall').get("dom"))}) inv_pts=data.get('dom_pts').get("inv"), def_pts=data.get('dom_pts').get("def"),
wall_for=data.get('wall').get("for"), wall_dom=data.get('wall').get("dom")
)
self.div.update({div: battle_div})
def __repr__(self): def __repr__(self):
now = utils.now() now = utils.now()
is_started = self.start < utils.now() is_started = self.start < utils.now()
if is_started: if is_started:
timepart = "{}".format(now - self.start) time_part = "{}".format(now - self.start)
else: else:
timepart = "- {}".format(self.start - now) time_part = "- {}".format(self.start - now)
return "Battle {} | {:>21.21}:{:<21.21} | Round {:2} | Start {}".format(self.id, return "Battle {} | {:>21.21}:{:<21.21} | Round {:2} | Start {}".format(
utils.COUNTRIES[self.invader.id], self.id, utils.COUNTRIES[self.invader.id], utils.COUNTRIES[self.defender.id], self.zone_id, time_part
utils.COUNTRIES[self.defender.id], )
self.zone_id, timepart)
class EnergyToFight: class EnergyToFight:

View File

@ -6,6 +6,7 @@ import re
import sys import sys
import time import time
import traceback import traceback
import unicodedata
from collections import deque from collections import deque
from decimal import Decimal from decimal import Decimal
from json import JSONEncoder from json import JSONEncoder
@ -15,7 +16,6 @@ from typing import Union
import pytz import pytz
import requests import requests
from requests import Response from requests import Response
from slugify import slugify
__all__ = ["FOOD_ENERGY", "COMMIT_ID", "COUNTRIES", "erep_tz", __all__ = ["FOOD_ENERGY", "COMMIT_ID", "COUNTRIES", "erep_tz",
@ -214,7 +214,7 @@ def write_file(filename: str, content: str) -> int:
def write_request(response: requests.Response, is_error: bool = False): def write_request(response: requests.Response, is_error: bool = False):
from erepublik_script import Citizen from erepublik import Citizen
# Remove GET args from url name # Remove GET args from url name
url = response.url url = response.url
last_index = url.index("?") if "?" in url else len(response.url) last_index = url.index("?") if "?" in url else len(response.url)
@ -237,8 +237,8 @@ def write_request(response: requests.Response, is_error: bool = False):
"mimetype": "application/json" if ext == "json" else "text/html"} "mimetype": "application/json" if ext == "json" else "text/html"}
def send_email(name, content: list, player=None, local_vars=dict, promo: bool = False, captcha: bool = False): def send_email(name: str, content: list, player=None, local_vars=dict, promo: bool = False, captcha: bool = False):
from erepublik_script import Citizen from erepublik import Citizen
file_content_template = "<html><head><title>{title}</title></head><body>{body}</body></html>" file_content_template = "<html><head><title>{title}</title></head><body>{body}</body></html>"
if isinstance(player, Citizen): if isinstance(player, Citizen):
@ -284,156 +284,6 @@ def send_email(name, content: list, player=None, local_vars=dict, promo: bool =
requests.post('https://pasts.72.lv', data=data, files=files) requests.post('https://pasts.72.lv', data=data, files=files)
def parse_input(msg: str) -> bool:
msg += " (y|n):"
data = None
while data not in ['', 'y', 'Y', 'n', 'N']:
try:
data = input(msg)
except EOFError:
data = 'n'
return data in ['', 'y', 'Y']
def parse_config(config=None) -> dict:
if config is None:
config = {}
if not config.get('email'):
config['email'] = input("Player email: ")
if not config.get('password'):
config['password'] = input("Player password: ")
if 'wt' in config:
config['work'] = config['wt']
config['train'] = config['wt']
if 'work' not in config:
config['work'] = parse_input('Should I work')
if 'train' not in config:
config['train'] = parse_input('Should I train')
if 'ot' not in config:
config['ot'] = parse_input('Should I work overtime')
if 'wam' not in config:
config['wam'] = parse_input('Should I WAM')
if 'employ' not in config:
config['employ'] = parse_input('Should I employ employees')
if config['wam'] or config['employ']:
if "autosell" in config:
config.pop("autosell")
if "autosell_raw" in config:
config.pop("autosell_raw")
if "autosell_final" in config:
config.pop("autosell_final")
if 'auto_sell' not in config or not isinstance(config['auto_sell'], list):
if parse_input('Should I auto sell produced products'):
config['auto_sell'] = []
if parse_input("Should I auto sell Food products"):
if parse_input("Should I auto sell Food products"):
config['auto_sell'].append("food")
if parse_input("Should I auto sell Weapon products"):
config['auto_sell'].append("weapon")
if parse_input("Should I auto sell House products"):
config['auto_sell'].append("house")
if parse_input("Should I auto sell Aircraft products"):
config['auto_sell'].append("airplane")
if parse_input("Should I auto sell raw products"):
if parse_input("Should I auto sell Food raw"):
config['auto_sell'].append("foodRaw")
if parse_input("Should I auto sell Weapon raw"):
config['auto_sell'].append("weaponRaw")
if parse_input("Should I auto sell House raw"):
config['auto_sell'].append("houseRaw")
if parse_input("Should I auto sell Airplane raw"):
config['auto_sell'].append("airplaneRaw")
if config['auto_sell']:
if 'auto_sell_all' not in config:
print("When selling produced items should I also sell items already in inventory?")
config['auto_sell_all'] = parse_input('Y - sell all, N - only just produced')
else:
config['auto_sell_all'] = False
if 'auto_buy_raw' not in config:
config['auto_buy_raw'] = parse_input('Should I auto buy raw deficit at WAM or employ')
else:
config['auto_sell'] = []
config['auto_sell_all'] = False
config['auto_buy_raw'] = False
if 'fight' not in config:
config['fight'] = parse_input('Should I fight')
if config.get('fight'):
if 'air' not in config:
config['air'] = parse_input('Should I fight in AIR')
if 'ground' not in config:
config['ground'] = parse_input('Should I fight in GROUND')
if 'all_in' not in config:
print("When full energy should I go all in")
config['all_in'] = parse_input('Y - all in, N - 1h worth of energy')
if 'next_energy' not in config:
config['next_energy'] = parse_input('Should I fight when next pp +1 energy available')
if 'boosters' not in config:
config['boosters'] = parse_input('Should I use +50% dmg boosters')
if 'travel_to_fight' not in config:
config['travel_to_fight'] = parse_input('Should I travel to fight')
if 'epic_hunt' not in config:
config['epic_hunt'] = parse_input('Should I check for epic battles')
if not config['epic_hunt']:
config['epic_hunt_ebs'] = False
if not config['epic_hunt']:
config['epic_hunt_ebs'] = False
elif 'epic_hunt_ebs' not in config:
config['epic_hunt_ebs'] = parse_input('Should I eat EBs when fighting in epic battle')
if 'rw_def_side' not in config:
config['rw_def_side'] = parse_input('Should I fight on defenders side in RWs')
if 'continuous_fighting' not in config:
config['continuous_fighting'] = parse_input('If already fought in any battle, \n'
'should I continue to fight all FF in that battle')
else:
config['air'] = False
config['ground'] = False
config['all_in'] = False
config['next_energy'] = False
config['boosters'] = False
config['travel_to_fight'] = False
config['epic_hunt'] = False
config['epic_hunt_ebs'] = False
config['rw_def_side'] = False
config['continuous_fighting'] = False
if 'debug' not in config:
config['debug'] = parse_input('Should I generate debug files')
if 'random_sleep' not in config:
config['random_sleep'] = parse_input('Should I add random amount (0-120sec) to sleep time')
if 'gold_buy' not in config:
config['gold_buy'] = parse_input('Should I auto buy 10g every day')
if 'interactive' not in config:
config['interactive'] = parse_input('Should I print output to console?')
return config
def normalize_html_json(js: str) -> str: def normalize_html_json(js: str) -> str:
js = re.sub(r' \'(.*?)\'', lambda a: '"%s"' % a.group(1), js) js = re.sub(r' \'(.*?)\'', lambda a: '"%s"' % a.group(1), js)
js = re.sub(r'(\d\d):(\d\d):(\d\d)', r'\1\2\3', js) js = re.sub(r'(\d\d):(\d\d):(\d\d)', r'\1\2\3', js)
@ -446,7 +296,6 @@ def process_error(log_info: str, name: str, exc_info: tuple, citizen=None, commi
interactive: bool = False): interactive: bool = False):
""" """
Process error logging and email sending to developer Process error logging and email sending to developer
:param error:
:param interactive: Should print interactively :param interactive: Should print interactively
:param log_info: String to be written in output :param log_info: String to be written in output
:param name: String Instance name :param name: String Instance name
@ -462,4 +311,25 @@ def process_error(log_info: str, name: str, exc_info: tuple, citizen=None, commi
write_interactive_log(log_info) write_interactive_log(log_info)
else: else:
write_silent_log(log_info) write_silent_log(log_info)
send_email(name, bugtrace, citizen, local_vars=inspect.trace()[-1][0].f_locals) trace = inspect.trace()
if trace:
trace = trace[-1][0].f_locals
else:
trace = dict()
send_email(name, bugtrace, citizen, local_vars=trace)
def slugify(value, allow_unicode=False):
"""
Function copied from Django2.2.1 django.utils.text.slugify
Convert to ASCII if 'allow_unicode' is False. Convert spaces to hyphens.
Remove characters that aren't alphanumerics, underscores, or hyphens.
Convert to lowercase. Also strip leading and trailing whitespace.
"""
value = str(value)
if allow_unicode:
value = unicodedata.normalize('NFKC', value)
else:
value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore').decode('ascii')
value = re.sub(r'[^\w\s-]', '', value).strip().lower()
return re.sub(r'[-\s]+', '-', value)

View File

@ -1,12 +0,0 @@
# -*- coding: utf-8 -*-
"""Top-level package for eRepublik script."""
__author__ = """Eriks Karls"""
__email__ = 'eriks@72.lv'
__version__ = '0.14.3'
__all__ = ["Citizen"]
from erepublik_script import classes, utils
from erepublik_script.citizen import Citizen

View File

@ -1,6 +1,6 @@
pip==19.1.1 pip==19.1.1
bumpversion==0.5.3 bumpversion==0.5.3
wheel==0.32.1 wheel==0.33.4
watchdog==0.9.0 watchdog==0.9.0
flake8==3.7.8 flake8==3.7.8
tox==3.13.2 tox==3.13.2

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 0.14.3 current_version = 0.15.0
commit = True commit = True
tag = True tag = True
@ -7,7 +7,7 @@ tag = True
search = version='{current_version}' search = version='{current_version}'
replace = version='{new_version}' replace = version='{new_version}'
[bumpversion:file:erepublik_script/__init__.py] [bumpversion:file:erepublik/__init__.py]
search = __version__ = '{current_version}' search = __version__ = '{current_version}'
replace = __version__ = '{new_version}' replace = __version__ = '{new_version}'
@ -17,7 +17,7 @@ universal = 1
[flake8] [flake8]
exclude = docs exclude = docs
max-line-length = 120 max-line-length = 120
ignore = E722 ignore = E722 F401
[aliases] [aliases]

View File

@ -11,7 +11,7 @@ with open('README.rst') as readme_file:
with open('HISTORY.rst') as history_file: with open('HISTORY.rst') as history_file:
history = history_file.read() history = history_file.read()
requirements = ['pytz==2019.1', 'requests==2.22.0', 'python-slugify<3.0.0'] requirements = ['pytz==2019.1', 'requests==2.22.0']
setup_requirements = [ ] setup_requirements = [ ]
@ -21,26 +21,27 @@ setup(
author="Eriks Karls", author="Eriks Karls",
author_email='eriks@72.lv', author_email='eriks@72.lv',
classifiers=[ classifiers=[
'Development Status :: 2 - Pre-Alpha', 'Development Status :: 4 - Beta',
'Intended Audience :: Developers', 'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License', 'License :: OSI Approved :: MIT License',
'Natural Language :: English', 'Natural Language :: English',
'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.7',
], ],
description="Python package for eRepublik automated playing", description="Python package for automated eRepublik playing",
entry_points={}, entry_points={},
install_requires=requirements, install_requires=requirements,
license="MIT license", license="MIT license",
long_description=readme + '\n\n' + history, long_description=readme + '\n\n' + history,
include_package_data=True, include_package_data=True,
keywords='erepublik_script', keywords='erepublik',
name='erepublik_script', name='eRepublik',
packages=find_packages(include=['erepublik_script']), packages=find_packages(include=['erepublik']),
python_requires='>=3.7.*, <4',
setup_requires=setup_requirements, setup_requires=setup_requirements,
test_suite='tests', test_suite='tests',
tests_require=test_requirements, tests_require=test_requirements,
url='https://github.com/eeriks/erepublik_script', url='https://github.com/eeriks/erepublik_script',
version='0.14.3', version='0.15.0',
zip_safe=False, zip_safe=False,
) )

View File

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Unit test package for erepublik_script.""" """Unit test package for erepublik."""

View File

@ -1,18 +1,18 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Tests for `erepublik_script` package.""" """Tests for `erepublik` package."""
import unittest import unittest
from click.testing import CliRunner from click.testing import CliRunner
from erepublik_script import Citizen from erepublik import Citizen
from erepublik_script import cli from erepublik import cli
class TestErepublik_script(unittest.TestCase): class TestErepublik_script(unittest.TestCase):
"""Tests for `erepublik_script` package.""" """Tests for `erepublik` package."""
def setUp(self): def setUp(self):
"""Set up test fixtures, if any.""" """Set up test fixtures, if any."""
@ -28,7 +28,7 @@ class TestErepublik_script(unittest.TestCase):
runner = CliRunner() runner = CliRunner()
result = runner.invoke(cli.main) result = runner.invoke(cli.main)
assert result.exit_code == 0 assert result.exit_code == 0
assert 'erepublik_script.cli.main' in result.output assert 'erepublik.cli.main' in result.output
help_result = runner.invoke(cli.main, ['--help']) help_result = runner.invoke(cli.main, ['--help'])
assert help_result.exit_code == 0 assert help_result.exit_code == 0
assert '--help Show this message and exit.' in help_result.output assert '--help Show this message and exit.' in help_result.output