paramecio2fm/paramecio2/console.py

411 lines
15 KiB
Python
Executable file

#!/usr/bin/env python3
"""
Paramecio2fm is a series of wrappers for Flask, mako and others and construct a simple headless cms.
Copyright (C) 2023 Antonio de la Rosa Caballero
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import argparse
import os
import shutil
import getpass
import re
from pathlib import Path
from base64 import b64encode
from paramecio2.libraries.db.webmodel import WebModel
from paramecio2.modules.admin.models.admin import UserAdmin, LoginTries
from subprocess import call
from urllib.parse import urlparse
def start():
parser=argparse.ArgumentParser(prog='paramecio2', description='A tool for create new paramecio2 sites')
parser.add_argument('--path', help='The path where the paramecio site is located', required=True)
parser.add_argument('--modules', help='A list separated by commas with the git repos for download modules for this site', required=False)
parser.add_argument('--symlink', help='Set if create direct symlink to paramecio in new site', action='store_true')
parser.add_argument('--tests', help='Create a symlink to tests for check into paramecio site', action='store_true')
# Options for deploy
parser.add_argument('--url', help='The http/https base url of the real proxy server. Example: https://www.exampledomain.com, default is http://localhost:5000', required=False)
parser.add_argument('--folder', help='If you deploy in a subdirectory, set it, without beggining and ending slashes', required=False)
parser.add_argument('--host', help='The host ip or domain where the app is binded', required=False)
parser.add_argument('--port', help='Change the default port 8080 to other number. Use 80 is not recommended, use 80 for the proxy server how nginx or apache', required=False)
args=parser.parse_args()
#print(args)
#exit(0)
workdir=os.path.dirname(os.path.abspath(__file__))
# Create directory
path=Path(args.path)
try:
path.mkdir(0o755, True)
except:
print('Error: cannot create the directory. Check if exists and if you have permissions')
exit()
# Create folder settings and copy app.py, admin.py
path_settings=args.path+'/settings'
try:
os.mkdir(path_settings, 0o755)
except:
print('Error: cannot create the directory. Check if exists and if you have permissions')
# Copy the files. Need optimization, use an array for save the filenames and a simple for loop.
try:
shutil.copy(workdir+'/config.py.sample', path_settings+'/config.py')
except:
print('Error: cannot copy the file config.py. Check if exists and if you have permissions for this task')
try:
shutil.copy(workdir+'/frontend/app.py', args.path+'/app.py')
except:
print('Error: cannot copy the file index.py to app.py. Check if exists and if you have permissions for this task')
if args.symlink==True:
try:
os.symlink(workdir, args.path+'/paramecio2', True)
except:
print('Error: cannot symlink paramecio in new site')
if args.tests==True:
try:
os.symlink(workdir, args.path+'/paramecio2/', True)
except:
print('Error: cannot symlink paramecio2 in new site')
with open(path_settings+'/config.py', 'r') as f:
conf=f.read()
random_bytes = os.urandom(24)
secret_key_session = b64encode(random_bytes).decode('utf-8').strip()
conf=conf.replace('im smoking fool', secret_key_session)
#domain='localhost'
#conf=conf.replace("domain='localhost'", "domain='"+args.url+"'")
"""
if args.host==None:
args.host='localhost'
conf=conf.replace("host='localhost'", "host='"+args.host+"'")
if args.port==None:
args.port='8080'
conf=conf.replace("port=8080", "port="+args.port)
"""
base_url='/'
if args.folder==None:
args.folder=''
else:
#args.folder='/'+args.folder
base_url='/'+args.folder+'/'
conf=conf.replace("application_root='/'", "application_root='"+base_url+"'")
if args.url==None:
args.url='http://localhost:5000'
domain_url=args.url
conf=conf.replace("domain_url='http://localhost:5000'", "domain_url='"+domain_url+"'")
# Question about email
e_q=input('Email for site: ')
conf=conf.replace("no-reply@example.com", e_q)
#if e_q=='':
#domain_url='http://localhost:8080'
with open(path_settings+'/config.py', 'w') as f:
f.write(conf)
# Question about mysql configuration? If yes, install configuration
s=input('Do you want use paramecio with MySQL database? y/n: ')
if s=='y' or s=='Y':
host_db=input('MySQL database server host, by default localhost: ').strip()
db=input('MySQL database name, by default paramecio_db: ').strip()
user_db=input('MySQL database user, by default root: ').strip()
pass_db=getpass.getpass('MySQL database password, by default "": ').strip()
if host_db=='':
host_db='localhost'
if user_db=='':
user_db='root'
#user=UserAdmin()
#Create db
if db=="":
db='paramecio_db'
WebModel.connections={'default': {'name': 'default', 'host': host_db, 'user': user_db, 'password': pass_db, 'db': '', 'charset': 'utf8mb4', 'set_connection': False, 'db_type': 'pymysql'} }
connection_code="WebModel.connections={'default': {'name': 'default', 'host': '"+host_db+"', 'user': '"+user_db+"', 'password': '"+pass_db+"', 'db': '"+db+"', 'charset': 'utf8mb4', 'set_connection': False, 'db_type': 'pymysql'} }"
with open(path_settings+'/config.py', 'a') as f:
f.write("\n\n"+connection_code)
f.close()
sql='create database '+db
conn=WebModel.connection()
useradmin=UserAdmin(conn)
logintries=LoginTries(conn)
# Check if db exists
c=0
with useradmin.query('SHOW DATABASES LIKE "%s"' % db) as cur:
c=cur.rowcount
if c==0:
useradmin.query(sql)
#print('Error: cannot create database or db doesn\'t exists, check database permissions for this user')
#if not useradmin.query(sql):
#print('Error: cannot create database, check the data of database')
#else:
useradmin.query('use '+db)
admin=input('Do you want create admin site? y/n: ')
if admin=='y' or admin=='Y':
try:
#shutil.copy(workdir+'/settings/modules.py.admin', path_settings+'/modules.py')
#shutil.copy(workdir+'/settings/config_admin.py.sample', path_settings+'/config_admin.py')
sql=useradmin.create_table()
if not useradmin.query(sql):
print('Error: cannot create table admin, you can create this table with padmin.py')
else:
sql_login=logintries.create_table()
logintries.query(sql_login)
# Add admin module to config
with open(path_settings+'/config.py', 'r') as f:
config_text=f.read()
f.close()
#apps={'welcome': ['paramecio2.modules.welcome', 'welcome_app', '/'], 'admin': ['paramecio2.modules.admin', 'admin_app', '/']}
config_text=config_text.replace("apps={'welcome': ['paramecio2.modules.welcome', 'welcome_app', '/']}", "apps={'welcome': ['paramecio2.modules.welcome', 'welcome_app', '/'], 'admin': ['paramecio2.modules.admin', 'admin_app', '/']}")
with open(path_settings+'/config.py', 'w') as f:
f.write(config_text)
f.close()
"""
try:
shutil.copy(workdir+'/settings/modules.py.admin', path_settings+'/modules.py')
except:
print('Error: cannot copy the file modules.py. Check if exists and if you have permissions for this task')
"""
print('Created admin site...')
except:
print('Error: cannot create the database. Check if tables exists in it and if you have permissions for this task')
exit(1)
pass
# Install modules
if args.modules!=None:
if args.modules.strip()!='':
arr_modules=args.modules.split(',')
final_modules=[]
final_modules_models=[]
if len(arr_modules)>0:
for k, module in enumerate(arr_modules):
module=module.strip()
try:
u=urlparse(module)
module_path=os.path.basename(u.path)
except:
print('Error: not valid url for repository')
exit(1)
if call("git clone %s %s/modules/%s" % (module, path, module_path), shell=True) > 0:
print('Error, cannot install the module %s' % module_path)
exit(1)
else:
print('Added module %s' % module_path)
final_modules.append(("modules/%s" % (module_path)).replace('/', '.'))
final_modules_models.append("modules/%s" % (module_path))
# Edit config.py
with open(path_settings+'/config.py') as f:
modules_final='\''+'\', \''.join(final_modules)+'\''
p=re.compile(r"^modules=\[(.*)\]$")
#config_file=p.sub(r"modules=[\1, "+modules_final+"]", "modules=['paramecio.modules.welcome', 'paramecio.modules.admin', 'paramecio.modules.lang', 'modules.pastafari', 'modules.monit', 'modules.example']")
final_config=''
for line in f:
if p.match(line):
line=p.sub(r"modules=[\1, "+modules_final+"]", line)
final_config+=line
with open(path_settings+'/config.py', 'w') as f:
f.write(final_config)
print('Updated configuration for add new modules...')
#Change workdir
real_dir=os.getcwd()
os.chdir(args.path)
# Installing models
padmin='paramecio2db'
os.chmod(padmin, 0o755)
for mod_path in final_modules_models:
models_path=mod_path+'/models'
if os.path.isdir(models_path):
models_files=os.listdir(models_path)
m=re.compile(r".*\.py$")
underscore=re.compile("^__.*")
for f in models_files:
if m.match(f) and not underscore.match(f):
if call('paramecio2db --model '+models_path+'/'+f, shell=True) > 0:
print('Error, cannot create the modules of '+models_path+'/'+f)
else:
print('Models from '+models_path+'/'+f+' created')
# Execute two times the loop because i can need good installed models for postscript script
# Execute postscript
print('Executing postscripts')
for mod_path in final_modules_models:
postscript=mod_path+"/install/postinstall.py"
os.chmod(padmin, 0o755)
if os.path.isfile(postscript):
os.chmod(postscript, 0o755)
if call('./'+postscript, shell=True) > 0:
print('Error, cannot execute the postinstall script')
exit(1)
else:
print('Postinstall script finished')
conn.close()
if __name__=="__main__":
start()