File: //volume1/@appstore/SynologyPhotos/migration/python/dump_moments_db.py
#!/usr/bin/env python3
import json
import logging
import sys
import pg8000
class MomentsPGSql:
def __init__(self):
self.cursor = self.init_cursor()
def init_cursor(self):
user = "postgres"
unix_sock = "/var/run/postgresql/.s.PGSQL.5432"
database = "synophoto"
conn = pg8000.connect(user, unix_sock=unix_sock, database=database)
cursor = conn.cursor()
cursor.execute("SET CLIENT_ENCODING TO 'UTF8'")
return cursor
def GetUserInfos(self):
self.cursor.execute(
"""
SELECT id, uid, name, config, enable FROM user_info
"""
)
result = []
for id, uid, name, config, enable in self.cursor:
result.append(
{
"id": id,
"uid": 0 if uid is None else uid,
"name": name,
"config": config,
"enable": enable,
}
)
return result
def GetAlbum(self, id_user_info):
self.cursor.execute(
"""
SELECT id, name, shared, create_time, cover, passphrase_share, item_count, start_time, end_time FROM user_{}.normal_album
""".format(
id_user_info
)
)
result = []
for (
id,
name,
shared,
create_time,
cover,
passphrase_share,
item_count,
start_time,
end_time,
) in self.cursor.fetchall():
if name[0:2] == "\x08\x07":
name = name[2:]
is_temp_share = True
else:
is_temp_share = False
cover_path = self.GetCoverPath(cover, id_user_info)
result.append(
{
"id": id,
"name": name,
"is_temp_share": is_temp_share,
"shared": shared,
"create_time": create_time,
"cover": cover_path,
"passphrase_share": passphrase_share or "",
"item_count": item_count,
"start_time": start_time,
"end_time": end_time,
}
)
return result
def GetCoverPath(self, cover, id_user_info):
if 0 == cover:
return ""
self.cursor.execute(
"""
SELECT filename, id_folder FROM user_{}.unit WHERE id_item = {};
""".format(
id_user_info, cover
)
)
filename, id_folder = self.cursor.fetchone()
self.cursor.execute(
"""
SELECT name
FROM user_{}.folder WHERE id = {};
""".format(
id_user_info, id_folder
)
)
[folder_name] = self.cursor.fetchone()
return folder_name + "/" + filename
def GetAlbumUnit(self, id_user_info, id_album):
self.cursor.execute(
"""
SELECT filename, id_folder
FROM user_{}.unit WHERE id_item IN(SELECT id_item FROM user_{}.many_item_has_many_normal_album WHERE id_normal_album = {});
""".format(
id_user_info, id_user_info, id_album
)
)
folder_ids = []
units = self.cursor.fetchall()
if not units:
return []
for filename, id_folder in units:
folder_ids.append(id_folder)
self.cursor.execute(
"""
SELECT id, name
FROM user_{}.folder WHERE id IN ({});
""".format(
id_user_info, ",".join(str(v) for v in folder_ids)
)
)
folders = {}
for folder_id, name in self.cursor:
folders[folder_id] = name
result = []
for filename, id_folder in units:
result.append(folders[id_folder] + "/" + filename)
return result
def GetAlbumSharingInfo(self, passphrase_share):
self.cursor.execute(
"""
SELECT allow_operation, access_permission
FROM share WHERE passphrase = '{}';
""".format(
passphrase_share
)
)
allow_operation, access_permission = self.cursor.fetchone()
self.cursor.execute(
"""
SELECT uid
FROM user_info WHERE id IN (SELECT id_user_info FROM many_share_has_many_user_info WHERE passphrase_share = '{}');
""".format(
passphrase_share
)
)
uids = []
for [uid] in self.cursor:
uids.append(uid)
self.cursor.execute(
"""
SELECT gid
FROM group_info WHERE id IN (SELECT id_group_info FROM many_share_has_many_group_info WHERE passphrase_share = '{}');
""".format(
passphrase_share
)
)
gids = []
for [gid] in self.cursor:
gids.append(gid)
result = {
"allow_download": allow_operation & 1 > 0,
"allow_upload": allow_operation & 2 > 0,
"allow_comment": allow_operation & 4 > 0,
"share_type": "DSM" if (access_permission >> 1) == 0 else "Public",
"uid": uids,
"gid": gids,
}
return result
def GetConfig(self):
try:
self.cursor.execute(
"""
SELECT key, value FROM config
"""
)
except Exception as err:
logging.error("Failed to get config, error: {}".format(err))
return {}
result = {}
for key, value in self.cursor:
result.update(
{
key: value,
}
)
return result
def GetTeamLibrary(self):
try:
# get default team library
self.cursor.execute(
"""
SELECT name, path FROM team_library ORDER BY name ASC LIMIT 1
"""
)
except Exception as err:
logging.error("Failed to get config, error: {}".format(err))
return []
result = []
for name, path in self.cursor:
result.append(
{
"name": name,
"path": path,
}
)
return result
def GetUserInfoWithAlbum(pgsql):
try:
result = []
for user_info in pgsql.GetUserInfos():
result_albums = []
for album in pgsql.GetAlbum(user_info["id"]):
units = pgsql.GetAlbumUnit(user_info["id"], album["id"])
result_album = {
"album": album,
"unit": units,
}
if album["passphrase_share"] != "":
result_album["sharing_info"] = pgsql.GetAlbumSharingInfo(
album["passphrase_share"]
)
result_albums.append(result_album)
result.append(
{
"user_info": user_info,
"album": result_albums,
}
)
except Exception as err:
logging.error("Failed to get user info, error: {}".format(err))
return []
return result
def main():
pgsql = MomentsPGSql()
result = {
"user_info": GetUserInfoWithAlbum(pgsql),
"config": pgsql.GetConfig(),
"team_library": pgsql.GetTeamLibrary(),
}
return result
if __name__ == "__main__":
result = main()
if len(sys.argv) >= 2:
path = sys.argv[1]
json.dump(result, open(path, "w"))
else:
print(json.dumps(result))