Skip to content

Commit 537429e

Browse files
authored
Merge pull request #533 from MerginMaps/develop
Develop
2 parents 6e59b27 + 16aeab3 commit 537429e

29 files changed

Lines changed: 1985 additions & 542 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
projects*/
33
data/
44
mergin_db
5+
diagnostic_logs
56

67
logs
78
*.log

deployment/common/set_permissions.sh

100644100755
File mode changed.

development.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ cd deployment/community/
7171
# Create .prod.env file from .env.template
7272
cp .env.template .prod.env
7373

74-
# Run the docker composition with the current Dockerfiles
75-
cp .env.template .prod.env
7674
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d
7775

7876
# Give ownership of the ./projects folder to user that is running the gunicorn container

server/Pipfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ flask-migrate = "==2.6.0" # 3.1.0
2626
wtforms-json = "==0.3.5"
2727
pytz = "==2022.2.1"
2828
scikit-build = "==0.18.1"
29-
pygeodiff = "==1.0.6"
29+
pygeodiff = "==2.0.4"
3030
pathvalidate = "==3.2.0"
3131
celery= "==5.4.0"
3232
redis= "==5.0.1"
@@ -40,6 +40,7 @@ psycogreen = "==1.0.2"
4040
importlib-metadata = "==8.4.0" # https://github.com/pallets/flask/issues/4502
4141
typing_extensions = "==4.12.2"
4242
python-magic = "==0.4.27"
43+
click = "==8.2.0"
4344
# requirements for development on windows
4445
colorama = "==0.4.5"
4546

server/Pipfile.lock

Lines changed: 77 additions & 43 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/application.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
remove_projects_archives,
2828
remove_temp_files,
2929
remove_projects_backups,
30+
remove_unused_chunks,
3031
)
3132
from mergin.celery import celery, configure_celery
3233
from mergin.stats.config import Configuration
@@ -47,6 +48,7 @@
4748
"GLOBAL_WRITE",
4849
"ENABLE_SUPERADMIN_ASSIGNMENT",
4950
"DIAGNOSTIC_LOGS_URL",
51+
"V2_PUSH_ENABLED",
5052
]
5153
)
5254
register_stats(application)
@@ -85,4 +87,9 @@ def setup_periodic_tasks(sender, **kwargs):
8587
crontab(hour=3, minute=0),
8688
remove_projects_archives,
8789
name="remove old project archives",
90+
),
91+
sender.add_periodic_task(
92+
crontab(hour="*/4", minute=0),
93+
remove_unused_chunks,
94+
name="clean up of outdated chunks",
8895
)

server/mergin/app.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,17 @@
1212
from sqlalchemy.schema import MetaData
1313
from flask_sqlalchemy import SQLAlchemy
1414
from flask_marshmallow import Marshmallow
15-
from flask import json, jsonify, request, abort, current_app, Flask, Request, Response
15+
from flask import (
16+
json,
17+
jsonify,
18+
make_response,
19+
request,
20+
abort,
21+
current_app,
22+
Flask,
23+
Request,
24+
Response,
25+
)
1626
from flask_login import current_user, LoginManager
1727
from flask_wtf.csrf import generate_csrf, CSRFProtect
1828
from flask_migrate import Migrate
@@ -25,7 +35,7 @@
2535
import time
2636
import traceback
2737
from werkzeug.exceptions import HTTPException
28-
from typing import List, Dict, Optional
38+
from typing import List, Dict, Optional, Tuple
2939

3040
from .sync.utils import get_blacklisted_dirs, get_blacklisted_files
3141
from .config import Configuration
@@ -347,6 +357,16 @@ def ping(): # pylint: disable=W0612
347357
)
348358
return status, 200
349359

360+
# reading raw input stream not supported in connexion so far
361+
# https://github.com/zalando/connexion/issues/592
362+
# and as workaround we use custom Flask endpoint in create_app function
363+
@app.route("/v2/projects/<id>/chunks", methods=["POST"])
364+
@auth_required
365+
def upload_chunk_v2(id: str):
366+
from .sync import public_api_v2_controller
367+
368+
return public_api_v2_controller.upload_chunk(id)
369+
350370
# reading raw input stream not supported in connexion so far
351371
# https://github.com/zalando/connexion/issues/592
352372
# and as workaround we use custom Flask endpoint in create_app function
@@ -485,6 +505,12 @@ class ResponseError:
485505
def to_dict(self) -> Dict:
486506
return dict(code=self.code, detail=self.detail + f" ({self.code})")
487507

508+
def response(self, status_code: int) -> Tuple[Response, int]:
509+
"""Returns a custom error response with the given code."""
510+
response = make_response(jsonify(self.to_dict()), status_code)
511+
response.headers["Content-Type"] = "application/problem+json"
512+
return response, status_code
513+
488514

489515
def whitespace_filter(obj):
490516
return obj.strip() if isinstance(obj, str) else obj

server/mergin/sync/commands.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
from flask import Flask, current_app
1212
from sqlalchemy import func
1313

14-
from .files import UploadChanges
1514
from ..app import db
1615
from .models import Project, ProjectVersion
1716
from .utils import split_project_path
@@ -55,8 +54,8 @@ def create(name, namespace, username): # pylint: disable=W0612
5554
p = Project(**project_params)
5655
p.updated = datetime.utcnow()
5756
db.session.add(p)
58-
changes = UploadChanges(added=[], updated=[], removed=[])
59-
pv = ProjectVersion(p, 0, user.id, changes, "127.0.0.1")
57+
pv = ProjectVersion(p, 0, user.id, [], "127.0.0.1")
58+
pv.project = p
6059
db.session.add(pv)
6160
db.session.commit()
6261
os.makedirs(p.storage.project_dir, exist_ok=True)

server/mergin/sync/config.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,14 @@ class Configuration(object):
6464
)
6565
# in seconds, older unfinished zips are moved to temp
6666
PARTIAL_ZIP_EXPIRATION = config("PARTIAL_ZIP_EXPIRATION", default=600, cast=int)
67+
# whether new push is allowed
68+
V2_PUSH_ENABLED = config("V2_PUSH_ENABLED", default=True, cast=bool)
69+
# directory for file chunks
70+
UPLOAD_CHUNKS_DIR = config(
71+
"UPLOAD_CHUNKS_DIR",
72+
default=os.path.join(LOCAL_PROJECTS, "chunks"),
73+
)
74+
# time in seconds after chunks are permanently deleted (1 day)
75+
UPLOAD_CHUNKS_EXPIRATION = config(
76+
"UPLOAD_CHUNKS_EXPIRATION", default=86400, cast=int
77+
)

server/mergin/sync/db_events.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
from flask import current_app, abort
77
from sqlalchemy import event
88

9+
from .models import ProjectVersion
10+
from .tasks import optimize_storage
911
from ..app import db
1012

1113

@@ -14,9 +16,17 @@ def check(session):
1416
abort(503, "Service unavailable due to maintenance, please try later")
1517

1618

19+
def optimize_gpgk_storage(mapper, connection, project_version):
20+
# do not optimize on every version, every 10th is just fine
21+
if not project_version.name % 10:
22+
optimize_storage.delay(project_version.project_id)
23+
24+
1725
def register_events():
1826
event.listen(db.session, "before_commit", check)
27+
event.listen(ProjectVersion, "after_insert", optimize_gpgk_storage)
1928

2029

2130
def remove_events():
2231
event.remove(db.session, "before_commit", check)
32+
event.listen(ProjectVersion, "after_insert", optimize_gpgk_storage)

0 commit comments

Comments
 (0)