forked from oyd/Adunatio
Compare commits
13 Commits
updateDock
...
master
Author | SHA1 | Date |
---|---|---|
Mustafa Yontar | 73a5820535 | 4 years ago |
Mustafa Yontar | 24b5ebc40a | 4 years ago |
Mustafa Yontar | 739497f824 | 4 years ago |
Mustafa Yontar | 5994f2a155 | 4 years ago |
Mustafa Yontar | 539ff5e2e5 | 4 years ago |
Mustafa Yontar | 7e15e570db | 4 years ago |
Özcan Oğuz | 5207e712bf | 4 years ago |
Özcan Oğuz | b57590b32f | 4 years ago |
Mustafa Yontar | ca49799d68 | 4 years ago |
Mustafa Yontar | 89aeb025f3 | 4 years ago |
Özcan Oğuz | 75d04c4268 | 4 years ago |
Özcan Oğuz | 1e90dec29e | 4 years ago |
murat emir cabaroğlu | 74fcc75ee9 | 4 years ago |
@ -0,0 +1,8 @@ |
||||
APP_SECRET=s3cr3tk3yh3r3 |
||||
FLASK_DEBUG=1 |
||||
|
||||
MONGO_HOST=mongo |
||||
MONGO_USER=username |
||||
MONGO_PASSWORD=Pa$$w0rD |
||||
|
||||
ADUNATIO_PRIV_KEY=privkey.pem |
@ -1,22 +1,52 @@ |
||||
from mongoengine import * |
||||
|
||||
from models.Union import Union |
||||
from restapi import Methods |
||||
|
||||
|
||||
class Group(Document): |
||||
meta = { |
||||
'index_background': True, |
||||
'index_cls': False, |
||||
'auto_create_index': True, |
||||
'can_query': True, |
||||
'with_sub_docs': True, |
||||
'methods': [Methods.Get, Methods.List, Methods.Create], |
||||
"indexes": [ |
||||
('name'), |
||||
("-name"), |
||||
("union","deleted"), |
||||
("union","deleted","name"), |
||||
], |
||||
} |
||||
union = ReferenceField(Union) |
||||
name = StringField() |
||||
rights = ListField(StringField()) |
||||
name = StringField(required=True) |
||||
rights = ListField(StringField(), required=True) |
||||
deleted = BooleanField(default=False) |
||||
|
||||
def __unicode__(self): |
||||
return "{} {}".format(self.union.name, self.name) |
||||
|
||||
|
||||
class PaymentGroup(Document): |
||||
meta = { |
||||
'index_background': True, |
||||
'index_cls': False, |
||||
'auto_create_index': True, |
||||
'can_query': True, |
||||
'with_sub_docs': True, |
||||
'methods': [Methods.Get, Methods.List, Methods.Create], |
||||
"indexes": [ |
||||
('name'), |
||||
("-name"), |
||||
("union"), |
||||
('union','name',"deleted") |
||||
], |
||||
} |
||||
union = ReferenceField(Union) |
||||
name = StringField() |
||||
name = StringField(required=True) |
||||
deleted = BooleanField(default=False) |
||||
discount_percent = IntField() |
||||
discount_percent = IntField(required=True) |
||||
|
||||
def __unicode__(self): |
||||
return "{} {}".format(self.union.name, self.name) |
@ -0,0 +1,331 @@ |
||||
from random import randint, choice |
||||
from string import ascii_lowercase |
||||
|
||||
from models.Account import Account |
||||
from models.Payment import Payments |
||||
from models.User import User |
||||
from scripts.generate_flutter_model import build_class |
||||
|
||||
|
||||
def mainBuilder(classlist): |
||||
blist = [] |
||||
for cls in classlist: |
||||
data = build_class(cls, blist) |
||||
blist = blist + data[1] |
||||
clstypeList = [i.__class__.__name__ for i in blist] |
||||
configlistNames = [] |
||||
for classItem in data[0]: |
||||
saveAction = "" |
||||
|
||||
imports = "import 'package:flutter/material.dart';\n" |
||||
imports += "import 'package:flutter/services.dart';\n" |
||||
imports += "import 'package:dio/dio.dart';\n" |
||||
imports += "import 'package:horde/widgets/HorusBox.dart';\n" |
||||
imports += "import 'package:dropdown_search/dropdown_search.dart';\n" |
||||
imports += "import '../Models.dart';\n" |
||||
controller = "" |
||||
controllerInit = "" |
||||
controllerDispose = "" |
||||
textFields = "" |
||||
for field in classItem.get('fields'): |
||||
if field.get('name') == "id": |
||||
continue |
||||
if field.get('autogen'): |
||||
continue |
||||
controller += "\tTextEditingController _{};\n".format(field.get('name')) |
||||
controllerInit += "\t\t_{} = new TextEditingController();\n".format(field.get('name')) |
||||
controllerDispose += "\t\t_{}.dispose();\n".format(field.get('name')) |
||||
req = "" |
||||
if field.get('required'): |
||||
req = """ |
||||
validator: (value) { |
||||
if (value.isEmpty) { |
||||
return 'Please enter some text'; |
||||
} |
||||
return null; |
||||
}, |
||||
""" |
||||
if field.get("is_class"): |
||||
|
||||
# imports += "import 'package:adunationfe/data/models/{}.dart';\n".format(field.get('class_name')) |
||||
if field.get('islist'): |
||||
if field.get('embeded') == False: |
||||
controller += "\t\tList<{classname}> item{name};\n".format( |
||||
classname=field.get('class_name'), |
||||
name=field.get('name')) |
||||
controllerInit += "\t\t\titem{name} = [];\n".format(name=field.get('name')) |
||||
saveAction += "\t\tnew{classname}.{name} = item{name};\n".format(name=field.get('name'), |
||||
classname=classItem.get( |
||||
'class')) |
||||
else: |
||||
imports += "import 'Form{}.dart';\n".format( |
||||
field.get('class_name')) |
||||
if field.get('class_name') not in configlistNames: |
||||
clsname = field.get('class_name') |
||||
configlistNames.append(field.get('class_name')) |
||||
else: |
||||
clsname = field.get('class_name') + ''.join( |
||||
[choice(ascii_lowercase) for i in range(randint(3, 6))]) |
||||
while clsname in configlistNames: |
||||
clsname = field.get('class_name') + ''.join( |
||||
[choice(ascii_lowercase) for i in range(randint(3, 6))]) |
||||
configlistNames.append(clsname) |
||||
saveAction += "\t\tnew{classname}.{name} = item{clist}List;\n".format(clist=clsname, |
||||
name=field.get( |
||||
'name'), |
||||
classname=classItem.get( |
||||
'class')) |
||||
controller += """ |
||||
List<{originclass}> item{classname}List = []; |
||||
|
||||
""".format(originclass=field.get("class_name"), classname=clsname) |
||||
textFields += """ |
||||
Padding(padding: EdgeInsets.only(left:40,right: 40), |
||||
child: Column( |
||||
children: [ |
||||
Text('{cname} list'), |
||||
Column( |
||||
children: List.generate(item{clsname}List.length, (index) {{ |
||||
return HorusBox( |
||||
child: |
||||
Row( |
||||
children: [ |
||||
Expanded(child: Text(item{clsname}List[index].name)), |
||||
GestureDetector( |
||||
onTap: () {{ |
||||
item{clsname}List.removeAt(index); |
||||
setState(() {{ |
||||
}}); |
||||
}}, |
||||
child: Icon(Icons.delete), |
||||
) |
||||
|
||||
], |
||||
) |
||||
, |
||||
); |
||||
}}), |
||||
) |
||||
], |
||||
), |
||||
|
||||
), |
||||
|
||||
ElevatedButton(onPressed: () |
||||
{{ |
||||
_showMaterialDialog(SingleChildScrollView(child:Container(width:500,height:500,child:new Form{classname}(onSave: ({classname} item) {{ |
||||
item{clsname}List.add(item); |
||||
Navigator.pop(context); |
||||
setState(() {{ |
||||
}}); |
||||
}}))),"Create {cname}"); |
||||
|
||||
|
||||
|
||||
}}, child: Text('Add {cname}')), |
||||
SizedBox( |
||||
height: 15, |
||||
), |
||||
|
||||
""".format(classname=field.get('class_name'), cname=field.get('name'), clsname=clsname) |
||||
elif field.get("embeded") == False: |
||||
controller += "\t\t{classname} item{name};\n".format(classname=field.get('class_name'), |
||||
name=field.get('name')) |
||||
saveAction += "\t\tnew{classname}.{name} = item{name};\n".format(name=field.get('name'), |
||||
classname=classItem.get( |
||||
'class')) |
||||
|
||||
controllerInit += "\t\t\titem{name} = {classname}();\n".format( |
||||
classname=field.get('class_name'), |
||||
name=field.get('name')) |
||||
|
||||
controller += "\t\tList<{classname}> {cname}List = [];".format( |
||||
classname=field.get('class_name'), cname=field.get('name')) |
||||
|
||||
controller += """ |
||||
Future<List<{classname}>> getData{classname}(filter) async {{ |
||||
print(filter); |
||||
var response = await Dio().get( |
||||
"${{apiurl}}/{cname}", |
||||
queryParameters: {{"{search}__contains": filter}}, |
||||
); |
||||
List<{classname}> models = []; |
||||
response.data.forEach((element) {{ |
||||
{classname} cn = {classname}(); |
||||
cn.name = element['{search}']; |
||||
models.add(cn); |
||||
}}); |
||||
|
||||
return models; |
||||
}} |
||||
""".format(classname=field.get('class_name'), cname=field.get('name'), |
||||
search=field.get('search_field')) |
||||
textFields += """ |
||||
DropdownSearch<{classname}>( |
||||
mode: Mode.BOTTOM_SHEET, |
||||
showSearchBox: true, |
||||
onFind: (String filter) => getData{classname}(filter), |
||||
items: [], |
||||
itemAsString: ({classname} u) => u.{search}, |
||||
isFilteredOnline: true, |
||||
autoValidateMode: AutovalidateMode.onUserInteraction, |
||||
validator: ({classname} u) => |
||||
u == null ? "field is required " : null, |
||||
hint: "{cname} in menu mode", |
||||
onChanged: ({classname} selected) {{ |
||||
item{cname} = selected; |
||||
setState(() {{ |
||||
}}); |
||||
}}), |
||||
SizedBox( |
||||
height: 15, |
||||
), |
||||
""".format(classname=field.get('class_name'), cname=field.get('name'), |
||||
search=field.get('search_field')) |
||||
elif field.get("embeded"): |
||||
imports += "import 'Form{}.dart';\n".format( |
||||
field.get('class_name')) |
||||
saveAction += "\t\tif(!_key{classname}.currentState.build{classname}()) return false;\n".format( |
||||
classname=field.get('class_name')) |
||||
saveAction += "\t\tnew{cname}.{name} = _key{classname}.currentState.new{classname};\n".format( |
||||
classname=field.get('class_name'), name=field.get('name'), cname=classItem.get('class')) |
||||
|
||||
textFields += "Form{classname}(key:_key{classname}),".format(classname=field.get('class_name')) |
||||
controller += "\tGlobalKey<Form{}State> _key{} = GlobalKey();\n".format(field.get('class_name'), |
||||
field.get('class_name')) |
||||
elif field.get('choices'): |
||||
saveAction += "\t\tnew{classname}.{name} = _{name}.text;\n".format(name=field.get('name'), |
||||
classname=classItem.get('class')) |
||||
|
||||
imports += "import 'package:dropdown_search/dropdown_search.dart';\n" |
||||
textFields += """ |
||||
DropdownSearch<String>( |
||||
mode: Mode.BOTTOM_SHEET, |
||||
showClearButton: true, |
||||
showSearchBox: true, |
||||
label: '{name}', |
||||
showSelectedItem: true, |
||||
items: ['{items}'], |
||||
hint: "country in menu mode", |
||||
onChanged: print, |
||||
selectedItem: "") |
||||
, |
||||
SizedBox( |
||||
height: 15, |
||||
), |
||||
""".format(items="','".join(field.get('choices')), name=field.get('name')) |
||||
elif field.get('type') == 'String': |
||||
saveAction += "\t\tnew{classname}.{name} = _{name}.text;\n".format(name=field.get('name'), |
||||
classname=classItem.get('class')) |
||||
|
||||
textFields += """ |
||||
new TextFormField( |
||||
decoration: new InputDecoration(labelText: "Enter your {name}"), |
||||
controller: _{name}, |
||||
{req} |
||||
), |
||||
SizedBox( |
||||
height: 15, |
||||
), |
||||
""".format(name=field.get('name'), req=req) |
||||
elif field.get('type') == 'int': |
||||
saveAction += "\t\tnew{classname}.{name} = int.tryParse(_{name}.text);\n".format( |
||||
name=field.get('name'), |
||||
classname=classItem.get('class')) |
||||
|
||||
textFields += """ |
||||
new TextFormField( |
||||
decoration: new InputDecoration(labelText: "Enter your {name}"), |
||||
controller: _{name}, |
||||
keyboardType: TextInputType.number, |
||||
inputFormatters: < TextInputFormatter > [ |
||||
FilteringTextInputFormatter.digitsOnly |
||||
], |
||||
{req} |
||||
), |
||||
SizedBox( |
||||
height: 15, |
||||
), |
||||
""".format(name=field.get('name'), req=req) |
||||
# elif field.get('is_class'): |
||||
# print(field) |
||||
# # exit() |
||||
|
||||
cls_text = """ |
||||
{imports} |
||||
class Form{classname} extends StatefulWidget {{ |
||||
final Function onSave; |
||||
|
||||
|
||||
const Form{classname}({{Key key, this.onSave}}) : super(key: key); |
||||
@override |
||||
Form{classname}State createState() => Form{classname}State(); |
||||
}} |
||||
class Form{classname}State extends State<Form{classname}> {{ |
||||
{controller} |
||||
var apiurl = ""; |
||||
{classname} new{classname} = new {classname}(); |
||||
|
||||
bool build{classname}() {{ |
||||
if (_{classname}.currentState.validate()) {{ |
||||
{saveact} |
||||
widget.onSave(new{classname}); |
||||
return true; |
||||
}} |
||||
return false; |
||||
}} |
||||
_showMaterialDialog(content, title) {{ |
||||
showDialog( |
||||
context: context, |
||||
builder: (_) => new AlertDialog( |
||||
title: new Text(title), |
||||
content: content, |
||||
)); |
||||
}} |
||||
|
||||
final _{classname} = GlobalKey<FormState>(); |
||||
@override |
||||
void initState() {{ |
||||
{initdata} |
||||
super.initState(); |
||||
}} |
||||
@override |
||||
void dispose() {{ |
||||
{dispose} |
||||
super.dispose(); |
||||
}} |
||||
@override |
||||
Widget build(BuildContext context) {{ |
||||
return new Form( |
||||
key:_{classname}, |
||||
child:new Column( |
||||
mainAxisAlignment: MainAxisAlignment.center, |
||||
children: <Widget>[ |
||||
{textfield} |
||||
Row( |
||||
children: [ |
||||
widget.onSave !=null ? ElevatedButton( |
||||
child: Text('Save'), |
||||
onPressed: () {{ |
||||
build{classname}(); |
||||
}}, |
||||
): Center() |
||||
], |
||||
) |
||||
]) |
||||
); |
||||
}} |
||||
|
||||
}} |
||||
|
||||
""".format(imports=imports, classname=classItem.get('class'), controller=controller, |
||||
initdata=controllerInit, dispose=controllerDispose, textfield=textFields, saveact=saveAction) |
||||
|
||||
f = open("flutter_out/Form{}.dart".format(classItem.get('class')), "w+") |
||||
f.write(cls_text) |
||||
f.close() |
||||
import os |
||||
os.chdir('../') |
||||
print(os.getcwd()) |
||||
mainBuilder([User, Payments, Account]) |
||||
os.system("flutter format flutter_out/") |
@ -0,0 +1,212 @@ |
||||
import mongoengine |
||||
import os |
||||
|
||||
from models.Account import Account |
||||
from models.Payment import Payments |
||||
from models.User import * |
||||
from mongoengine import fields |
||||
types = { |
||||
mongoengine.fields.StringField: "String", |
||||
IntField: 'int', |
||||
BooleanField: 'bool', |
||||
FloatField: 'Float', |
||||
DictField: 'Map<String,dynamic>' |
||||
} |
||||
|
||||
|
||||
def to_camel_case(snake_str): |
||||
components = snake_str.split('_') |
||||
# We capitalize the first letter of each component except the first one |
||||
# with the 'title' method and join them together. |
||||
return components[0] + ''.join(x.title() for x in components[1:]) |
||||
|
||||
|
||||
def buildReferenceField(field_object, builded): |
||||
if isinstance(field_object, (ReferenceField, EmbeddedDocumentField)): |
||||
if field_object.document_type not in builded: |
||||
builded.append(field_object.document_type) |
||||
return build_class(field_object.document_type, builded) |
||||
return None, builded |
||||
|
||||
else: |
||||
return None, builded |
||||
|
||||
|
||||
def buildFields(field_object): |
||||
type = "" |
||||
if isinstance(field_object, mongoengine.fields.LongField): |
||||
type = "long" |
||||
elif isinstance(field_object, EncryptedStringField): |
||||
type = "String" |
||||
elif isinstance(field_object, fields.ImageField): |
||||
type = "String" |
||||
elif isinstance(field_object, EncryptedStringField): |
||||
type = "String" |
||||
elif isinstance(field_object, StringField): |
||||
type = "String" |
||||
elif isinstance(field_object, ObjectIdField): |
||||
type = "String" |
||||
elif isinstance(field_object, DateTimeField): |
||||
type = "DateTime" |
||||
elif isinstance(field_object, IntField): |
||||
type = "int" |
||||
elif isinstance(field_object, BooleanField): |
||||
type = "bool" |
||||
|
||||
elif isinstance(field_object, FloatField): |
||||
type = "double" |
||||
elif isinstance(field_object, DictField): |
||||
type = "Map<String,dynamic>" |
||||
elif isinstance(field_object, DynamicField): |
||||
type = "dynamic" |
||||
else: |
||||
type = "String" |
||||
return type |
||||
|
||||
|
||||
def build_class(mongoClass, builded): |
||||
if builded is None: |
||||
builded = [] |
||||
mClass = mongoClass |
||||
builded.append(mClass) |
||||
rClass = mongoClass() |
||||
builded.append(rClass) |
||||
class_list = [] |
||||
field_list = [] |
||||
for field in rClass._fields_ordered: |
||||
field_object = getattr(mClass, field) |
||||
ignore_fields = mClass._meta.get('ignore_fields') |
||||
autogen_fields = mClass._meta.get('auto_generated') |
||||
if not ignore_fields: |
||||
ignore_fields = [] |
||||
if not autogen_fields: |
||||
autogen_fields = [] |
||||
|
||||
if isinstance(field_object, (ReferenceField, EmbeddedDocumentField)): |
||||
_, builded = buildReferenceField(field_object, builded) |
||||
if _ is not None: |
||||
class_list = class_list + list(_) |
||||
pn = field_object.document_type() |
||||
if field not in ignore_fields: |
||||
field_list.append( |
||||
{"type": pn._class_name, "origin_name": field, "name": to_camel_case(field), "islist": False, |
||||
"is_class": True, "required":field_object.required, "class_name": pn._class_name, "autogen": field in autogen_fields}) |
||||
|
||||
elif isinstance(field_object, ListField): |
||||
if isinstance(field_object.field, (ReferenceField, EmbeddedDocumentField)): |
||||
_, builded = buildReferenceField(field_object.field, builded) |
||||
|
||||
if _ is not None: |
||||
class_list = class_list + list(_) |
||||
pn = field_object.field.document_type() |
||||
if field not in ignore_fields: |
||||
|
||||
field_list.append( |
||||
{"type": "List<{}>".format(pn._class_name), "origin_name": field, "name": to_camel_case(field), |
||||
"islist": True, "is_class": True, "required":field_object.required, "class_name": pn._class_name, "autogen": field in autogen_fields}) |
||||
|
||||
|
||||
else: |
||||
type = buildFields(field_object.field) |
||||
if field not in ignore_fields: |
||||
|
||||
field_list.append({"type": "List<{}>".format(type), "name": to_camel_case(field), "origin_name": field, |
||||
"islist": True, "originType": field_object.field, "required":field_object.required, "autogen": field in autogen_fields,"choices":field_object.field.choices}) |
||||
|
||||
else: |
||||
type = buildFields(field_object) |
||||
if field not in ignore_fields: |
||||
chc = None |
||||
req = False |
||||
if field_object is not None: |
||||
chc = field_object.choices |
||||
req = field_object.required |
||||
field_list.append( |
||||
{"type": "{}".format(type), "name": to_camel_case(field), "origin_name": field, "islist": False, |
||||
"originType": field_object, "autogen": field in autogen_fields,"choices":chc,"required":req}) |
||||
class_list.append({'class': rClass._class_name, "fields": field_list}) |
||||
return class_list, builded |
||||
|
||||
f = None |
||||
|
||||
def print(item): |
||||
if f: |
||||
f.writelines(str(item) + "\n") |
||||
|
||||
def buildFunctionFromJson(fields): |
||||
print("\t void fromJson(data) {") |
||||
|
||||
for i in fields: |
||||
if i.get('type') != "DateTime": |
||||
if not i.get('islist') and not i.get('is_class'): |
||||
print("\t\tthis.{} = data[\"{}\"];".format(i.get('name'), i.get("origin_name"))) |
||||
elif i.get('islist') and not i.get('is_class'): |
||||
print("\t\tthis.{}=[];".format(i.get('name'))); |
||||
print("\t\tdata[\"{}\"].forEach((element)".format(i.get("origin_name"))) |
||||
print("\t\t{") |
||||
print("\t\t\tthis.{}.add(element);".format(i.get('name'))) |
||||
print("\t\t}" |
||||
");") |
||||
elif not i.get('islist') and i.get('is_class'): |
||||
print("\t\tthis.{} = {}();".format(i.get('name'), i.get('class_name'))) |
||||
print("\t\tthis.{}.fromJson(data[\"{}\"]);".format(i.get('name'), i.get('origin_name'))) |
||||
else: |
||||
print("\t\tthis.{}=[];".format(i.get('name'))); |
||||
print("\t\tdata[\"{}\"].forEach((element)".format(i.get("origin_name"))) |
||||
print("\t\t{") |
||||
print("\t\t\t{cname} cls = {cname}();".format(cname=i.get('class_name'))) |
||||
print("\t\t\tcls.fromJson(data[\"{}\"]);".format(i.get('origin_name'))) |
||||
|
||||
print("\t\t\tthis.{}.add(cls);".format(i.get('name'))) |
||||
print("\t\t}" |
||||
");") |
||||
|
||||
print("\t}") |
||||
|
||||
|
||||
def exportJson(fields): |
||||
print("\tMap<String,dynamic> toJson() {") |
||||
print("\t\tMap<String,dynamic> output = {};") |
||||
for i in fields: |
||||
if i.get('type') != "DateTime": |
||||
if not i.get('islist') and not i.get('is_class'): |
||||
print("\t\toutput[\"{}\"] = this.{};".format(i.get('origin_name'), i.get("name"))) |
||||
elif i.get('islist') and not i.get('is_class'): |
||||
print("\t\toutput[\"{}\"] = [];".format(i.get('origin_name'))) |
||||
print("\t\tthis.{}.forEach((element) => output[\"{}\"].add(element));".format(i.get('name'),i.get('origin_name'))) |
||||
elif i.get('islist') and i.get('is_class'): |
||||
print("\t\toutput[\"{}\"] = [];".format(i.get('origin_name'))) |
||||
print("\t\tthis.{}.forEach((element) => output[\"{}\"].add(element.toJson()));".format(i.get('name'), |
||||
i.get('origin_name'))) |
||||
elif not i.get('islist') and i.get('is_class'): |
||||
print("\t\toutput[\"{}\"] = this.{}.toJson();".format(i.get('origin_name'),i.get('name'))) |
||||
print("\t\treturn output;") |
||||
print("\t}") |
||||
|
||||
|
||||
|
||||
|
||||
def mainBuilder(classlist): |
||||
global f |
||||
blist = [] |
||||
for cls in classlist: |
||||
data = build_class(cls,blist) |
||||
blist = blist + data[1] |
||||
for i in data[0]: |
||||
f = open('flutter_out/{}.dart'.format(i.get('class')),"w") |
||||
print("import 'package:scoped_model/scoped_model.dart';") |
||||
print("class {} extends Model ".format(i.get('class'))) |
||||
print("{") |
||||
for field in i.get('fields'): |
||||
print("\t {} {};".format(field.get('type'), field.get('name'))) |
||||
print("") |
||||
print("\t// Build Functions") |
||||
print("\t// ") |
||||
buildFunctionFromJson(i.get('fields')) |
||||
exportJson(i.get('fields')) |
||||
print("}") |
||||
if __name__ == '__main__': |
||||
import os |
||||
os.chdir('../') |
||||
print(os.getcwd()) |
||||
mainBuilder([User, Payments, Account]) |
Loading…
Reference in new issue