Progress.
This commit is contained in:
parent
81479e7058
commit
d10768403d
src/snek
@ -1,3 +1 @@
|
||||
|
||||
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
from aiohttp import web
|
||||
from aiohttp import web
|
||||
|
||||
from snek.app import Application
|
||||
|
||||
if __name__ == '__main__':
|
||||
web.run_app(Application(), port=8081,host='0.0.0.0')
|
||||
if __name__ == "__main__":
|
||||
web.run_app(Application(), port=8081, host="0.0.0.0")
|
||||
|
@ -3,6 +3,7 @@ import logging
|
||||
import pathlib
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from snek.view.threads import ThreadsView
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
@ -24,7 +25,7 @@ from snek.service import get_services
|
||||
from snek.system import http
|
||||
from snek.system.cache import Cache
|
||||
from snek.system.markdown import MarkdownExtension
|
||||
from snek.system.middleware import cors_middleware
|
||||
from snek.system.middleware import auth_middleware, cors_middleware
|
||||
from snek.system.profiler import profiler_handler
|
||||
from snek.system.template import EmojiExtension, LinkifyExtension, PythonExtension
|
||||
from snek.view.about import AboutHTMLView, AboutMDView
|
||||
@ -37,12 +38,13 @@ from snek.view.logout import LogoutView
|
||||
from snek.view.register import RegisterView
|
||||
from snek.view.rpc import RPCView
|
||||
from snek.view.search_user import SearchUserView
|
||||
from snek.view.settings.index import SettingsIndexView
|
||||
from snek.view.settings.profile import SettingsProfileView
|
||||
from snek.view.status import StatusView
|
||||
from snek.view.terminal import TerminalSocketView, TerminalView
|
||||
from snek.view.upload import UploadView
|
||||
from snek.view.web import WebView
|
||||
from snek.webdav import WebdavApplication
|
||||
from snek.view.settings import SettingsView
|
||||
|
||||
SESSION_KEY = b"c79a0c5fda4b424189c427d28c9f7c34"
|
||||
|
||||
@ -76,6 +78,7 @@ class Application(BaseApplication):
|
||||
session_setup(self, EncryptedCookieStorage(SESSION_KEY))
|
||||
self.tasks = asyncio.Queue()
|
||||
self._middlewares.append(session_middleware)
|
||||
self._middlewares.append(auth_middleware)
|
||||
self.jinja2_env.add_extension(MarkdownExtension)
|
||||
self.jinja2_env.add_extension(LinkifyExtension)
|
||||
self.jinja2_env.add_extension(PythonExtension)
|
||||
@ -138,7 +141,9 @@ class Application(BaseApplication):
|
||||
self.router.add_view("/docs.html", DocsHTMLView)
|
||||
self.router.add_view("/docs.md", DocsMDView)
|
||||
self.router.add_view("/status.json", StatusView)
|
||||
self.router.add_view("/settings.html", SettingsView)
|
||||
self.router.add_view("/settings/index.html", SettingsIndexView)
|
||||
self.router.add_view("/settings/profile.html", SettingsProfileView)
|
||||
self.router.add_view("/settings/profile.json", SettingsProfileView)
|
||||
self.router.add_view("/web.html", WebView)
|
||||
self.router.add_view("/login.html", LoginView)
|
||||
self.router.add_view("/login.json", LoginView)
|
||||
@ -189,8 +194,8 @@ class Application(BaseApplication):
|
||||
channels = []
|
||||
if not context:
|
||||
context = {}
|
||||
|
||||
context['rid'] = str(uuid.uuid4())
|
||||
|
||||
context["rid"] = str(uuid.uuid4())
|
||||
if request.session.get("uid"):
|
||||
async for subscribed_channel in self.services.channel_member.find(
|
||||
user_uid=request.session.get("uid"), deleted_at=None, is_banned=False
|
||||
|
@ -7,6 +7,7 @@ from snek.mapper.drive import DriveMapper
|
||||
from snek.mapper.drive_item import DriveItemMapper
|
||||
from snek.mapper.notification import NotificationMapper
|
||||
from snek.mapper.user import UserMapper
|
||||
from snek.mapper.user_property import UserPropertyMapper
|
||||
from snek.system.object import Object
|
||||
|
||||
|
||||
@ -21,6 +22,7 @@ def get_mappers(app=None):
|
||||
"notification": NotificationMapper(app=app),
|
||||
"drive_item": DriveItemMapper(app=app),
|
||||
"drive": DriveMapper(app=app),
|
||||
"user_property": UserPropertyMapper(app=app),
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -5,7 +5,11 @@ from snek.model.channel_member import ChannelMemberModel
|
||||
|
||||
# from snek.model.channel_message import ChannelMessageModel
|
||||
from snek.model.channel_message import ChannelMessageModel
|
||||
from snek.model.drive import DriveModel
|
||||
from snek.model.drive_item import DriveItemModel
|
||||
from snek.model.notification import NotificationModel
|
||||
from snek.model.user import UserModel
|
||||
from snek.model.user_property import UserPropertyModel
|
||||
from snek.system.object import Object
|
||||
|
||||
|
||||
@ -17,6 +21,10 @@ def get_models():
|
||||
"channel_member": ChannelMemberModel,
|
||||
"channel": ChannelModel,
|
||||
"channel_message": ChannelMessageModel,
|
||||
"drive_item": DriveItemModel,
|
||||
"drive": DriveModel,
|
||||
"notification": NotificationModel,
|
||||
"user_property": UserPropertyModel,
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -28,6 +28,16 @@ async def cors_allow_middleware(request, handler):
|
||||
return response
|
||||
|
||||
|
||||
@web.middleware
|
||||
async def auth_middleware(request, handler):
|
||||
request["user"] = None
|
||||
if request.session.get("uid") and request.session.get("logged_in"):
|
||||
request["user"] = await request.app.services.user.get(
|
||||
uid=request.app.session.get("uid")
|
||||
)
|
||||
return await handler(request)
|
||||
|
||||
|
||||
@web.middleware
|
||||
async def cors_middleware(request, handler):
|
||||
if request.headers.get("Allow"):
|
||||
|
@ -31,7 +31,7 @@
|
||||
<a class="no-select" href="/search-user.html">🔍</a>
|
||||
<a class="no-select" style="display:none" id="install-button" href="#">📥</a>
|
||||
<a class="no-select" href="/threads.html">👥</a>
|
||||
<a class="no-select" href="#">⚙️</a>
|
||||
<a class="no-select" href="/settings/index.html">⚙️</a>
|
||||
<a class="no-select" href="/logout.html">🔒</a>
|
||||
</nav>
|
||||
|
||||
|
@ -13,24 +13,14 @@
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
{% block logo %}
|
||||
<h1>Setting page</h1>
|
||||
|
||||
<div id="profile_description"></div>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
|
||||
|
||||
<script type="module">
|
||||
|
||||
require.config({ paths: { 'vs': 'https://cdn.bootcdn.net/ajax/libs/monaco-editor/0.20.0/min/vs' } });
|
||||
|
||||
require(['vs/editor/editor.main'], function () {
|
||||
var editor = monaco.editor.create(document.getElementById('profile_description'), {
|
||||
value: phpCode,
|
||||
language: 'php'
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
{% endblock main %}
|
||||
|
@ -1,14 +0,0 @@
|
||||
<style>
|
||||
.channel-list-item-highlight {
|
||||
/* xxx */
|
||||
}
|
||||
</style>
|
||||
<aside class="sidebar" id="channelSidebar">
|
||||
<h2>Settings</h2>
|
||||
<ul>
|
||||
<li><a class="no-select" href="/settings.html">Profile</a></li>
|
||||
<li><a class="no-select" href="/settings-notifications.html">Notifications</a></li>
|
||||
<li><a class="no-select" href="/settings-privacy.html">Privacy</a></li>
|
||||
</ul>
|
||||
|
||||
</aside>
|
@ -1,8 +0,0 @@
|
||||
from snek.system.view import BaseView
|
||||
|
||||
class SettingsView(BaseView):
|
||||
|
||||
login_required = True
|
||||
|
||||
async def get(self):
|
||||
return await self.render_template('settings.html')
|
@ -1,9 +1,8 @@
|
||||
import logging
|
||||
|
||||
import pathlib
|
||||
|
||||
logging.basicConfig(level=logging.DEBUG)
|
||||
|
||||
import asyncio
|
||||
import base64
|
||||
import datetime
|
||||
import mimetypes
|
||||
@ -21,7 +20,7 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
def __init__(self, parent, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.locks = {}
|
||||
|
||||
|
||||
self.router.add_route("OPTIONS", "/{filename:.*}", self.handle_options)
|
||||
self.router.add_route("GET", "/{filename:.*}", self.handle_get)
|
||||
self.router.add_route("PUT", "/{filename:.*}", self.handle_put)
|
||||
@ -31,22 +30,21 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
self.router.add_route("COPY", "/{filename:.*}", self.handle_copy)
|
||||
self.router.add_route("PROPFIND", "/{filename:.*}", self.handle_propfind)
|
||||
self.router.add_route("PROPPATCH", "/{filename:.*}", self.handle_proppatch)
|
||||
#self.router.add_route("LOCK", "/{filename:.*}", self.handle_lock)
|
||||
#self.router.add_route("UNLOCK", "/{filename:.*}", self.handle_unlock)
|
||||
# self.router.add_route("LOCK", "/{filename:.*}", self.handle_lock)
|
||||
# self.router.add_route("UNLOCK", "/{filename:.*}", self.handle_unlock)
|
||||
self.parent = parent
|
||||
|
||||
@property
|
||||
@property
|
||||
def db(self):
|
||||
return self.parent.db
|
||||
|
||||
@property
|
||||
@property
|
||||
def services(self):
|
||||
return self.parent.services
|
||||
|
||||
return self.parent.services
|
||||
|
||||
async def authenticate(self, request):
|
||||
#session = request.session
|
||||
#if session.get('uid'):
|
||||
# session = request.session
|
||||
# if session.get('uid'):
|
||||
# request['user'] = await self.services.user.get(uid=session['uid'])
|
||||
# try:
|
||||
# request['home'] = await self.services.user.get_home_folder(user_uid=request['user']['uid'])
|
||||
@ -60,13 +58,17 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
encoded_creds = auth_header.split("Basic ")[1]
|
||||
decoded_creds = base64.b64decode(encoded_creds).decode()
|
||||
username, password = decoded_creds.split(":", 1)
|
||||
request['user'] = await self.services.user.authenticate(username=username, password=password)
|
||||
request["user"] = await self.services.user.authenticate(
|
||||
username=username, password=password
|
||||
)
|
||||
try:
|
||||
request['home'] = await self.services.user.get_home_folder(request['user']['uid'])
|
||||
request["home"] = await self.services.user.get_home_folder(
|
||||
request["user"]["uid"]
|
||||
)
|
||||
except Exception as ex:
|
||||
print(ex)
|
||||
pass
|
||||
return request['user']
|
||||
return request["user"]
|
||||
|
||||
async def handle_get(self, request):
|
||||
if not await self.authenticate(request):
|
||||
@ -75,7 +77,7 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
)
|
||||
|
||||
requested_path = request.match_info.get("filename", "")
|
||||
abs_path = request['home'] / requested_path
|
||||
abs_path = request["home"] / requested_path
|
||||
|
||||
if not abs_path.exists():
|
||||
return aiohttp.web.Response(status=404, text="File not found")
|
||||
@ -95,7 +97,7 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
return aiohttp.web.Response(
|
||||
status=401, headers={"WWW-Authenticate": 'Basic realm="WebDAV"'}
|
||||
)
|
||||
file_path = request['home'] / request.match_info["filename"]
|
||||
file_path = request["home"] / request.match_info["filename"]
|
||||
file_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
async with aiofiles.open(file_path, "wb") as f:
|
||||
while chunk := await request.content.read(1024):
|
||||
@ -107,7 +109,7 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
return aiohttp.web.Response(
|
||||
status=401, headers={"WWW-Authenticate": 'Basic realm="WebDAV"'}
|
||||
)
|
||||
file_path = request['home'] / request.match_info["filename"]
|
||||
file_path = request["home"] / request.match_info["filename"]
|
||||
if file_path.is_file():
|
||||
file_path.unlink()
|
||||
return aiohttp.web.Response(status=204)
|
||||
@ -121,7 +123,7 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
return aiohttp.web.Response(
|
||||
status=401, headers={"WWW-Authenticate": 'Basic realm="WebDAV"'}
|
||||
)
|
||||
dir_path = request['home'] / request.match_info["filename"]
|
||||
dir_path = request["home"] / request.match_info["filename"]
|
||||
if dir_path.exists():
|
||||
return aiohttp.web.Response(status=405, text="Directory already exists")
|
||||
dir_path.mkdir(parents=True, exist_ok=True)
|
||||
@ -132,8 +134,8 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
return aiohttp.web.Response(
|
||||
status=401, headers={"WWW-Authenticate": 'Basic realm="WebDAV"'}
|
||||
)
|
||||
src_path = request['home'] / request.match_info["filename"]
|
||||
dest_path = request['home'] / request.headers.get("Destination", "").replace(
|
||||
src_path = request["home"] / request.match_info["filename"]
|
||||
dest_path = request["home"] / request.headers.get("Destination", "").replace(
|
||||
"http://localhost:8080/", ""
|
||||
)
|
||||
if not src_path.exists():
|
||||
@ -146,8 +148,8 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
return aiohttp.web.Response(
|
||||
status=401, headers={"WWW-Authenticate": 'Basic realm="WebDAV"'}
|
||||
)
|
||||
src_path = request['home'] / request.match_info["filename"]
|
||||
dest_path = request['home'] / request.headers.get("Destination", "").replace(
|
||||
src_path = request["home"] / request.match_info["filename"]
|
||||
dest_path = request["home"] / request.headers.get("Destination", "").replace(
|
||||
"http://localhost:8080/", ""
|
||||
)
|
||||
if not src_path.exists():
|
||||
@ -188,14 +190,13 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
statvfs = os.statvfs(path)
|
||||
return statvfs.f_bavail * statvfs.f_frsize
|
||||
|
||||
|
||||
async def create_node(self, request, response_xml, full_path, depth):
|
||||
requested_path = request.match_info.get("filename", "")
|
||||
request.match_info.get("filename", "")
|
||||
abs_path = pathlib.Path(full_path)
|
||||
relative_path = str(full_path.relative_to(request['home']))
|
||||
relative_path = str(full_path.relative_to(request["home"]))
|
||||
|
||||
href_path = f"{relative_path}".strip("/")
|
||||
#href_path = href_path.replace("./","/")
|
||||
# href_path = href_path.replace("./","/")
|
||||
href_path = href_path.replace("//", "/")
|
||||
response = etree.SubElement(response_xml, "{DAV:}response")
|
||||
href = etree.SubElement(response, "{DAV:}href")
|
||||
@ -213,7 +214,7 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
else self.get_directory_size(full_path)
|
||||
)
|
||||
etree.SubElement(prop, "{DAV:}quota-available-bytes").text = str(
|
||||
self.get_disk_free_space(request['home'])
|
||||
self.get_disk_free_space(request["home"])
|
||||
)
|
||||
etree.SubElement(prop, "{DAV:}getlastmodified").text = last_modified
|
||||
etree.SubElement(prop, "{DAV:}displayname").text = full_path.name
|
||||
@ -222,10 +223,10 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
if full_path.is_file():
|
||||
etree.SubElement(prop, "{DAV:}contenttype").text = mimetype
|
||||
etree.SubElement(prop, "{DAV:}getcontentlength").text = str(
|
||||
full_path.stat().st_size
|
||||
if full_path.is_file()
|
||||
else self.get_directory_size(full_path)
|
||||
)
|
||||
full_path.stat().st_size
|
||||
if full_path.is_file()
|
||||
else self.get_directory_size(full_path)
|
||||
)
|
||||
supported_lock = etree.SubElement(prop, "{DAV:}supportedlock")
|
||||
lock_entry_1 = etree.SubElement(supported_lock, "{DAV:}lockentry")
|
||||
lock_scope_1 = etree.SubElement(lock_entry_1, "{DAV:}lockscope")
|
||||
@ -238,13 +239,10 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
lock_type_2 = etree.SubElement(lock_entry_2, "{DAV:}locktype")
|
||||
etree.SubElement(lock_type_2, "{DAV:}write")
|
||||
etree.SubElement(propstat, "{DAV:}status").text = "HTTP/1.1 200 OK"
|
||||
|
||||
|
||||
if abs_path.is_dir() and depth != -1:
|
||||
for item in abs_path.iterdir():
|
||||
await self.create_node(request,response_xml, item, depth - 1)
|
||||
|
||||
|
||||
|
||||
await self.create_node(request, response_xml, item, depth - 1)
|
||||
|
||||
async def handle_propfind(self, request):
|
||||
if not await self.authenticate(request):
|
||||
@ -257,14 +255,13 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
depth = int(request.headers.get("Depth", "0"))
|
||||
except ValueError:
|
||||
pass
|
||||
requested_path = request.match_info.get("filename", "")
|
||||
abs_path = request['home'] / requested_path
|
||||
requested_path = request.match_info.get("filename", "")
|
||||
abs_path = request["home"] / requested_path
|
||||
if not abs_path.exists():
|
||||
return aiohttp.web.Response(status=404, text="Directory not found")
|
||||
nsmap = {"D": "DAV:"}
|
||||
response_xml = etree.Element("{DAV:}multistatus", nsmap=nsmap)
|
||||
directories = [requested_path]
|
||||
|
||||
|
||||
await self.create_node(request, response_xml, abs_path, depth)
|
||||
|
||||
xml_output = etree.tostring(
|
||||
@ -286,9 +283,9 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
return aiohttp.web.Response(
|
||||
status=401, headers={"WWW-Authenticate": 'Basic realm="WebDAV"'}
|
||||
)
|
||||
resource = request.match_info.get("filename", "/")
|
||||
request.match_info.get("filename", "/")
|
||||
lock_id = str(uuid.uuid4())
|
||||
#self.locks[resource] = lock_id
|
||||
# self.locks[resource] = lock_id
|
||||
xml_response = self.generate_lock_response(lock_id)
|
||||
headers = {
|
||||
"Lock-Token": f"opaquelocktoken:{lock_id}",
|
||||
@ -341,8 +338,8 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
)
|
||||
|
||||
requested_path = request.match_info.get("filename", "")
|
||||
print(requested_path)
|
||||
abs_path = request['home'] / requested_path
|
||||
print(requested_path)
|
||||
abs_path = request["home"] / requested_path
|
||||
|
||||
if not abs_path.exists():
|
||||
return aiohttp.web.Response(status=404, text="File not found")
|
||||
@ -363,5 +360,3 @@ class WebdavApplication(aiohttp.web.Application):
|
||||
}
|
||||
|
||||
return aiohttp.web.Response(status=200, headers=headers)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user