mirror of
https://gitea.augustin64.fr/piair/MsRewards-Reborn.git
synced 2025-06-17 17:14:46 +02:00
updated webUI according to param changes
This commit is contained in:
15
modules/Classes/Config.py
Normal file
15
modules/Classes/Config.py
Normal file
@ -0,0 +1,15 @@
|
||||
import json
|
||||
|
||||
from modules.Classes.UserCredentials import UserCredentials
|
||||
|
||||
|
||||
class Config:
|
||||
def __init__(self, args):
|
||||
self.args = args
|
||||
self.UserCredentials = UserCredentials()
|
||||
|
||||
with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile:
|
||||
configs = json.load(inFile)
|
||||
for i in configs[str(args.config)]["accounts"]:
|
||||
d = configs[str(args.config)]["accounts"][i]
|
||||
self.UserCredentials.add(d["mail"], d["pwd"], d["2fa"])
|
39
modules/Classes/UserCredentials.py
Normal file
39
modules/Classes/UserCredentials.py
Normal file
@ -0,0 +1,39 @@
|
||||
import json
|
||||
from modules.Tools.logger import debug, warning
|
||||
|
||||
|
||||
class UserCredentials:
|
||||
def __init__(self):
|
||||
self.data = {}
|
||||
self.current = 0
|
||||
self.total = 0
|
||||
|
||||
def add(self, username: str, password: str, tfa: str = None):
|
||||
debug(f"adding account with data : Username: {username}, Password: {password}, 2FA: {'None' if tfa == '' else tfa}")
|
||||
self.data[self.total] = {
|
||||
"username": username,
|
||||
"password": password,
|
||||
"2fa": None if tfa == '' else tfa
|
||||
}
|
||||
self.total += 1
|
||||
|
||||
def tfa_enable(self):
|
||||
return self.data[self.current]["2fa"] is not None
|
||||
|
||||
def get_mail(self):
|
||||
return self.data[self.current]["username"]
|
||||
|
||||
def get_password(self):
|
||||
return self.data[self.current]["password"]
|
||||
|
||||
def get_tfa(self):
|
||||
if not self.tfa_enable():
|
||||
warning("Warning: TFA is not enabled. Calling get_tfa is an expected behaviour.")
|
||||
return self.data[self.current]["tfa"]
|
||||
|
||||
def next_account(self):
|
||||
self.current += 1
|
||||
debug(f"New credentials: {self.data[self.current]}")
|
||||
|
||||
def is_valid(self):
|
||||
return self.current < self.total
|
47
modules/Tools/logger.py
Normal file
47
modules/Tools/logger.py
Normal file
@ -0,0 +1,47 @@
|
||||
import logging
|
||||
|
||||
# ANSI escape codes for colors
|
||||
COLOR_CODES = {
|
||||
'RESET': '\033[0m',
|
||||
'BOLD': '\033[1m',
|
||||
'RED': '\033[31m',
|
||||
'GREEN': '\033[32m',
|
||||
'YELLOW': '\033[33m',
|
||||
'BLUE': '\033[34m',
|
||||
}
|
||||
|
||||
# Define colors for each log level
|
||||
LOG_COLORS = {
|
||||
'DEBUG': COLOR_CODES['BLUE'],
|
||||
'INFO': COLOR_CODES['GREEN'],
|
||||
'WARNING': COLOR_CODES['YELLOW'],
|
||||
'ERROR': COLOR_CODES['RED'],
|
||||
'CRITICAL': COLOR_CODES['BOLD'] + COLOR_CODES['RED'],
|
||||
}
|
||||
|
||||
|
||||
# Create a formatter with colors
|
||||
class ColoredFormatter(logging.Formatter):
|
||||
def format(self, record):
|
||||
log_level = record.levelname
|
||||
record.levelname = f"{LOG_COLORS.get(log_level, '')}{record.levelname}{COLOR_CODES['RESET']}"
|
||||
return super().format(record)
|
||||
|
||||
|
||||
# Set up the root logger
|
||||
root_logger = logging.getLogger()
|
||||
root_logger.setLevel(logging.DEBUG)
|
||||
|
||||
# Create a console handler and set the formatter
|
||||
ch = logging.StreamHandler()
|
||||
ch.setFormatter(ColoredFormatter('%(levelname)s: %(message)s'))
|
||||
|
||||
# Add the console handler to the root logger
|
||||
root_logger.addHandler(ch)
|
||||
|
||||
# Define log level functions
|
||||
debug = root_logger.debug
|
||||
info = root_logger.info
|
||||
warning = root_logger.warning
|
||||
error = root_logger.error
|
||||
critical = root_logger.critical
|
34
modules/cards.py
Normal file
34
modules/cards.py
Normal file
@ -0,0 +1,34 @@
|
||||
from modules.imports import *
|
||||
|
||||
|
||||
def welcome_tour(elm, driver):
|
||||
try :
|
||||
driver.find_element(By.CSS_SELECTOR, '[class="welcome-tour-next-button c-call-to-action c-glyph"]').click()
|
||||
except :
|
||||
pass
|
||||
driver.find_element(By.CSS_SELECTOR, '[class="quiz-link gray-button c-call-to-action c-glyph f-lightweight"]').click()
|
||||
sleep(5)
|
||||
driver.find_element(By.CSS_SELECTOR, '[class="c-glyph glyph-cancel"]').click()
|
||||
elm.click()
|
||||
driver.find_element(By.CSS_SELECTOR, '[class="quiz-link gray-button c-call-to-action c-glyph f-lightweight"]').click()
|
||||
sleep(5)
|
||||
driver.find_element(By.CSS_SELECTOR, '[class="c-glyph glyph-cancel"]').click()
|
||||
elm.click()
|
||||
driver.find_element(By.CSS_SELECTOR, '[class="quiz-link gray-button c-call-to-action c-glyph f-lightweight"]').click()
|
||||
sleep(5)
|
||||
driver.find_element(By.CSS_SELECTOR, '[class="c-glyph glyph-cancel"]').click()
|
||||
|
||||
def welcome_tour_NO(driver):
|
||||
try :
|
||||
driver.find_element(By.CSS_SELECTOR, '[class="welcome-tour-next-button c-call-to-action c-glyph"]').click()
|
||||
except :
|
||||
pass
|
||||
driver.find_element(By.CSS_SELECTOR, '[class="c-glyph glyph-cancel"]').click()
|
||||
sleep(5)
|
||||
|
||||
|
||||
def spotify(driver):
|
||||
sleep(5)
|
||||
driver.find_element(By.CSS_SELECTOR, '[data-bi-id="spotify-premium gratuit"]').click()
|
||||
sleep(5)
|
||||
close_tab(driver.window_handles[1])
|
107
modules/config.py
Normal file
107
modules/config.py
Normal file
@ -0,0 +1,107 @@
|
||||
#!/usr/bin/python3.10
|
||||
from modules.driver_tools import *
|
||||
from modules.imports import *
|
||||
import modules.globals as g
|
||||
import json
|
||||
|
||||
|
||||
class FakeWebHook:
|
||||
def send(self, text="", username='', avatar_url='', embed="", file=""):
|
||||
print(text)
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--config",
|
||||
help="Choose a specific config file",
|
||||
default=""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-v",
|
||||
"--vnc",
|
||||
help="enable VNC",
|
||||
dest="vnc"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--version",
|
||||
help="display a message on discord to tell that the bot have been updated",
|
||||
dest="update_version",
|
||||
default="None"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--json",
|
||||
help="input json to start the bot with custom parameters",
|
||||
default=""
|
||||
)
|
||||
|
||||
with open("/app/MsRewards-Reborn/user_data/discord.json", "r") as inFile:
|
||||
discord = json.load(inFile)
|
||||
with open("/app/MsRewards-Reborn/user_data/settings.json", "r") as inFile:
|
||||
settings = json.load(inFile)
|
||||
with open("/app/MsRewards-Reborn/user_data/proxy.json", "r") as inFile:
|
||||
proxy = json.load(inFile)
|
||||
with open("/app/MsRewards-Reborn/user_data/configs.json", "r") as inFile:
|
||||
config = json.load(inFile)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
g.json_start = args.json
|
||||
|
||||
g.vnc_enabled = args.vnc != "None"
|
||||
g.vnc_port = args.vnc
|
||||
g.update_version = args.update_version
|
||||
# global variables used later in the code
|
||||
|
||||
g.start_time = time()
|
||||
|
||||
# path configurations
|
||||
g.mot_path = "/usr/share/dict/french"
|
||||
g.credential_path = "/app/MsRewards-Reborn/user_data/login.csv"
|
||||
|
||||
discord_conf = config[args.config]["discord"]
|
||||
|
||||
# discord configuration
|
||||
g.discord_success_link = discord[discord_conf]["successL"]
|
||||
g.discord_error_link = discord[discord_conf]["errorsL"]
|
||||
g.discord_enabled_error = discord[discord_conf]["errorsT"] == "True"
|
||||
g.discord_enabled_success = discord[discord_conf]["successT"] == "True"
|
||||
|
||||
g.avatar_url = settings["avatarlink"]
|
||||
|
||||
if not g.json_start:
|
||||
if g.discord_enabled_error:
|
||||
webhookFailure = Webhook.from_url(g.discord_error_link, adapter=RequestsWebhookAdapter())
|
||||
if g.discord_enabled_success:
|
||||
webhookSuccess = Webhook.from_url(g.discord_success_link, adapter=RequestsWebhookAdapter())
|
||||
else:
|
||||
webhookFailure = FakeWebHook()
|
||||
webhookSuccess = FakeWebHook()
|
||||
|
||||
|
||||
# base settings
|
||||
g.discord_embed = False # send new point value in an embed, fixed for now
|
||||
g.headless = False
|
||||
|
||||
# proxy settings
|
||||
g.proxy_enabled = config[args.config]["proxy"] != "-1"
|
||||
if g.proxy_enabled:
|
||||
g.proxy_address = proxy[config[args.config]["proxy"]]["address"]
|
||||
g.proxy_port = proxy[config[args.config]["proxy"]]["port"]
|
||||
|
||||
|
||||
# list of words
|
||||
with open(g.mot_path, "r", encoding="utf-8") as h:
|
||||
lines = h.readlines()
|
||||
if len(lines) < 3:
|
||||
Liste_de_mot = list(lines[0].split(","))
|
||||
else:
|
||||
Liste_de_mot = [x.replace('\n', "") for x in lines]
|
||||
|
||||
|
||||
if g.proxy_enabled:
|
||||
setup_proxy(g.proxy_address, g.proxy_port)
|
67
modules/db.py
Normal file
67
modules/db.py
Normal file
@ -0,0 +1,67 @@
|
||||
import sqlite3
|
||||
|
||||
#Create a new row, for the account [compte] whith [points] points
|
||||
def add_row(compte, points, mycursor, mydb):
|
||||
sql = "INSERT INTO daily (compte, points, date) VALUES (?, ?, date())"
|
||||
val = (compte, points)
|
||||
mycursor.execute(sql, val)
|
||||
mydb.commit()
|
||||
#printf(mycursor.rowcount, "record created.")
|
||||
|
||||
|
||||
#update the ammount of points for the account [compte]
|
||||
def update_row(compte, points, mycursor, mydb):
|
||||
sql = f"UPDATE daily SET points = {points} WHERE compte = '{compte}' AND date = date() ;"
|
||||
mycursor.execute(sql)
|
||||
mydb.commit()
|
||||
#printf(mycursor.rowcount, "record(s) updated")
|
||||
|
||||
# update the value of last_pts for the table comptes
|
||||
def update_last(compte, points, mycursor, mydb):
|
||||
sql1 = f"UPDATE comptes SET last_pts = {points} WHERE compte = '{compte}';"
|
||||
sql2 = f"select * from comptes where compte = '{compte}'"
|
||||
sql3 = f"INSERT INTO comptes (compte, last_pts,banned) VALUES ('{compte}', {points}, 0)"
|
||||
cmd = mycursor.execute(sql2)
|
||||
if len(list(cmd)) == 0:
|
||||
mycursor.execute(sql3)
|
||||
else :
|
||||
mycursor.execute(sql1)
|
||||
mydb.commit()
|
||||
#printf(mycursor.rowcount, "record(s) updated")
|
||||
|
||||
# if return if there already is a line in the database for the account [compte]. if same_point is enabled, the line must also have the same number of points
|
||||
# SQLITE
|
||||
def get_row(compte, points, mycursor, same_points = True):
|
||||
if same_points :
|
||||
mycursor.execute(f"SELECT * FROM daily WHERE points = {points} AND compte = '{compte}' AND date = date() ;")
|
||||
else :
|
||||
mycursor.execute(f"SELECT * FROM daily WHERE compte = '{compte}' AND date = date() ;")
|
||||
myresult = mycursor.fetchall()
|
||||
return(len(myresult) == 1)
|
||||
|
||||
|
||||
def add_to_database(compte, points, save_if_fail=True):
|
||||
if points is None:
|
||||
pass
|
||||
else:
|
||||
mydb = sqlite3.connect("/app/MsRewards-Reborn/MsRewards.db")
|
||||
mycursor = mydb.cursor()
|
||||
if get_row(compte, points,mycursor, True): #check if the row exist with the same ammount of points and do nothind if it does
|
||||
#printf("les points sont deja bon")
|
||||
#return(0)
|
||||
pass
|
||||
elif get_row(compte, points,mycursor, False) : #check if the row exist, but without the same ammount of points and update the point account then
|
||||
update_row(compte, points,mycursor,mydb)
|
||||
#printf("row updated")
|
||||
#return(1)
|
||||
else : # if the row don't exist, create it with the good ammount of points
|
||||
add_row(compte, points,mycursor,mydb)
|
||||
#return(2) #printf("row added")
|
||||
if int(points) > 10 :
|
||||
update_last(compte, points, mycursor, mydb)
|
||||
mycursor.close()
|
||||
mydb.close()
|
||||
|
||||
|
||||
|
||||
|
96
modules/driver_tools.py
Normal file
96
modules/driver_tools.py
Normal file
@ -0,0 +1,96 @@
|
||||
from modules.imports import *
|
||||
from modules.config import *
|
||||
from modules.tools import *
|
||||
import modules.globals as g
|
||||
|
||||
|
||||
def set_language(ldriver):
|
||||
ldriver.get("chrome://settings/languages")
|
||||
action = ActionChains(ldriver)
|
||||
action.reset_actions()
|
||||
# select language
|
||||
x_coord = 1200
|
||||
y_coord = 150
|
||||
action.move_by_offset(x_coord, y_coord).click().perform()
|
||||
sleep(0.5)
|
||||
# scroll down
|
||||
action.reset_actions()
|
||||
elm = ldriver.find_element(By.XPATH, "/html/body")
|
||||
ActionChains(ldriver)\
|
||||
.send_keys("french")\
|
||||
.pause(0.5)\
|
||||
.send_keys(Keys.TAB + Keys.TAB + Keys.ENTER + Keys.TAB + Keys.TAB + Keys.ENTER)\
|
||||
.perform()
|
||||
x_coord = 1163
|
||||
y_coord = 717
|
||||
action.move_by_offset(x_coord, y_coord).click().perform()
|
||||
# put to the top
|
||||
sleep(0.5)
|
||||
action.reset_actions()
|
||||
x_coord = 1257
|
||||
y_coord = 328
|
||||
action.move_by_offset(x_coord, y_coord).click().perform()
|
||||
action.click().perform()
|
||||
|
||||
|
||||
def setup_proxy(ip: str, port: str) -> None:
|
||||
PROXY = f"{ip}:{port}"
|
||||
webdriver.DesiredCapabilities.FIREFOX['proxy'] = {
|
||||
"httpProxy": PROXY,
|
||||
"sslProxy": PROXY,
|
||||
"proxyType": "MANUAL",
|
||||
}
|
||||
|
||||
|
||||
#Deal with RGPD popup as well as some random popup like 'are you satisfied' one
|
||||
def rgpd_popup(driver) -> None:
|
||||
for i in ["bnp_btn_accept", "bnp_hfly_cta2", "bnp_hfly_close"] :
|
||||
try:
|
||||
driver.find_element(By.ID, i).click()
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# save webdriver cookies
|
||||
def save_cookies(driver) -> None:
|
||||
if g.dev:
|
||||
f = open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{g._mail}_unsafe.pkl", "w")
|
||||
for i in driver.get_cookies():
|
||||
f.write(str(i) + "\n")
|
||||
f.close()
|
||||
else :
|
||||
pickle.dump(driver.get_cookies(), open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{g._mail}.pkl", "wb"))
|
||||
|
||||
|
||||
# load cookies previously saved to the driver
|
||||
def load_cookies(driver) -> None:
|
||||
if g.dev:
|
||||
f = open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{g._mail}_unsafe.pkl", "r")
|
||||
lines = f.readlines()
|
||||
f.close()
|
||||
cookies = [literal_eval(x) for x in lines]
|
||||
else :
|
||||
cookies = pickle.load(open(f"{'/'.join(__file__.split('/')[:-2])}/user_data/cookies/{g._mail}.pkl", "rb"))
|
||||
for cookie in cookies:
|
||||
driver.add_cookie(cookie)
|
||||
|
||||
"""
|
||||
send_keys_wait([selenium element:element, str:keys]) send the different keys to the field element, with a random time between each press to simulate human action.
|
||||
keys can be an string, but also selenium keys
|
||||
"""
|
||||
def send_keys_wait(element, keys: str) -> None:
|
||||
for i in keys:
|
||||
element.send_keys(i)
|
||||
sleep(uniform(0.1, 0.3))
|
||||
|
||||
|
||||
|
||||
# Wait for the presence of the element identifier or [timeout]s
|
||||
def wait_until_visible(search_by: str, identifier: str, timeout = 20, browser = None) -> None:
|
||||
try :
|
||||
WebDriverWait(browser, timeout).until(EC.visibility_of_element_located((search_by,identifier)), "element not found")
|
||||
return(True)
|
||||
except TimeoutException as e:
|
||||
printf(f"element {identifier} not found after {timeout}s")
|
||||
return(False)
|
||||
|
8
modules/error.py
Normal file
8
modules/error.py
Normal file
@ -0,0 +1,8 @@
|
||||
class Banned(Exception):
|
||||
pass
|
||||
|
||||
class NotBanned(Exception):
|
||||
pass
|
||||
|
||||
class Identity(Exception):
|
||||
pass
|
30
modules/globals.py
Normal file
30
modules/globals.py
Normal file
@ -0,0 +1,30 @@
|
||||
driver = None
|
||||
display = None
|
||||
log = False
|
||||
full_log = False
|
||||
vnc_enabled = False
|
||||
vnc_port = 2345
|
||||
points_file = "/"
|
||||
update_version = False
|
||||
start_time = 0
|
||||
mot_path = "/"
|
||||
credential_path = "/"
|
||||
discord_success_link = "https://example.com"
|
||||
discord_error_link = "https://example.com"
|
||||
discord_enabled_error = False
|
||||
discord_enabled_success = False
|
||||
avatar_url = ""
|
||||
fidelity_link = "None"
|
||||
discord_embed = False
|
||||
headless = False
|
||||
proxy_enabled = False
|
||||
proxy_address = "0.0.0.0"
|
||||
proxy_port = "0"
|
||||
sql_enabled = False
|
||||
sql_usr = "None"
|
||||
sql_pwd = "azerty"
|
||||
sql_host = "https://example.com"
|
||||
sql_database = "MsRewards"
|
||||
norvege = False
|
||||
database_error_override = False
|
||||
json_start = ""
|
36
modules/imports.py
Normal file
36
modules/imports.py
Normal file
@ -0,0 +1,36 @@
|
||||
import argparse
|
||||
import asyncio
|
||||
import json
|
||||
import configparser
|
||||
import pickle
|
||||
from csv import reader
|
||||
from datetime import datetime, timedelta
|
||||
from os import path, sys, system
|
||||
from random import choice, randint, shuffle, uniform
|
||||
from re import findall, search
|
||||
from sys import platform
|
||||
from time import sleep, time
|
||||
|
||||
from discord import Colour, Embed, File, RequestsWebhookAdapter, Webhook
|
||||
from pyotp import TOTP
|
||||
from pyvirtualdisplay import Display
|
||||
from pyvirtualdisplay.smartdisplay import SmartDisplay
|
||||
from requests import get
|
||||
from selenium import webdriver
|
||||
from selenium.common import exceptions
|
||||
from selenium.common.exceptions import (ElementClickInterceptedException,
|
||||
NoSuchElementException,
|
||||
StaleElementReferenceException,
|
||||
TimeoutException, WebDriverException)
|
||||
from selenium.webdriver import ActionChains
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.firefox.options import Options
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.support.ui import Select, WebDriverWait
|
||||
from ast import literal_eval
|
||||
try:
|
||||
import enquiries
|
||||
except:
|
||||
system("") # enable colors in windows cmd
|
||||
import undetected_chromedriver as uc
|
82
modules/tools.py
Normal file
82
modules/tools.py
Normal file
@ -0,0 +1,82 @@
|
||||
from modules.imports import *
|
||||
from modules.config import *
|
||||
from modules.db import *
|
||||
import modules.globals as g
|
||||
# add the time arround the text given in [text]&
|
||||
def Timer(text: str) -> str:
|
||||
return(f"[{g._mail.split('@')[0]} - {datetime.today().strftime('%d/%m')} - {timedelta(seconds = round(float(time() - g.start_time)))}] " + str(text))
|
||||
|
||||
|
||||
# replace the function print, with more options
|
||||
# [txt] : string, [driver] : selenium webdriver
|
||||
def printf(txt):
|
||||
print(Timer(txt))
|
||||
|
||||
|
||||
# return current page domain
|
||||
def get_domain(driver):
|
||||
return(driver.current_url.split("/")[2])
|
||||
|
||||
|
||||
# check if the user is using IPV4 using ipify.org
|
||||
# [driver] : selenium webdriver
|
||||
# never used here
|
||||
# can be useful as Ms had issues with IPV6 at some point
|
||||
def check_ipv4(driver):
|
||||
driver.get("https://api64.ipify.org")
|
||||
elm = driver.find_element(By.TAG_NAME, "body")
|
||||
if len(elm.text.split('.')) == 4 :
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def custom_sleep(temps):
|
||||
try :
|
||||
if g.log : #only print sleep when user see it
|
||||
points = ["⢿", "⣻", "⣽", "⣾", "⣷", "⣯", "⣟", "⡿"]
|
||||
passe = 0
|
||||
for i in range(int(temps)):
|
||||
for i in range(8):
|
||||
sleep(0.125)
|
||||
passe += 0.125
|
||||
print(f"{points[i]} - {round(float(temps) - passe, 3)}", end="\r")
|
||||
print(" ", end="\r")
|
||||
else:
|
||||
sleep(temps)
|
||||
except KeyboardInterrupt :
|
||||
print("attente annulée")
|
||||
|
||||
|
||||
def format_error(e) -> str:
|
||||
tb = e.__traceback__
|
||||
txt = ""
|
||||
while tb != None :
|
||||
txt = txt + f" -> {tb.tb_frame.f_code.co_name} ({tb.tb_lineno}) "
|
||||
tb = tb.tb_next
|
||||
return(txt + "\n" + str(e))
|
||||
|
||||
|
||||
def progressBar(current, total=30, barLength=20, name="Progress"):
|
||||
percent = float(current + 1) * 100 / total
|
||||
arrow = "-" * int(percent / 100 * barLength - 1) + ">"
|
||||
spaces = " " * (barLength - len(arrow))
|
||||
print(name + ": [%s%s] %d %%" % (arrow, spaces, percent), end="\r")
|
||||
|
||||
|
||||
def save_points_from_file(file):
|
||||
with open(file) as f:
|
||||
read = reader(f)
|
||||
points_list = list(read)
|
||||
for item in points_list:
|
||||
compte, points = item[0], item[1]
|
||||
add_to_database(compte, points, g.sql_host,g.sql_usr,g.sql_pwd,g.sql_database, save_if_fail=False)
|
||||
with open(file, "w") as f:
|
||||
f.write("")
|
||||
|
||||
|
||||
def select_accounts(multiple = True):
|
||||
system("clear") # clear from previous command to allow a clean choice
|
||||
emails = [x[0] for x in g._cred] # list of all email adresses
|
||||
emails_selected = enquiries.choose(f"quel{'s' if multiple else ''} compte{'s' if multiple else ''} ?", emails, multi=multiple)
|
||||
return([x for x in g._cred if x[0] in emails_selected])
|
||||
|
Reference in New Issue
Block a user