Compare commits

...

18 Commits

Author SHA1 Message Date
e14cbc18e9 Bump version: 0.15.1 → 0.15.2 2019-08-01 17:24:07 +03:00
048ce798dd All battle div div containing dicts where reference to the same object 2019-08-01 17:23:24 +03:00
e5b7cde044 Bump version: 0.15.0 → 0.15.1 2019-08-01 15:06:34 +03:00
6bbc7a1f64 Typehinting and battle/war stuff - last battle, attackable regions if CP, etc 2019-08-01 15:05:44 +03:00
4eccb339bb Deploy bombs 2019-08-01 15:04:16 +03:00
dbeb6e9ba5 Market scraper updates 2019-08-01 09:37:26 +03:00
9c9bb5ae40 Region attacking post updated 2019-08-01 09:37:08 +03:00
d8eb69f82a Travel bugfix and market scraper fixup 2019-07-31 22:39:54 +03:00
42c430213f Minor updates 2019-07-31 21:41:24 +03:00
39dbcaa27d Continuing work on return Response free Citizen class 2019-07-31 21:41:08 +03:00
8911adb81c Traveling improved for Citizen class 2019-07-31 21:38:34 +03:00
7927c162f8 More precise type hint 2019-07-31 21:37:29 +03:00
92b7c45a7d Report promos to erep.lv 2019-07-31 21:36:57 +03:00
53257487d8 Write on country wall update 2019-07-30 18:32:12 +03:00
8690c4d3f2 minor fix 2019-07-30 11:10:35 +03:00
43c6bce160 minor fix 2019-07-30 11:10:09 +03:00
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
8 changed files with 496 additions and 343 deletions

View File

@ -2,13 +2,20 @@
History History
======= =======
0.1.0 (2019-07-19)
------------------
* First release on PyPI. 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) 0.14.4 (2019-07-23)
------------------- -------------------
* Wall post comment endpoints updated with comment create endpoints * Wall post comment endpoints updated with comment create endpoints.
0.1.0 (2019-07-19)
------------------
* First release on PyPI.

View File

@ -6,8 +6,8 @@ eRepublik script
.. image:: https://img.shields.io/pypi/v/erepublik.svg .. image:: https://img.shields.io/pypi/v/erepublik.svg
:target: https://pypi.python.org/pypi/erepublik :target: https://pypi.python.org/pypi/erepublik
.. image:: https://readthedocs.org/projects/erepublik/badge/?version=latest .. image:: https://readthedocs.org/projects/erepublik_script/badge/?version=latest
:target: https://erepublik.readthedocs.io/en/latest/?badge=latest :target: https://erepublik_script.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status :alt: Documentation Status

View File

@ -4,7 +4,7 @@
__author__ = """Eriks Karls""" __author__ = """Eriks Karls"""
__email__ = 'eriks@72.lv' __email__ = 'eriks@72.lv'
__version__ = '__version__ = '0.14.7'' __version__ = '0.15.2'
from erepublik import classes, utils from erepublik import classes, utils
from erepublik.citizen import Citizen from erepublik.citizen import Citizen

View File

@ -1,4 +1,5 @@
import datetime import datetime
import itertools
import re import re
import sys import sys
import threading import threading
@ -17,12 +18,12 @@ class Citizen(classes.CitizenAPI):
division = 0 division = 0
all_battles: Dict[int, classes.Battle] = dict() all_battles: Dict[int, classes.Battle] = None
countries: Dict[int, Dict[str, Union[str, List[int]]]] = dict() countries: Dict[int, Dict[str, Union[str, List[int]]]] = None
__last_war_update_data = {} __last_war_update_data = None
__last_full_update: datetime.datetime __last_full_update: datetime.datetime = utils.now().min
active_fs = False active_fs: bool = False
food = {"q1": 0, "q2": 0, "q3": 0, "q4": 0, "q5": 0, "q6": 0, "q7": 0, "total": 0} food = {"q1": 0, "q2": 0, "q3": 0, "q4": 0, "q5": 0, "q6": 0, "q7": 0, "total": 0}
inventory = {"used": 0, "total": 0} inventory = {"used": 0, "total": 0}
@ -43,8 +44,8 @@ class Citizen(classes.CitizenAPI):
work_units = 0 work_units = 0
ot_points = 0 ot_points = 0
tg_contract = {} tg_contract = None
promos = {} promos = None
eday = 0 eday = 0
@ -136,7 +137,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.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):
@ -288,11 +289,11 @@ 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))
self.promos = {k: v for k, v in self.promos.items() if v > self.now} self.promos = {k: v for k, v in (self.promos.items() if self.promos else {}) if v > self.now}
send_mail = False send_mail = False
for promo in promos: for promo in promos:
promo_name = promo.get("id") promo_name = promo.get("id")
@ -311,7 +312,10 @@ class Citizen(classes.CitizenAPI):
self.details.gold, self.details.cc self.details.gold, self.details.cc
)) ))
if send_mail: if send_mail:
active_promos = ["{} active until {}".format(k, v.strftime("%F %T")) for k, v in self.promos.items()] active_promos = []
for kind, time_until in self.promos.items():
active_promos.append(f"{kind} active until {time_until}")
utils.report_promo(kind, time_until)
utils.send_email(self.name, active_promos, player=self, promo=True) utils.send_email(self.name, active_promos, player=self, promo=True)
new_date = re.search(r"var new_date = '(\d*)';", html) new_date = re.search(r"var new_date = '(\d*)';", html)
@ -356,25 +360,26 @@ class Citizen(classes.CitizenAPI):
self.politics.is_party_president = bool(party.get('is_party_president')) self.politics.is_party_president = bool(party.get('is_party_president'))
self.politics.party_slug = "{}-{}".format(party.get("stripped_title"), party.get('party_id')) self.politics.party_slug = "{}-{}".format(party.get("stripped_title"), party.get('party_id'))
def update_money(self, page: int = 0, currency: int = 62) -> Response: def update_money(self, page: int = 0, currency: int = 62) -> Dict[str, Any]:
""" """
Gets monetary market offers to get exact amount of CC and Gold available Gets monetary market offers to get exact amount of CC and Gold available
""" """
if currency not in [1, 62]: if currency not in [1, 62]:
currency = 62 currency = 62
resp = self.post_economy_exchange_retrieve(False, page, currency) resp = self._post_economy_exchange_retrieve(False, page, currency)
self.details.cc = float(resp.json().get("ecash").get("value")) resp_data = resp.json()
self.details.gold = float(resp.json().get("gold").get("value")) self.details.cc = float(resp_data.get("ecash").get("value"))
return resp self.details.gold = float(resp_data.get("gold").get("value"))
return resp_data
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))
@ -386,7 +391,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")})
@ -418,7 +423,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", {}):
@ -426,20 +431,21 @@ class Citizen(classes.CitizenAPI):
if status == "rewarded": if status == "rewarded":
continue continue
elif status == "completed": elif status == "completed":
self.post_weekly_challenge_reward(reward.get("id", 0)) self._post_weekly_challenge_reward(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", ""))
if pps: if pps:
self.details.next_pp.append(int(pps.group(1))) self.details.next_pp.append(int(pps.group(1)))
def update_war_info(self) -> Dict[Any, Any]: def update_war_info(self):
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"):
self.all_battles = {}
self.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:
self.countries.update({ self.countries.update({
@ -451,7 +457,6 @@ class Citizen(classes.CitizenAPI):
if resp_json.get("battles"): if resp_json.get("battles"):
for battle_id, battle_data in resp_json.get("battles", {}).items(): for battle_id, battle_data in resp_json.get("battles", {}).items():
self.all_battles.update({int(battle_id): classes.Battle(battle_data)}) self.all_battles.update({int(battle_id): classes.Battle(battle_data)})
return self.__last_war_update_data
def eat(self): def eat(self):
""" """
@ -486,7 +491,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(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(
@ -538,8 +543,15 @@ class Citizen(classes.CitizenAPI):
def_allies = battle.defender.deployed + [battle.defender.id] def_allies = battle.defender.deployed + [battle.defender.id]
all_allies = inv_allies + def_allies all_allies = inv_allies + def_allies
if self.details.current_country not in all_allies: if self.details.current_country not in all_allies:
self._travel(battle.defender.id, self.get_country_travel_region(battle.defender.id)) if self.details.current_country in battle.invader.allies:
side = battle.defender.id allies = battle.invader.deployed
side = battle.invader.id
else:
allies = battle.defender.deployed
side = battle.defender.id
self.travel_to_battle(battle.id, allies)
else: else:
if self.details.current_country in inv_allies: if self.details.current_country in inv_allies:
side = battle.invader.id side = battle.invader.id
@ -567,7 +579,6 @@ class Citizen(classes.CitizenAPI):
self.active_fs = active_fs self.active_fs = active_fs
def sorted_battles(self, sort_by_time: bool = False) -> List[int]: def sorted_battles(self, sort_by_time: bool = False) -> List[int]:
r = self.update_war_info()
cs_battles_air: List[int] = [] cs_battles_air: List[int] = []
cs_battles_ground: List[int] = [] cs_battles_ground: List[int] = []
deployed_battles_air: List[int] = [] deployed_battles_air: List[int] = []
@ -614,17 +625,19 @@ class Citizen(classes.CitizenAPI):
other_battles_air.append(battle.id) other_battles_air.append(battle.id)
ret_battles = [] ret_battles = []
if r.get("citizen_contribution"): if self.__last_war_update_data.get("citizen_contribution"):
battle_id = r.get("citizen_contribution")[0].get("battle_id", 0) battle_id = self.__last_war_update_data.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 + deployed_battles_air + deployed_battles_ground + \ ret_battles += (cs_battles_air + cs_battles_ground +
ally_battles_air + ally_battles_ground + other_battles_air + other_battles_ground deployed_battles_air + deployed_battles_ground +
ally_battles_air + ally_battles_ground +
other_battles_air + other_battles_ground)
return ret_battles return ret_battles
@property @property
def has_battle_contribution(self): def has_battle_contribution(self):
return bool(self.update_war_info().get("citizen_contribution", [])) return bool(self.__last_war_update_data.get("citizen_contribution", []))
def find_battle_and_fight(self): def find_battle_and_fight(self):
if self.should_fight(False): if self.should_fight(False):
@ -672,14 +685,16 @@ class Citizen(classes.CitizenAPI):
if travel_needed: if travel_needed:
if battle.is_rw: if battle.is_rw:
self._travel(battle.defender.id, self.get_country_travel_region(battle.defender.id)) country_ids_to_travel = [battle.defender.id]
elif self.details.current_country not in battle.invader.allies: elif self.details.current_country in battle.invader.allies:
self.travel(battle_id=battle.id) country_ids_to_travel = battle.invader.deployed + [battle.invader.id]
side_id = battle.invader.id side_id = battle.invader.id
else: else:
self._travel(battle.defender.id, self.get_country_travel_region(battle.defender.id)) country_ids_to_travel = battle.defender.deployed + [battle.defender.id]
side_id = battle.defender.id side_id = battle.defender.id
if not self.travel_to_battle(battle_id, country_ids_to_travel):
break
self.fight(battle_id, side_id, battle.is_air) self.fight(battle_id, side_id, battle.is_air)
self.travel_to_residence() self.travel_to_residence()
self.collect_weekly_reward() self.collect_weekly_reward()
@ -715,9 +730,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(data['battleId'], data['sideId']) response = self._post_military_fight_air(data['battleId'], data['sideId'])
else: else:
response = self.post_military_fight_ground(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)
@ -745,11 +760,15 @@ class Citizen(classes.CitizenAPI):
return hits, err, damage return hits, err, damage
def deploy_bomb(self, battle_id: int, bomb_id: int):
r = self._post_military_deploy_bomb(battle_id, bomb_id).json()
return not r.get('error')
def work_ot(self): def work_ot(self):
# 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() 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()
@ -767,7 +786,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("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:
@ -786,10 +805,10 @@ 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 = {"free_train": tg_json["hasFreeTrain"]}
if tg_json["contracts"]: if tg_json["contracts"]:
self.tg_contract.update(**tg_json["contracts"][0]) self.tg_contract.update(**tg_json["contracts"][0])
@ -799,7 +818,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(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()
@ -900,8 +919,9 @@ class Citizen(classes.CitizenAPI):
if wam_list: if wam_list:
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']) if not self.travel_to_region(wam_holding['region_id']):
response = self.post_economy_work("production", wam=wam_list, employ=employee_companies).json() return False
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:
@ -927,7 +947,7 @@ class Citizen(classes.CitizenAPI):
amount = amount_remaining amount = amount_remaining
best_offer = self.get_market_offers(self.details.citizenship, industry, 1) best_offer = self.get_market_offers(self.details.citizenship, industry, 1)
amount = best_offer['amount'] if amount >= best_offer['amount'] else amount amount = best_offer['amount'] if amount >= best_offer['amount'] else amount
rj = self.buy_from_market(amount=best_offer['amount'], offer=best_offer['offer_id']).json() rj = self.buy_from_market(amount=best_offer['amount'], offer=best_offer['offer_id'])
if not rj.get('error'): if not rj.get('error'):
amount_remaining -= amount amount_remaining -= amount
else: else:
@ -963,15 +983,8 @@ class Citizen(classes.CitizenAPI):
self.post_market_offer(industry=self.available_industries[kind], amount=int(amount), self.post_market_offer(industry=self.available_industries[kind], amount=int(amount),
quality=int(quality), price=price) quality=int(quality), price=price)
def travel_to_residence(self):
self.update_citizen_info()
res_r = self.details.residence_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)
def get_country_travel_region(self, country_id: int) -> int: def get_country_travel_region(self, country_id: int) -> int:
r = self.get_travel_regions(country_id=country_id).json() regions = self.get_travel_regions(country_id=country_id)
regions = r.get("regions")
regs = [] regs = []
if regions: if regions:
for region in regions.values(): for region in regions.values():
@ -982,50 +995,112 @@ class Citizen(classes.CitizenAPI):
else: else:
return 0 return 0
def travel(self, holding_id=0, battle_id=0, region_id=0): def _update_citizen_location(self, country_id: int, region_id: int):
r = self.get_travel_regions(holding_id, battle_id, region_id) self.details.current_region = region_id
regions = r.json()["regions"] self.details.current_country = country_id
closest_region = 99999
country_id = int(r.json()["preselectCountryId"]) def travel_to_residence(self) -> bool:
region_id = int(r.json()["preselectRegionId"]) self.update_citizen_info()
if not any((region_id, country_id)): res_r = self.details.residence_region
for rid, info in regions.items(): if self.details.residence_country and res_r and not res_r == self.details.current_region:
if info.get("distanceInKm", 99999) < closest_region: r = self._travel(self.details.residence_country, self.details.residence_region)
closest_region = info.get("distanceInKm") if r.json().get('message', '') == 'success':
country_id = info.get("countryId") self._update_citizen_location(self.details.residence_country, self.details.current_region)
region_id = rid return True
self._travel(country_id, region_id) return False
return True
def travel_to_region(self, region_id: int) -> bool:
data = self._post_travel_data(region_id=region_id).json()
if data.get('alreadyInRegion'):
return True
else:
r = self._travel(data.get('preselectCountryId'), region_id).json()
if r.get('message', '') == 'success':
self._update_citizen_location(data.get('preselectCountryId'), region_id)
return True
return False
def travel_to_country(self, country_id: int) -> bool:
data = self._post_travel_data(countryId=country_id, check="getCountryRegions").json()
regs = []
if data.get('regions'):
for region in data.get('regions').values():
if region['countryId'] == country_id: # Is not occupied by other country
regs.append((region['id'], region['distanceInKm']))
if regs:
region_id = min(regs, key=lambda _: int(_[1]))[0]
r = self._travel(country_id, region_id).json()
if r.get('message', '') == 'success':
self._update_citizen_location(country_id, region_id)
return True
return False
def travel_to_holding(self, holding_id: int) -> bool:
data = self._post_travel_data(holdingId=holding_id).json()
if data.get('alreadyInRegion'):
return True
else:
r = self._travel(data.get('preselectCountryId'), data.get('preselectRegionId')).json()
if r.get('message', '') == 'success':
self._update_citizen_location(data.get('preselectCountryId'), data.get('preselectRegionId'))
return True
return False
def travel_to_battle(self, battle_id: int, *allowed_countries: List[int]) -> bool:
data = self.get_travel_regions(battle_id=battle_id)
regs = []
if data:
for region in data.values():
if region['countryId'] in allowed_countries: # Is not occupied by other country
regs.append((region['distanceInKm'], region['id'], region['countryId']))
if regs:
reg = min(regs, key=lambda _: int(_[0]))
region_id = reg[1]
country_id = reg[2]
r = self._travel(country_id, region_id).json()
if r.get('message', '') == 'success':
self._update_citizen_location(country_id, region_id)
return True
return False
def _travel(self, country_id: int, region_id: int = 0) -> Response: def _travel(self, country_id: int, region_id: int = 0) -> Response:
data = { data = {
"toCountryId": country_id, "toCountryId": country_id,
"inRegionId": region_id, "inRegionId": region_id,
"battleId": 0,
} }
return self.post_travel("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, country_id: int = 0
country_id: int = 0) -> Response: ) -> Union[List[Any], Dict[str, Dict[str, Any]]]:
data = { d = self._post_travel_data(holdingId=holding_id, battleId=battle_id, countryId=country_id).json()
"holdingId": holding_id, return d.get('regions', [])
"battleId": battle_id,
"regionId": region_id, def get_travel_countries(self) -> List[int]:
} response_json = self._post_travel_data().json()
data.update(countryId=country_id) return_list = []
return self.post_travel_data(**data) for country_data in response_json['countries'].values():
if country_data['currentRegions']:
return_list.append(country_data['id'])
return return_list
def parse_notifications(self, page: int = 1) -> list: def parse_notifications(self, page: int = 1) -> list:
response = self.get_message_alerts(page) community = self._get_notifications_ajax_community(page).json()
notifications = re.findall(r"<p class=\"smallpadded\">(.*?)</p>", response.text, re.M | re.I | re.S) system = self._get_notifications_ajax_system(page).json()
return notifications return community['alertsList'] + system['alertsList']
def delete_notifications(self): def delete_notifications(self):
def notification_ids(html): response = self._get_notifications_ajax_community().json()
return re.findall(r"id=\"delete_alert_(\d+)\"", html) while response['totalAlerts']:
self._post_messages_alert([_['id'] for _ in response['alertList']])
response = self._get_notifications_ajax_community().json()
response = self.get_message_alerts() response = self._get_notifications_ajax_system().json()
while notification_ids(response.text): while response['totalAlerts']:
response = self.post_messages_alert(notification_ids(response.text)) self._post_messages_alert([_['id'] for _ in response['alertList']])
response = self._get_notifications_ajax_system().json()
def collect_weekly_reward(self): def collect_weekly_reward(self):
self.update_weekly_challenge() self.update_weekly_challenge()
@ -1033,7 +1108,7 @@ class Citizen(classes.CitizenAPI):
def collect_daily_task(self) -> 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:
self.post_daily_task_reward() self._post_daily_task_reward()
def send_mail_to_owner(self) -> None: def send_mail_to_owner(self) -> None:
if not self.details.citizen_id == 1620414: if not self.details.citizen_id == 1620414:
@ -1041,16 +1116,21 @@ class Citizen(classes.CitizenAPI):
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)
self.post_delete_message([msg_id]) self._post_delete_message([msg_id])
None
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()
raw_short_names = dict(frm="foodRaw", wrm="weaponRaw", hrm="houseRaw", arm="airplaneRaw") raw_short_names = dict(frm="foodRaw", wrm="weaponRaw", hrm="houseRaw", arm="airplaneRaw")
q1_industries = ["aircraft"] + list(raw_short_names.values()) q1_industries = ["aircraft"] + list(raw_short_names.values())
if product in raw_short_names: if product:
quality = 1 if product not in self.available_industries and product not in raw_short_names:
product = raw_short_names.get(product) self.write_log("Industry '{}' not implemented".format(product))
raise classes.ErepublikException("Industry '{}' not implemented".format(product))
elif product in raw_short_names:
quality = 1
product = raw_short_names.get(product)
product = [product]
elif quality:
raise classes.ErepublikException("Quality without product not allowed")
item_data = dict(price=999999., country=0, amount=0, offer_id=0, citizen_id=0) item_data = dict(price=999999., country=0, amount=0, offer_id=0, citizen_id=0)
@ -1063,48 +1143,43 @@ class Citizen(classes.CitizenAPI):
"foodRaw": dict(q1=item_data.copy()), "weaponRaw": dict(q1=item_data.copy()), "foodRaw": dict(q1=item_data.copy()), "weaponRaw": dict(q1=item_data.copy()),
"houseRaw": dict(q1=item_data.copy()), "airplaneRaw": dict(q1=item_data.copy())} "houseRaw": dict(q1=item_data.copy()), "airplaneRaw": dict(q1=item_data.copy())}
countries = [country_id] if country_id else self.countries if country_id:
if product not in self.available_industries: countries = [country_id]
self.write_log("Industry '{}' not implemented".format(product)) else:
return ret good_countries = self.get_travel_countries()
countries = {cid for cid in self.countries.keys() if cid in good_countries}
start_dt = self.now start_dt = self.now
for country in countries: iterable = [countries, product or items, [quality] if quality else range(1, 8)]
if not country_id and not self.get_country_travel_region(country): for country, industry, q in itertools.product(*iterable):
if (q > 1 and industry in q1_industries) or (q > 5 and industry == "house"):
continue continue
for industry in [product] or items:
for q in [quality] if quality else range(1, 8):
if (q > 1 and industry in q1_industries) or (q > 5 and industry == "house"):
break
str_q = "q%i" % q str_q = "q%i" % q
data = {'country': country, 'industry': self.available_industries[industry], 'quality': q} r = self._post_economy_marketplace(country, self.available_industries[industry], q).json()
r = self.post_economy_marketplace(**data) obj = items[industry][str_q]
rjson = r.json() if not r.get("error", False):
obj = items[industry][str_q] for offer in r["offers"]:
if not rjson.get("error", False): if obj["price"] > float(offer["priceWithTaxes"]):
for offer in rjson["offers"]: obj["price"] = float(offer["priceWithTaxes"])
if obj["price"] > float(offer["priceWithTaxes"]): obj["country"] = int(offer["country_id"])
obj["price"] = float(offer["priceWithTaxes"]) obj["amount"] = int(offer["amount"])
obj["country"] = int(offer["country_id"]) obj["offer_id"] = int(offer["id"])
obj["amount"] = int(offer["amount"]) obj["citizen_id"] = int(offer["citizen_id"])
obj["offer_id"] = int(offer["id"]) elif obj["price"] == float(offer["priceWithTaxes"]) and obj["amount"] < int(offer["amount"]):
obj["citizen_id"] = int(offer["citizen_id"]) obj["country"] = int(offer["country_id"])
elif obj["price"] == float(offer["priceWithTaxes"]) \ obj["amount"] = int(offer["amount"])
and obj["amount"] < int(offer["amount"]): obj["offer_id"] = int(offer["id"])
obj["country"] = int(offer["country_id"])
obj["amount"] = int(offer["amount"])
obj["offer_id"] = int(offer["id"])
self.write_log("Scraped market in {}!".format(self.now - start_dt)) self.write_log("Scraped market in {}!".format(self.now - start_dt))
if quality: if quality:
ret = items[product]["q%i" % quality] ret = items[product[0]]["q%i" % quality]
elif product: elif product:
if product in raw_short_names.values(): if product[0] in raw_short_names.values():
ret = items[product]["q1"] ret = items[product[0]]["q1"]
else: else:
ret = items[product] ret = items[product[0]]
else: else:
ret = items ret = items
return ret return ret
@ -1135,7 +1210,7 @@ class Citizen(classes.CitizenAPI):
def get_monetary_offers(self, currency: int = 62) -> List[Dict[str, Union[int, float]]]: 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._post_economy_exchange_retrieve(False, 0, currency).json()
ret = [] ret = []
offers = re.findall(r"id='purchase_(\d+)' data-i18n='Buy for' data-currency='GOLD' " offers = re.findall(r"id='purchase_(\d+)' data-i18n='Buy for' data-currency='GOLD' "
r"data-price='(\d+\.\d+)' data-max='(\d+\.\d+)' trigger='purchase'", r"data-price='(\d+\.\d+)' data-max='(\d+\.\d+)' trigger='purchase'",
@ -1147,14 +1222,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(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) -> None: def activate_dmg_booster(self, battle_id: int):
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:
@ -1165,52 +1240,52 @@ 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
self.post_fight_activate_booster(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) -> Response: def activate_battle_effect(self, battle_id: int, kind: str) -> Response:
return self.post_activate_battle_effect(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) -> Response: def activate_pp_booster(self, battle_id: int) -> Response:
return self.post_fight_activate_booster(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) -> Response: 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(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(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(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(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:
r = self.get_message_alerts() r = self._get_notifications_ajax_system()
count = 0 count = 0
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(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_notifications_ajax_system()
donation_ids = re.findall(r"erepublik.functions.acceptRejectDonation\(\"reject\", (\d+)\)", r.text) donation_ids = re.findall(r"erepublik.functions.acceptRejectDonation\(\"reject\", (\d+)\)", r.text)
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
@ -1372,7 +1447,7 @@ class Citizen(classes.CitizenAPI):
return False return False
def get_article_comments(self, article_id: int = 2645676, page_id: int = 1) -> Response: def get_article_comments(self, article_id: int = 2645676, page_id: int = 1) -> Response:
return self.post_article_comments(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:
@ -1385,14 +1460,14 @@ class Citizen(classes.CitizenAPI):
return r return r
def write_article_comment(self, message: str, article_id: int, parent_id: int = None) -> Response: def write_article_comment(self, message: str, article_id: int, parent_id: int = None) -> Response:
return self.post_article_comments_create(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) -> Response: 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(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(
@ -1413,22 +1488,22 @@ 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) -> dict:
ret = self.post_economy_marketplace_actions(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 json_ret
else: else:
self.details.cc = ret.json()['currency'] self.details.cc = ret.json()['currency']
self.details.gold = ret.json()['gold'] self.details.gold = ret.json()['gold']
r_json = ret.json() r_json = ret.json()
r_json.pop("offerUpdate", None) r_json.pop("offerUpdate", None)
self.reporter.report_action("BUY_PRODUCT", ret.json()) self.reporter.report_action("BUY_PRODUCT", ret.json())
return ret return json_ret
def get_raw_surplus(self) -> (float, float): def get_raw_surplus(self) -> (float, float):
frm = 0.00 frm = 0.00
@ -1457,10 +1532,10 @@ class Citizen(classes.CitizenAPI):
""" """
Assigns factory to new holding Assigns factory to new holding
""" """
return self.post_economy_assign_to_holding(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(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:
""" """
@ -1470,10 +1545,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(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(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]:
@ -1493,7 +1568,7 @@ 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('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
@ -1501,12 +1576,12 @@ class Citizen(classes.CitizenAPI):
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())
self.post_economy_resign() self._post_economy_resign()
return True return True
return False 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(citizen=0, salary=10) data = dict(citizen=0, salary=10)
for posting in jobs: for posting in jobs:
@ -1517,13 +1592,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(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
@ -1531,15 +1606,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})
@ -1547,11 +1622,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"]})
@ -1559,10 +1634,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(int(r.json()["panelContents"]["pages"])):
r = self.get_military_unit_data(mu_id, page) r = self._get_military_unit_data(mu_id, currentPage=page + 1)
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"]})
@ -1572,13 +1647,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(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(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']})
@ -1586,27 +1661,54 @@ 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"])
def schedule_attack(self, war_id: int, region_id: int, at_time: datetime) -> None: def schedule_attack(self, war_id: int, region_id: int, region_name: str, at_time: datetime) -> None:
if at_time: if at_time:
self.sleep(utils.get_sleep_seconds(at_time)) self.sleep(utils.get_sleep_seconds(at_time))
self.get_csrf_token() self.get_csrf_token()
self._launch_battle(war_id, region_id) self.launch_attack(war_id, region_id, region_name)
def get_active_wars_with_regions(self): def get_active_wars(self, country_id: int = None) -> List[int]:
self.get_country_military(self.countries.get(self.details.citizen_id)["name"]) r = self._get_country_military(utils.COUNTRY_LINK.get(country_id or self.details.citizenship))
raise NotImplementedError all_war_ids = re.findall(r'//www\.erepublik\.com/en/wars/show/(\d+)"', r.text)
return [int(wid) for wid in all_war_ids]
def _launch_battle(self, war_id: int, region_id: int) -> Response: def get_war_status(self, war_id: int) -> Dict[str, Union[bool, Dict[int, str]]]:
return self.post_wars_attack_region(war_id, region_id) r = self._get_wars_show(war_id)
html = r.text
ret = {}
reg_re = re.compile(fr'data-war-id="{war_id}" data-region-id="(\d+)" data-region-name="([- \w]+)"')
if reg_re.findall(html):
ret.update(regions={}, can_attack=True)
for reg in reg_re.findall(html):
ret["regions"].update({str(reg[0]): reg[1]})
elif re.search(r'<a href="//www.erepublik.com/en/military/battlefield/(\d+)" '
r'class="join" title="Join"><span>Join</span></a>', html):
battle_id = re.search(r'<a href="//www.erepublik.com/en/military/battlefield/(\d+)" '
r'class="join" title="Join"><span>Join</span></a>', html).group(1)
ret.update(can_attack=False, battle_id=battle_id)
else:
ret.update(can_attack=False)
return ret
def get_last_battle_of_war_end_time(self, war_id: int) -> datetime:
r = self._get_wars_show(war_id)
html = r.text
last_battle_id = int(re.search(r'<a href="//www.erepublik.com/en/military/battlefield/(\d+)">', html).group(1))
console = self._post_military_battle_console(last_battle_id, 'warList', 1).json()
battle = console.get('list')[0]
return utils.localize_dt(datetime.datetime.strptime(battle.get('result').get('end'), "%Y-%m-%d %H:%M:%S"))
def launch_attack(self, war_id: int, region_id: int, region_name: str):
self._post_wars_attack_region(war_id, region_id, region_name)
def state_update_repeater(self): def state_update_repeater(self):
try: try:
@ -1692,8 +1794,8 @@ class Citizen(classes.CitizenAPI):
buy = self.buy_from_market(global_cheapest['offer_id'], 1) buy = self.buy_from_market(global_cheapest['offer_id'], 1)
else: else:
buy = self.buy_from_market(cheapest_offer['offer_id'], 1) buy = self.buy_from_market(cheapest_offer['offer_id'], 1)
if buy.json()["error"]: if buy["error"]:
msg = "Unable to buy q{} house! \n{}".format(q, buy.json()['message']) msg = "Unable to buy q{} house! \n{}".format(q, buy['message'])
self.write_log(msg) self.write_log(msg)
else: else:
ok_to_activate = True ok_to_activate = True
@ -1718,20 +1820,20 @@ 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(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() 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(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")}
@ -1740,9 +1842,9 @@ class Citizen(classes.CitizenAPI):
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(**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:
@ -1750,9 +1852,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(**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:
@ -1760,19 +1862,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(**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="(\d?)">.*?</option>.*</select>""",
self.r.text, re.S | re.M) self.r.text, re.S | re.M)
if post_to_wall_as: r = self._post_country_post_create(message, max(post_to_wall_as, key=int) if post_to_wall_as else 0)
self.post_country_post_create(message, max(post_to_wall_as)) return r.json()
return True
return False
def report_error(self, msg: str = ""): def report_error(self, msg: str = ""):
utils.process_error(msg, self.name, sys.exc_info(), self, self.commit_id, False) utils.process_error(msg, self.name, sys.exc_info(), self, self.commit_id, False)
@ -1782,7 +1882,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(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

@ -5,7 +5,7 @@ import random
import time import time
from collections import deque from collections import deque
from json import JSONDecodeError, loads, JSONEncoder from json import JSONDecodeError, loads, JSONEncoder
from typing import Any, Dict, List, Union from typing import Any, Dict, List, Union, Mapping, Iterable
from requests import Response, Session from requests import Response, Session
@ -26,11 +26,13 @@ class ErepublikNetworkException(Exception):
class MyCompanies: class MyCompanies:
work_units: int = 0 work_units: int = 0
next_ot_time: datetime.datetime next_ot_time: datetime.datetime
holdings: Dict[int, Dict] = dict() holdings: Dict[int, Dict] = None
companies: Dict[int, Dict] = dict() companies: Dict[int, Dict] = None
ff_lockdown: int = 0 ff_lockdown: int = 0
def __init__(self): def __init__(self):
self.holdings = dict()
self.companies = dict()
self.next_ot_time = utils.now() self.next_ot_time = utils.now()
def prepare_holdings(self, holdings: dict): def prepare_holdings(self, holdings: dict):
@ -41,7 +43,7 @@ class MyCompanies:
template = dict(id=0, num_factories=0, region_id=0, companies=[]) template = dict(id=0, num_factories=0, region_id=0, companies=[])
for holding_id, holding in holdings.items(): for holding_id, holding in holdings.items():
tmp: Dict[str, Union[List[Any], Any]] = {} tmp: Dict[str, Union[Iterable[Any], Any]] = {}
for key in template: for key in template:
if key == 'companies': if key == 'companies':
tmp.update({key: []}) tmp.update({key: []})
@ -441,6 +443,9 @@ class CitizenAPI:
token: str = "" 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 +454,124 @@ 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] = None): def _get_city_data_residents(self, city: int, page: int = 1, params: Mapping[str, Any] = None) -> Response:
if params is None: if params is None:
params = {} 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, **kwargs) -> Response: def _get_military_unit_data(self, unit_id: int, **kwargs) -> Response:
params = {"groupId": unit_id, "panel": "members", **kwargs} 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, 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": self.token}) return self.get("{}/main/money-donation/accept/{}".format(self.url, donation_id), params={"_token": self.token})
def get_money_donation_reject(self, 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": self.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, battle: int, kind: str, citizen_id: int) -> Response: def _get_wars_show(self, war_id: int) -> Response:
return self.get("{}/wars/show/{}".format(self.url, war_id))
def _post_activate_battle_effect(self, battle: int, kind: str, citizen_id: int) -> Response:
data = dict(battleId=battle, citizenId=citizen_id, type=kind, _token=self.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, article: int, page: int = 1) -> Response: def _post_article_comments(self, article: int, page: int = 1) -> Response:
data = dict(_token=self.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, 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=self.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, 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=self.token) leftPage=page, rightPage=page, _token=self.token)
if damage: if damage:
@ -564,15 +581,15 @@ 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, 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=self.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, presentation: str = "") -> Response: def _post_candidate_for_congress(self, presentation: str = "") -> Response:
data = dict(_token=self.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, citizen: int, add: bool) -> Response: def _post_citizen_add_remove_friend(self, citizen: int, add: bool) -> Response:
data = dict(_token=self.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"})
@ -580,69 +597,70 @@ class CitizenAPI:
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) -> Response: def _post_collect_anniversary_reward(self) -> Response:
return self.post("{}/main/collect-anniversary-reward".format(self.url), data={"_token": self.token}) return self.post("{}/main/collect-anniversary-reward".format(self.url), data={"_token": self.token})
def post_country_donate(self, country: int, action: str, value: Union[int, float], quality: int = None): def _post_country_donate(self, country: int, action: str, value: Union[int, float],
quality: int = None) -> Response:
json = dict(countryId=country, action=action, _token=self.token, value=value, quality=quality) 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) -> Response: def _post_daily_task_reward(self) -> Response:
return self.post("{}/main/daily-tasks-reward".format(self.url), data=dict(_token=self.token)) return self.post("{}/main/daily-tasks-reward".format(self.url), data=dict(_token=self.token))
def post_delete_message(self, msg_id: list) -> Response: def _post_delete_message(self, msg_id: list) -> Response:
data = {"_token": self.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, color: str) -> Response: def _post_eat(self, color: str) -> Response:
data = dict(_token=self.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, quality: int) -> Response: def _post_economy_activate_house(self, quality: int) -> Response:
data = {"action": "activate", "quality": quality, "type": "house", "_token": self.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, factory: int, holding: int) -> Response: def _post_economy_assign_to_holding(self, factory: int, holding: int) -> Response:
data = dict(_token=self.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, industry: int, building_type: int = 1) -> Response: def _post_economy_create_company(self, industry: int, building_type: int = 1) -> Response:
data = {"_token": self.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, 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=self.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, 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=self.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, amount: float, currency: int, offer: int) -> Response: def _post_economy_exchange_purchase(self, amount: float, currency: int, offer: int) -> Response:
data = dict(_token=self.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, personal: bool, page: int, currency: int) -> Response: def _post_economy_exchange_retrieve(self, personal: bool, page: int, currency: int) -> Response:
data = dict(_token=self.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, citizen: int, salary: int) -> Response: def _post_economy_job_market_apply(self, citizen: int, salary: int) -> Response:
data = dict(_token=self.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, 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=self.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, 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=self.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)
@ -651,12 +669,12 @@ class CitizenAPI:
industryId=kwargs["industry"], 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) -> 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": self.token, "action_type": "resign"}) data={"_token": self.token, "action_type": "resign"})
def post_economy_sell_company(self, 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=self.token, pin="" if pin is None else pin) data = dict(_token=self.token, pin="" if pin is None else pin)
if sell: if sell:
@ -665,10 +683,10 @@ class CitizenAPI:
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, 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
@ -677,11 +695,11 @@ class CitizenAPI:
data['_token'] = self.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, 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=self.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, 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
""" """
@ -690,87 +708,91 @@ class CitizenAPI:
if wam is None: if wam is None:
wam = [] wam = []
data: Dict[str, Union[int, str]] = dict(action_type=action_type, _token=self.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
}) })
return self.post("{}/economy/work".format(self.url), data=data) max_idx += 1
else: return self.post("{}/economy/work".format(self.url), data=data)
return
def post_economy_work_overtime(self) -> Response: def _post_economy_work_overtime(self) -> Response:
data = dict(action_type="workOvertime", _token=self.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, email: str) -> Response: def _post_forgot_password(self, email: str) -> Response:
data = dict(_token=self.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, 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=self.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, email: str, password: str) -> Response: def _post_login(self, email: str, password: str) -> Response:
data = dict(csrf_token=self.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, notification_ids: list) -> Response: def _post_messages_alert(self, notification_ids: List[int]) -> Response:
data = {"_token": self.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, 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=self.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, battle_id: int, round_id: int, division: int) -> Response: def _post_military_battle_console(self, battle_id: int, action: str, page: int = 1, **kwargs) -> Response:
data = dict(battleId=battle_id, zoneId=round_id, action="battleStatistics", round=round_id, division=division, data = dict(battleId=battle_id, action=action, _token=self.token)
type="damage", leftPage=1, rightPage=1, _token=self.token) if action == "battleStatistics":
return self.post("{}/military/battle-console".format(self.url, battle_id), data=data) data.update(round=kwargs["round_id"], zoneId=kwargs["round_id"], leftPage=page, rightPage=page,
division=kwargs["division"], type=kwargs.get("type", 'damage'),)
elif action == "warList":
data.update(page=page)
return self.post("{}/military/battle-console".format(self.url), data=data)
def post_military_fight_air(self, battle_id: int, side_id: int) -> Response: def _post_military_deploy_bomb(self, battle_id: int, bomb_id: int) -> Response:
data = dict(battleId=battle_id, bombId=bomb_id, _token=self.token)
return self.post("{}/military/deploy-bomb".format(self.url), data=data)
def _post_military_fight_air(self, battle_id: int, side_id: int) -> Response:
data = dict(sideId=side_id, battleId=battle_id, _token=self.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, 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=self.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) -> Response: def _post_military_group_missions(self) -> Response:
data = dict(action="check", _token=self.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, check: str, **kwargs) -> Response: def _post_travel(self, check: str, **kwargs) -> Response:
data = dict(_token=self.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, **kwargs) -> Response: def _post_travel_data(self, **kwargs) -> Response:
return self.post("{}/main/travelData".format(self.url), data=dict(_token=self.token, **kwargs)) return self.post("{}/main/travelData".format(self.url), data=dict(_token=self.token, **kwargs))
def post_wars_attack_region(self, war: int, region: int) -> Response: def _post_wars_attack_region(self, war_id: int, region_id: int, region_name: str) -> Response:
data = dict(_token=self.token) data = {'_token': self.token, 'warId': war_id, 'regionName': region_name, 'regionNameConfirm': region_name}
return self.post("{}/wars/attack-region/{}/{}".format(self.url, war, region), data=data) return self.post('{}/wars/attack-region/{}/{}'.format(self.url, war_id, region_id), data=data)
def post_weekly_challenge_reward(self, reward_id: int) -> Response: def _post_weekly_challenge_reward(self, reward_id: int) -> Response:
data = dict(_token=self.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, 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=self.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)
@ -778,73 +800,73 @@ class CitizenAPI:
# Wall Posts # Wall Posts
# ## Country # ## Country
def post_country_comment_retrieve(self, post_id: int): def _post_country_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": self.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_comment_create(self, post_id: int, comment_message: str): def _post_country_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message} data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/country-comment/create/json".format(self.url), data=data) return self.post("{}/main/country-comment/create/json".format(self.url), data=data)
def post_country_post_create(self, body: str, post_as: int): def _post_country_post_create(self, body: str, post_as: int) -> Response:
data = {"_token": self.token, "post_message": body, "post_as": post_as} 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): def _post_country_post_retrieve(self) -> Response:
data = {"_token": self.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, post_id: int): def _post_military_unit_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": self.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_comment_create(self, post_id: int, comment_message: str): def _post_military_unit_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message} 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) 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): def _post_military_unit_post_create(self, body: str, post_as: int) -> Response:
data = {"_token": self.token, "post_message": body, "post_as": post_as} 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): def _post_military_unit_post_retrieve(self) -> Response:
data = {"_token": self.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, post_id: int): def _post_party_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": self.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_comment_create(self, post_id: int, comment_message: str): def _post_party_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message} data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/party-comment/create/json".format(self.url), data=data) return self.post("{}/main/party-comment/create/json".format(self.url), data=data)
def post_party_post_create(self, body: str): def _post_party_post_create(self, body: str) -> Response:
data = {"_token": self.token, "post_message": body} 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): def _post_party_post_retrieve(self) -> Response:
data = {"_token": self.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, post_id: int): def _post_wall_comment_retrieve(self, post_id: int) -> Response:
data = {"_token": self.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_comment_create(self, post_id: int, comment_message: str): def _post_wall_comment_create(self, post_id: int, comment_message: str) -> Response:
data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message} data = {"_token": self.token, "postId": post_id, 'comment_message': comment_message}
return self.post("{}/main/wall-comment/create/json".format(self.url), data=data) return self.post("{}/main/wall-comment/create/json".format(self.url), data=data)
def post_wall_post_create(self, body: str): def _post_wall_post_create(self, body: str) -> Response:
data = {"_token": self.token, "post_message": body} 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): def _post_wall_post_retrieve(self) -> Response:
data = {"_token": self.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)
@ -950,8 +972,8 @@ class MyJSONEncoder(JSONEncoder):
class BattleSide: class BattleSide:
id: int id: int
points: int points: int
deployed: List[int] = list() deployed: List[int] = None
allies: List[int] = list() allies: List[int] = None
def __init__(self, country_id: int, points: int, allies: List[int], deployed: List[int]): def __init__(self, country_id: int, points: int, allies: List[int], deployed: List[int]):
self.id = country_id self.id = country_id
@ -963,8 +985,8 @@ class BattleSide:
class BattleDivision: class BattleDivision:
end: datetime.datetime end: datetime.datetime
epic: bool epic: bool
dom_pts: Dict[str, int] = dict() dom_pts: Dict[str, int] = None
wall: Dict[str, Union[int, float]] = dict() wall: Dict[str, Union[int, float]] = None
@property @property
def div_end(self) -> bool: def div_end(self) -> bool:
@ -973,8 +995,8 @@ class BattleDivision:
def __init__(self, end: datetime.datetime, epic: bool, inv_pts: int, def_pts: int, wall_for: int, wall_dom: float): def __init__(self, end: datetime.datetime, epic: bool, inv_pts: int, def_pts: int, wall_for: int, wall_dom: float):
self.end = end self.end = end
self.epic = epic self.epic = epic
self.dom_pts.update({"inv": inv_pts, "def": def_pts}) self.dom_pts = dict({"inv": inv_pts, "def": def_pts})
self.wall.update({"for": wall_for, "dom": wall_dom}) self.wall = dict({"for": wall_for, "dom": wall_dom})
class Battle(object): class Battle(object):
@ -986,13 +1008,13 @@ class Battle(object):
start: datetime.datetime = None start: datetime.datetime = None
invader: BattleSide = None invader: BattleSide = None
defender: BattleSide = None defender: BattleSide = None
div: Dict[int, BattleDivision] = dict() div: Dict[int, BattleDivision] = None
@property @property
def is_air(self) -> bool: def is_air(self) -> bool:
return not bool(self.zone_id % 4) return not bool(self.zone_id % 4)
def __init__(self, battle: dict): def __init__(self, battle: Dict[str, Any]):
self.id = int(battle.get('id', 0)) self.id = int(battle.get('id', 0))
self.war_id = int(battle.get('war_id', 0)) self.war_id = int(battle.get('war_id', 0))
self.zone_id = int(battle.get('zone_id', 0)) self.zone_id = int(battle.get('zone_id', 0))
@ -1009,6 +1031,7 @@ class Battle(object):
[row.get('id') for row in battle.get('def', {}).get('ally_list')], [row.get('id') for row in battle.get('def', {}).get('ally_list')],
[row.get('id') for row in battle.get('def', {}).get('ally_list') if row['deployed']]) [row.get('id') for row in battle.get('def', {}).get('ally_list') if row['deployed']])
self.div = {}
for div, data in battle.get('div', {}).items(): for div, data in battle.get('div', {}).items():
div = int(div) div = int(div)
if data.get('end'): if data.get('end'):

View File

@ -11,13 +11,12 @@ from collections import deque
from decimal import Decimal from decimal import Decimal
from json import JSONEncoder from json import JSONEncoder
from pathlib import Path from pathlib import Path
from typing import Union from typing import Union, Any, List, NoReturn, Mapping
import pytz import pytz
import requests import requests
from requests import Response from requests import Response
__all__ = ["FOOD_ENERGY", "COMMIT_ID", "COUNTRIES", "erep_tz", __all__ = ["FOOD_ENERGY", "COMMIT_ID", "COUNTRIES", "erep_tz",
"now", "localize_dt", "localize_timestamp", "good_timedelta", "eday_from_date", "date_from_eday", "now", "localize_dt", "localize_timestamp", "good_timedelta", "eday_from_date", "date_from_eday",
"get_sleep_seconds", "interactive_sleep", "silent_sleep", "get_sleep_seconds", "interactive_sleep", "silent_sleep",
@ -85,6 +84,19 @@ COUNTRIES = {1: 'Romania', 9: 'Brazil', 10: 'Italy', 11: 'France', 12: 'Germany'
82: 'Cyprus', 83: 'Belarus', 84: 'New Zealand', 164: 'Saudi Arabia', 165: 'Egypt', 82: 'Cyprus', 83: 'Belarus', 84: 'New Zealand', 164: 'Saudi Arabia', 165: 'Egypt',
166: 'United Arab Emirates', 167: 'Albania', 168: 'Georgia', 169: 'Armenia', 170: 'Nigeria', 171: 'Cuba'} 166: 'United Arab Emirates', 167: 'Albania', 168: 'Georgia', 169: 'Armenia', 170: 'Nigeria', 171: 'Cuba'}
COUNTRY_LINK = {1: 'Romania', 9: 'Brazil', 11: 'France', 12: 'Germany', 13: 'Hungary', 82: 'Cyprus', 168: 'Georgia',
15: 'Spain', 23: 'Canada', 26: 'Mexico', 27: 'Argentina', 28: 'Venezuela', 80: 'Montenegro', 24: 'USA',
29: 'United-Kingdom', 50: 'Australia', 47: 'South-Korea',171: 'Cuba', 79: 'Republic-of-Macedonia-FYROM',
30: 'Switzerland', 31: 'Netherlands', 32: 'Belgium', 33: 'Austria', 34: 'Czech-Republic', 35: 'Poland',
36: 'Slovakia', 37: 'Norway', 38: 'Sweden', 39: 'Finland', 40: 'Ukraine', 41: 'Russia', 42: 'Bulgaria',
43: 'Turkey', 44: 'Greece', 45: 'Japan', 48: 'India', 49: 'Indonesia', 78: 'Colombia', 68: 'Singapore',
51: 'South Africa', 52: 'Republic-of-Moldova', 53: 'Portugal', 54: 'Ireland', 55: 'Denmark', 56: 'Iran',
57: 'Pakistan', 58: 'Israel', 59: 'Thailand', 61: 'Slovenia', 63: 'Croatia', 64: 'Chile', 65: 'Serbia',
66: 'Malaysia', 67: 'Philippines', 70: 'Estonia', 165: 'Egypt', 14: 'China', 77: 'Peru', 10: 'Italy',
71: 'Latvia', 72: 'Lithuania', 73: 'North-Korea', 74: 'Uruguay', 75: 'Paraguay', 76: 'Bolivia',
81: 'Republic-of-China-Taiwan', 166: 'United-Arab-Emirates', 167: 'Albania', 69: 'Bosnia-Herzegovina',
169: 'Armenia', 83: 'Belarus', 84: 'New-Zealand', 164: 'Saudi-Arabia', 170: 'Nigeria', }
class MyJSONEncoder(JSONEncoder): class MyJSONEncoder(JSONEncoder):
def default(self, o): def default(self, o):
@ -107,18 +119,22 @@ class MyJSONEncoder(JSONEncoder):
return super().default(o) return super().default(o)
def now(): def now() -> datetime.datetime:
return datetime.datetime.now(erep_tz).replace(microsecond=0) return datetime.datetime.now(erep_tz).replace(microsecond=0)
def localize_timestamp(timestamp: int): def localize_timestamp(timestamp: int) -> datetime.datetime:
return datetime.datetime.fromtimestamp(timestamp, erep_tz) return datetime.datetime.fromtimestamp(timestamp, erep_tz)
def localize_dt(dt: Union[datetime.date, datetime.datetime]): def localize_dt(dt: Union[datetime.date, datetime.datetime]) -> datetime.datetime:
if isinstance(dt, datetime.date): try:
dt = datetime.datetime.combine(dt, datetime.time(0, 0, 0)) try:
return erep_tz.localize(dt) return erep_tz.localize(dt)
except AttributeError:
return erep_tz.localize(datetime.datetime.combine(dt, datetime.time(0, 0, 0)))
except ValueError:
return dt.astimezone(erep_tz)
def good_timedelta(dt: datetime.datetime, td: datetime.timedelta) -> datetime.datetime: def good_timedelta(dt: datetime.datetime, td: datetime.timedelta) -> datetime.datetime:
@ -237,7 +253,10 @@ 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: str, content: list, player=None, local_vars=dict, promo: bool = False, captcha: bool = False): def send_email(name: str, content: List[Any], player=None, local_vars: Mapping[Any, Any] = None,
promo: bool = False, captcha: bool = False):
if local_vars is None:
local_vars = {}
from erepublik 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>"
@ -319,7 +338,11 @@ def process_error(log_info: str, name: str, exc_info: tuple, citizen=None, commi
send_email(name, bugtrace, citizen, local_vars=trace) send_email(name, bugtrace, citizen, local_vars=trace)
def slugify(value, allow_unicode=False): def report_promo(kind: str, time_untill: datetime.datetime) -> NoReturn:
requests.post('https://api.erep.lv/promos/add/', data=dict(kind=kind, time_untill=time_untill))
def slugify(value, allow_unicode=False) -> str:
""" """
Function copied from Django2.2.1 django.utils.text.slugify Function copied from Django2.2.1 django.utils.text.slugify
Convert to ASCII if 'allow_unicode' is False. Convert spaces to hyphens. Convert to ASCII if 'allow_unicode' is False. Convert spaces to hyphens.

View File

@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 0.14.7 current_version = 0.15.2
commit = True commit = True
tag = True tag = True

View File

@ -42,6 +42,6 @@ setup(
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.7', version='0.15.2',
zip_safe=False, zip_safe=False,
) )