diff --git a/CTFd/__init__.py b/CTFd/__init__.py index 1dd466c0..63fd3473 100644 --- a/CTFd/__init__.py +++ b/CTFd/__init__.py @@ -41,14 +41,20 @@ def create_app(config='CTFd.config.Config'): if url.drivername == 'postgres': url.drivername = 'postgresql' + if url.drivername.startswith('mysql'): + url.query['charset'] = 'utf8mb4' + # Creates database if the database database does not exist if not database_exists(url): if url.drivername.startswith('mysql'): - url.query['charset'] = 'utf8mb4' create_database(url, encoding='utf8mb4') else: create_database(url) + # This allows any changes to the SQLALCHEMY_DATABASE_URI to get pushed back in + # This is mostly so we can force MySQL's charset + app.config['SQLALCHEMY_DATABASE_URI'] = str(url) + # Register database db.init_app(app) diff --git a/CTFd/admin/__init__.py b/CTFd/admin/__init__.py index 2775dff0..cd40e896 100644 --- a/CTFd/admin/__init__.py +++ b/CTFd/admin/__init__.py @@ -63,11 +63,8 @@ def admin_import_ctf(): import_ctf(backup, segments=segments.split(',')) else: import_ctf(backup) - except TypeError: - errors.append('The backup file is invalid') - except IntegrityError as e: - errors.append(e.message) except Exception as e: + print(e) errors.append(type(e).__name__) if errors: diff --git a/CTFd/utils.py b/CTFd/utils.py index d785c179..ac4f3681 100644 --- a/CTFd/utils.py +++ b/CTFd/utils.py @@ -792,6 +792,15 @@ def import_ctf(backup, segments=None, erase=False): saved = json.loads(data) for entry in saved['results']: entry_id = entry.pop('id', None) + # This is a hack to get SQlite to properly accept datetime values from dataset + # See Issue #246 + if get_config('SQLALCHEMY_DATABASE_URI').startswith('sqlite'): + for k, v in entry.items(): + if isinstance(v, six.string_types): + try: + entry[k] = datetime.datetime.strptime(v, '%Y-%m-%dT%H:%M:%S') + except ValueError as e: + pass table.insert(entry) else: continue diff --git a/export.py b/export.py new file mode 100644 index 00000000..7d62895a --- /dev/null +++ b/export.py @@ -0,0 +1,23 @@ +from CTFd import create_app +from CTFd.utils import ctf_name, export_ctf + +import datetime +import sys +import shutil +import zipfile + + +app = create_app() +with app.app_context(): + backup = export_ctf() + + if len(sys.argv) > 1: + with open(sys.argv[1], 'wb') as target: + shutil.copyfileobj(backup, target) + else: + ctf_name = ctf_name() + day = datetime.datetime.now().strftime("%Y-%m-%d") + full_name = "{}.{}.zip".format(ctf_name, day) + + with open(full_name, 'wb') as target: + shutil.copyfileobj(backup, target)