Skip to content

Commit de2f3e7

Browse files
committed
Merge remote-tracking branch 'origin/develop' into dev-r84-concurrent-push
2 parents 640f578 + 0bddcfa commit de2f3e7

31 files changed

Lines changed: 1138 additions & 346 deletions

File tree

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ You are currently browsing repository for Mergin Maps web server and web client.
4747
- 🌱 **Sharing with collaborators** - Projects can be shared with other team members
4848
- 🏰 **Permission system** - Decide who can read, write or manage projects
4949
- 🌈 **Web interface** - Simple user interface to view and manage projects
50-
- ⚡️ **Fast** - Efficient sync protocol transfering data between clients and server
50+
- ⚡️ **Fast** - Efficient sync protocol transferring data between clients and server
5151
- 🧑‍💻 **Developer friendly** - Mergin Maps is open platform. CLI tools and client libraries are available for [Python](https://github.com/MerginMaps/python-api-client) and [C++](https://github.com/MerginMaps/cpp-api-client)
5252
- :camera: **Sync images** - Supporting sync of photos with common cloud storage using [mergin-media-sync](https://github.com/MerginMaps/media-sync) tool
5353
- 💽 **Sync with database** - Supporting two-way sync of data with PostGIS using [mergin-db-sync](https://github.com/MerginMaps/db-sync) tool
@@ -74,7 +74,7 @@ Admin users can enter the admin interface available at `/admin` URL which provid
7474

7575
### Contributing
7676

77-
Contributions are welcomed! You can set up development environment by following a guide in [development.md](./deployment/community/development.md). Before you create your first pull request, we kindly ask you to sign the CLA with your GitHub user name and date [here](LICENSES/CLA-signed-list.md).
77+
Contributions are welcomed! You can set up development environment by following a guide in [development.md](./development.md). Before you create your first pull request, we kindly ask you to sign the CLA with your GitHub user name and date [here](LICENSES/CLA-signed-list.md).
7878

7979
## Documentation
8080

@@ -93,7 +93,7 @@ If you need support, a custom deployment, extending the service capabilities and
9393

9494
Contributions are welcome!
9595

96-
More information for developers can be found in the dedicated [development](./deployment/community/development.md) page.
96+
More information for developers can be found in the dedicated [development](./development.md) page.
9797

9898
Client side modules:
9999
- [Python](https://github.com/MerginMaps/python-api-client) client library + CLI

deployment/community/.env.template

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,10 @@ MAIL_SUPPRESS_SEND=0
9898

9999
#MAIL_BCC=''
100100

101-
#MERGIN_LOGO_URL= # for link to logo in emails
101+
MERGIN_LOGO_URL=https://merginmaps.com/MM_logo_HORIZ_COLOR_TRANSPARENT_no_padding.png
102102

103103
#MAIL_DEBUG=MAIL_SUPPRESS_SEND | False
104104

105-
106-
107105
# data sync
108106

109107
#LOCAL_PROJECTS=os.path.join(config_dir, os.pardir, os.pardir, 'projects') # for local storage type
@@ -215,5 +213,7 @@ NO_MONKEY_PATCH=False
215213

216214
# Diagnostic logs
217215

216+
DIAGNOSTIC_LOGS_URL=
217+
218218
DIAGNOSTIC_LOGS_DIR=/diagnostic_logs
219219

deployment/community/docker-compose.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ services:
3030
volumes:
3131
- ./projects:/data
3232
- ./diagnostic_logs:/diagnostic_logs
33-
- ../common/entrypoint.sh:/app/entrypoint.sh
3433
env_file:
3534
- .prod.env
3635
depends_on:
@@ -48,8 +47,6 @@ services:
4847
environment:
4948
- GEVENT_WORKER=0
5049
- NO_MONKEY_PATCH=1
51-
volumes:
52-
- ../common/entrypoint.sh:/app/entrypoint.sh
5350
depends_on:
5451
- redis
5552
- server
@@ -68,7 +65,6 @@ services:
6865
- NO_MONKEY_PATCH=1
6966
volumes:
7067
- ./projects:/data
71-
- ../common/entrypoint.sh:/app/entrypoint.sh
7268
depends_on:
7369
- redis
7470
- server

deployment/enterprise/.env.template

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,8 @@ ACCOUNT_EXPIRATION=1
175175

176176
# for links generated in emails
177177

178-
#MERGIN_BASE_URL=http://localhost:5000
179-
MERGIN_BASE_URL=fixme
180-
181178
#MERGIN_LOGO_URL= # for link to logo in emails
182-
MERGIN_LOGO_URL=fixme
179+
MERGIN_LOGO_URL=https://merginmaps.com/MM_logo_HORIZ_COLOR_TRANSPARENT_no_padding.png
183180

184181
# global workspace related bits - ignored in non-CE versions
185182
# GLOBAL_WORKSPACE mergin
@@ -228,6 +225,8 @@ VECTOR_TILES_STYLE_URL=https://tiles-ee.merginmaps.com//styles/default.json
228225
### Diagnostic logs from Mobile and QGIS Plugin
229226
DIAGNOSTIC_LOGS_DIR=/diagnostic_logs
230227

228+
DIAGNOSTIC_LOGS_URL=
229+
231230
### SSO ################################################################################################################
232231
SSO_ENABLED=False
233232

deployment/enterprise/docker-compose.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ services:
1313
volumes:
1414
- ./data:/data # map data dir to host
1515
- ./diagnostic_logs:/diagnostic_logs # diagnostic logs dir
16-
- ../common/entrypoint.sh:/app/entrypoint.sh
1716
env_file:
1817
- .prod.env
18+
environment:
19+
- GUNICORN_CMD_ARGS="--limit-request-line 8190"
1920
depends_on:
2021
- db
2122
networks:
@@ -56,8 +57,6 @@ services:
5657
restart: always
5758
user: 901:999
5859
command: ["celery -A application.celery beat --loglevel=info"]
59-
volumes:
60-
- ../common/entrypoint.sh:/app/entrypoint.sh
6160
env_file:
6261
- .prod.env
6362
depends_on:
@@ -75,7 +74,6 @@ services:
7574
volumes:
7675
- ./data:/data # map data dir to host
7776
- ./map_data:/overviews
78-
- ../common/entrypoint.sh:/app/entrypoint.sh
7977
env_file:
8078
- .prod.env
8179
depends_on:

development.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ $ yarn install
4343
$ yarn link:dependencies # link dependencies
4444
$ yarn build:libs # bild libraries @mergin/lib @mergin/admin-lib @mergin/lib-vue2
4545
$ yarn dev # development client web application dev server on port 8080 (package @mergin/app)
46-
$ yarn dev:admin # development admin appplication dev server on port 8081 (package @mergin/admin-app)
46+
$ yarn dev:admin # development admin application dev server on port 8081 (package @mergin/admin-app)
4747
```
4848

4949
If you are developing a library package (named **-lib*), it is useful to watch the library for changes instead of rebuilding it each time.
@@ -96,7 +96,7 @@ docker exec -it merginmaps-server flask server send-check-email --email admin@e
9696
In docker-compose.dev.yml is started maildev/maildev image that can be used to test emails (see [https://github.com/maildev/maildev/](https://github.com/maildev/maildev/)). In localhost:1080 you can see the emails sent by the application in web interface.
9797

9898
### Running with remote debugger
99-
If you want to run the application with remote debugger, you can use debug compose file with attatched source code and reload.
99+
If you want to run the application with remote debugger, you can use debug compose file with attached source code and reload.
100100
It starts a debugpy session on port 5678 you can attach to.
101101

102102
```shell

server/mergin/auth/commands.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
#
33
# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-MerginMaps-Commercial
44

5+
import sys
56
import click
67
from flask import Flask
78
from sqlalchemy import or_, func
89

910
from ..app import db
1011
from .models import User, UserProfile
12+
from ..commands import normalize_input
1113

1214

1315
def add_commands(app: Flask):
@@ -17,24 +19,25 @@ def user():
1719
pass
1820

1921
@user.command()
20-
@click.argument("username")
22+
@click.argument("username", callback=normalize_input())
2123
@click.argument("password")
2224
@click.option("--is-admin", is_flag=True)
23-
@click.option("--email", required=True)
25+
@click.option("--email", required=True, callback=normalize_input())
2426
def create(username, password, is_admin, email): # pylint: disable=W0612
2527
"""Create user account"""
2628
user = User.query.filter(
2729
or_(
28-
func.lower(User.username) == func.lower(username),
29-
func.lower(User.email) == func.lower(email),
30+
func.lower(User.username) == username,
31+
func.lower(User.email) == email,
3032
)
31-
).first()
33+
).count()
3234
if user:
33-
print("ERROR: User already exists!\n")
34-
return
35+
click.secho("ERROR: User already exists", fg="red", err=True)
36+
sys.exit(1)
3537

3638
user = User(username=username, passwd=password, is_admin=is_admin, email=email)
3739
user.profile = UserProfile()
3840
user.active = True
3941
db.session.add(user)
4042
db.session.commit()
43+
click.secho("User created", fg="green")

server/mergin/auth/models.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class User(db.Model):
3636
default=datetime.datetime.utcnow,
3737
)
3838

39+
last_signed_in = db.Column(db.DateTime(), nullable=True)
40+
3941
__table_args__ = (
4042
db.Index("ix_user_username", func.lower(username), unique=True),
4143
db.Index("ix_user_email", func.lower(email), unique=True),
@@ -289,6 +291,7 @@ def __init__(self, user_id: int, ua: str, ip: str, device_id: Optional[str] = No
289291
self.user_agent = ua
290292
self.ip_address = ip
291293
self.device_id = device_id
294+
self.timestamp = datetime.datetime.now(tz=datetime.timezone.utc)
292295

293296
@staticmethod
294297
def add_record(user_id: int, req: request) -> None:
@@ -300,4 +303,37 @@ def add_record(user_id: int, req: request) -> None:
300303
return
301304
lh = LoginHistory(user_id, ua, ip, device_id)
302305
db.session.add(lh)
306+
307+
# cache user last login
308+
User.query.filter_by(id=user_id).update({"last_signed_in": lh.timestamp})
309+
db.session.commit()
310+
311+
@staticmethod
312+
def get_users_last_signed_in(user_ids: list) -> dict:
313+
"""Get users last signed in dates.
314+
Result is also cached in User table for future use.
315+
"""
316+
result = (
317+
db.session.query(
318+
LoginHistory.user_id,
319+
func.max(LoginHistory.timestamp).label("last_signed_in"),
320+
)
321+
.filter(LoginHistory.user_id.in_(user_ids))
322+
.group_by(LoginHistory.user_id)
323+
.all()
324+
)
325+
326+
user_mapping = [
327+
{
328+
"id": row.user_id, # user_id as PK in User table
329+
"last_signed_in": row.last_signed_in,
330+
}
331+
for row in result
332+
]
333+
if not user_mapping:
334+
return {}
335+
336+
# cache users last signed in
337+
db.session.bulk_update_mappings(User, user_mapping)
303338
db.session.commit()
339+
return {item["id"]: item["last_signed_in"] for item in user_mapping}

0 commit comments

Comments
 (0)