UPdate.
This commit is contained in:
		
							parent
							
								
									dd108c2004
								
							
						
					
					
						commit
						f0591d4939
					
				@ -33,6 +33,7 @@ from snek.view.about import AboutHTMLView, AboutMDView
 | 
				
			|||||||
from snek.view.avatar import AvatarView
 | 
					from snek.view.avatar import AvatarView
 | 
				
			||||||
from snek.view.docs import DocsHTMLView, DocsMDView
 | 
					from snek.view.docs import DocsHTMLView, DocsMDView
 | 
				
			||||||
from snek.view.drive import DriveView
 | 
					from snek.view.drive import DriveView
 | 
				
			||||||
 | 
					from snek.view.drive import DriveApiView
 | 
				
			||||||
from snek.view.index import IndexView
 | 
					from snek.view.index import IndexView
 | 
				
			||||||
from snek.view.login import LoginView
 | 
					from snek.view.login import LoginView
 | 
				
			||||||
from snek.view.logout import LogoutView
 | 
					from snek.view.logout import LogoutView
 | 
				
			||||||
@ -178,7 +179,8 @@ class Application(BaseApplication):
 | 
				
			|||||||
        self.router.add_view("/threads.html", ThreadsView)
 | 
					        self.router.add_view("/threads.html", ThreadsView)
 | 
				
			||||||
        self.router.add_view("/terminal.ws", TerminalSocketView)
 | 
					        self.router.add_view("/terminal.ws", TerminalSocketView)
 | 
				
			||||||
        self.router.add_view("/terminal.html", TerminalView)
 | 
					        self.router.add_view("/terminal.html", TerminalView)
 | 
				
			||||||
        self.router.add_view("/drive.json", DriveView)
 | 
					        self.router.add_view("/drive.json", DriveApiView)
 | 
				
			||||||
 | 
					        self.router.add_view("/drive.html", DriveView)
 | 
				
			||||||
        self.router.add_view("/drive/{drive}.json", DriveView)
 | 
					        self.router.add_view("/drive/{drive}.json", DriveView)
 | 
				
			||||||
        self.router.add_view("/stats.json", StatsView)
 | 
					        self.router.add_view("/stats.json", StatsView)
 | 
				
			||||||
        self.router.add_view("/user/{user}.html", UserView)
 | 
					        self.router.add_view("/user/{user}.html", UserView)
 | 
				
			||||||
 | 
				
			|||||||
@ -9,6 +9,7 @@ class FileBrowser extends HTMLElement {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  connectedCallback() {
 | 
					  connectedCallback() {
 | 
				
			||||||
 | 
					      this.path = this.getAttribute("path") || "";
 | 
				
			||||||
    this.renderShell();
 | 
					    this.renderShell();
 | 
				
			||||||
    this.load();
 | 
					    this.load();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -19,11 +20,11 @@ class FileBrowser extends HTMLElement {
 | 
				
			|||||||
      <style>
 | 
					      <style>
 | 
				
			||||||
        :host { display:block; font-family: system-ui, sans-serif; box-sizing: border-box; }
 | 
					        :host { display:block; font-family: system-ui, sans-serif; box-sizing: border-box; }
 | 
				
			||||||
        nav    { display:flex; flex-wrap:wrap; gap:.5rem; margin:.5rem 0; align-items:center; }
 | 
					        nav    { display:flex; flex-wrap:wrap; gap:.5rem; margin:.5rem 0; align-items:center; }
 | 
				
			||||||
        button { padding:.35rem .65rem; border:none; border-radius:4px; background:#0074d9; color:#fff; cursor:pointer; font:inherit; }
 | 
					        button { padding:.35rem .65rem; border:none; border-radius:4px; background:#f05a28; color:#fff; cursor:pointer; font:inherit; }
 | 
				
			||||||
        button:disabled { background:#999; cursor:not-allowed; }
 | 
					        button:disabled { background:#999; cursor:not-allowed; }
 | 
				
			||||||
        .crumb  { font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
 | 
					        .crumb  { font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
 | 
				
			||||||
        .grid   { display:grid; grid-template-columns:repeat(auto-fill,minmax(120px,1fr)); gap:1rem; }
 | 
					        .grid   { display:grid; grid-template-columns:repeat(auto-fill,minmax(120px,1fr)); gap:1rem; }
 | 
				
			||||||
        .tile   { border:1px solid #ddd; border-radius:8px; padding:.5rem; background:#fafafa; text-align:center; cursor:pointer; transition:box-shadow .2s ease; }
 | 
					        .tile   { border:1px solid #f05a28; border-radius:8px; padding:.5rem; background:#000000; text-align:center; cursor:pointer; transition:box-shadow .2s ease; }
 | 
				
			||||||
        .tile:hover { box-shadow:0 2px 8px rgba(0,0,0,.1); }
 | 
					        .tile:hover { box-shadow:0 2px 8px rgba(0,0,0,.1); }
 | 
				
			||||||
        img.thumb { width:100%; height:90px; object-fit:cover; border-radius:6px; }
 | 
					        img.thumb { width:100%; height:90px; object-fit:cover; border-radius:6px; }
 | 
				
			||||||
        .icon { font-size:48px; line-height:90px; }
 | 
					        .icon { font-size:48px; line-height:90px; }
 | 
				
			||||||
 | 
				
			|||||||
@ -35,6 +35,7 @@
 | 
				
			|||||||
    <div class="logo no-select">{% block header_text %}{% endblock %}</div>
 | 
					    <div class="logo no-select">{% block header_text %}{% endblock %}</div>
 | 
				
			||||||
    <nav class="no-select" style="overflow:hidden;scroll-behavior:smooth">
 | 
					    <nav class="no-select" style="overflow:hidden;scroll-behavior:smooth">
 | 
				
			||||||
      <a class="no-select" href="/web.html">🏠</a>
 | 
					      <a class="no-select" href="/web.html">🏠</a>
 | 
				
			||||||
 | 
					      <a class="no-select" href="/drive.html">📂</a>
 | 
				
			||||||
      <a class="no-select" href="/search-user.html">🔍</a>
 | 
					      <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" style="display:none" id="install-button" href="#">📥</a>
 | 
				
			||||||
      <a class="no-select" href="/threads.html">👥</a>
 | 
					      <a class="no-select" href="/threads.html">👥</a>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										9
									
								
								src/snek/templates/drive.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/snek/templates/drive.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					{% extends "app.html" %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block header_text %}Drive{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block main %}
 | 
				
			||||||
 | 
					<div class="container">
 | 
				
			||||||
 | 
					<file-manager path="{{path}}" style="flex: 1"></file-manager>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
@ -3,43 +3,7 @@
 | 
				
			|||||||
{% block header_text %}<h1><i class="fa-solid fa-plus"></i> Create Repository</h1>{% endblock %}
 | 
					{% block header_text %}<h1><i class="fa-solid fa-plus"></i> Create Repository</h1>{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block main %}
 | 
					{% block main %}
 | 
				
			||||||
 | 
					{% include 'settings/repositories/form.html' %}
 | 
				
			||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
 | 
					 | 
				
			||||||
<style>
 | 
					 | 
				
			||||||
.container {
 | 
					 | 
				
			||||||
    div,input,label,button{
 | 
					 | 
				
			||||||
        padding-bottom: 15px;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
    form {
 | 
					 | 
				
			||||||
      padding: 2rem;
 | 
					 | 
				
			||||||
      border-radius: 10px;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    label { font-weight: bold; display: flex; align-items: center; gap: 0.5rem;}
 | 
					 | 
				
			||||||
    input[type="text"] {
 | 
					 | 
				
			||||||
      padding: 0.5rem;
 | 
					 | 
				
			||||||
      border: 1px solid #ccc; border-radius: 5px;
 | 
					 | 
				
			||||||
      font-size: 1rem;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
button, a.button {
 | 
					 | 
				
			||||||
      background: #198754; color: #fff; border: none; border-radius: 5px;
 | 
					 | 
				
			||||||
      padding: 0.1rem 0.8rem; text-decoration: none; cursor: pointer;
 | 
					 | 
				
			||||||
      transition: background 0.2s;
 | 
					 | 
				
			||||||
      font-size: 1rem; display: inline-flex; align-items: center; gap: 0.4rem;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .
 | 
					 | 
				
			||||||
    .cancel {
 | 
					 | 
				
			||||||
      background: #6c757d;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    @media (max-width: 600px) {
 | 
					 | 
				
			||||||
      .container { max-width: 98vw; }
 | 
					 | 
				
			||||||
      form { padding: 1rem; }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  </style>
 | 
					 | 
				
			||||||
</head>
 | 
					 | 
				
			||||||
<body>
 | 
					 | 
				
			||||||
  <div class="container">
 | 
					  <div class="container">
 | 
				
			||||||
    <form action="/settings/repositories/create.html" method="post">
 | 
					    <form action="/settings/repositories/create.html" method="post">
 | 
				
			||||||
      <div>
 | 
					      <div>
 | 
				
			||||||
@ -52,8 +16,9 @@ button, a.button {
 | 
				
			|||||||
          <i class="fa-solid fa-lock"></i> Private
 | 
					          <i class="fa-solid fa-lock"></i> Private
 | 
				
			||||||
        </label>
 | 
					        </label>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <button type="submit"><i class="fa-solid fa-plus"></i> Create</button>
 | 
					      <button type="submit"><i class="fa-solid fa-pen"></i> Update</button>
 | 
				
			||||||
      <button onclick="history.back()" class="cancel"><i class="fa-solid fa-arrow-left"></i> Back</button> 
 | 
					      <button onclick="history.back()" class="cancel"><i class="fa-solid fa-arrow-left"></i>Cancel</button>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    </form>
 | 
					    </form>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  {% endblock %}
 | 
					  {% endblock %}
 | 
				
			||||||
 | 
				
			|||||||
@ -3,32 +3,7 @@
 | 
				
			|||||||
{% block header_text %}<h1><i class="fa-solid fa-trash-can"></i> Delete Repository</h1>{% endblock %}
 | 
					{% block header_text %}<h1><i class="fa-solid fa-trash-can"></i> Delete Repository</h1>{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block main %}
 | 
					{% block main %}
 | 
				
			||||||
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
 | 
					    {% include "settings/repositories/form.html" %}  
 | 
				
			||||||
  <style>
 | 
					 | 
				
			||||||
    .repo-name {
 | 
					 | 
				
			||||||
      font-weight: bold;
 | 
					 | 
				
			||||||
      font-size: 1.2rem;
 | 
					 | 
				
			||||||
      margin: 1rem 0;
 | 
					 | 
				
			||||||
      color: #dc3545;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .actions {
 | 
					 | 
				
			||||||
      display: flex; gap: 1rem; justify-content: left; margin-top: 1.5rem;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    button {
 | 
					 | 
				
			||||||
      background: #dc3545; color: #fff;
 | 
					 | 
				
			||||||
      border: none; border-radius: 5px; padding: 0.6rem 1.2rem;
 | 
					 | 
				
			||||||
      font-size: 1rem; cursor: pointer;
 | 
					 | 
				
			||||||
      display: flex; align-items: center; gap: 0.5rem; text-decoration: none; justify-content: center;
 | 
					 | 
				
			||||||
      transition: background 0.2s;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .cancel {
 | 
					 | 
				
			||||||
      background: #6c757d;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    @media (max-width: 600px) {
 | 
					 | 
				
			||||||
      .container { max-width: 98vw; }
 | 
					 | 
				
			||||||
      .confirm-box { padding: 1rem; }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  </style>
 | 
					 | 
				
			||||||
<div class="container">
 | 
					<div class="container">
 | 
				
			||||||
      <p>Are you sure you want to <strong>delete</strong> the following repository?</p>
 | 
					      <p>Are you sure you want to <strong>delete</strong> the following repository?</p>
 | 
				
			||||||
      <div class="repo-name"><i class="fa-solid fa-book"></i> {{ repository.name }}</div>
 | 
					      <div class="repo-name"><i class="fa-solid fa-book"></i> {{ repository.name }}</div>
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										28
									
								
								src/snek/templates/settings/repositories/form.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/snek/templates/settings/repositories/form.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
 | 
				
			||||||
 | 
					  <style>
 | 
				
			||||||
 | 
					    form {
 | 
				
			||||||
 | 
					      padding: 2rem;
 | 
				
			||||||
 | 
					      border-radius: 10px;
 | 
				
			||||||
 | 
					      div {
 | 
				
			||||||
 | 
					        padding: 10px;
 | 
				
			||||||
 | 
					        padding-bottom: 15px
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    label { font-weight: bold; display: flex; align-items: center; gap: 0.5rem;}
 | 
				
			||||||
 | 
					    button {
 | 
				
			||||||
 | 
					      background: #0d6efd; color: #fff;
 | 
				
			||||||
 | 
					      border: none; border-radius: 5px; padding: 0.6rem 1rem;
 | 
				
			||||||
 | 
					      cursor: pointer;
 | 
				
			||||||
 | 
					      font-size: 1rem; display: inline-flex; align-items: center; gap: 0.4rem;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .cancel {
 | 
				
			||||||
 | 
					      background: #6c757d;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					      @media (max-width: 600px) {
 | 
				
			||||||
 | 
					      .container { max-width: 98vw; }
 | 
				
			||||||
 | 
					      form { padding: 1rem; }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3,27 +3,7 @@
 | 
				
			|||||||
{% block header_text %}<h1><i class="fa-solid fa-pen"></i> Update Repository</h1>{% endblock %}
 | 
					{% block header_text %}<h1><i class="fa-solid fa-pen"></i> Update Repository</h1>{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block main %}
 | 
					{% block main %}
 | 
				
			||||||
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
 | 
					{% include "settings/repositories/form.html" %}
 | 
				
			||||||
  <style>
 | 
					 | 
				
			||||||
    form {
 | 
					 | 
				
			||||||
      padding: 2rem;
 | 
					 | 
				
			||||||
      border-radius: 10px;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    label { font-weight: bold; display: flex; align-items: center; gap: 0.5rem;}
 | 
					 | 
				
			||||||
    button {
 | 
					 | 
				
			||||||
      background: #0d6efd; color: #fff;
 | 
					 | 
				
			||||||
      border: none; border-radius: 5px; padding: 0.6rem 1rem;
 | 
					 | 
				
			||||||
      cursor: pointer;
 | 
					 | 
				
			||||||
      font-size: 1rem; display: inline-flex; align-items: center; gap: 0.4rem;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    .cancel {
 | 
					 | 
				
			||||||
      background: #6c757d;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
      @media (max-width: 600px) {
 | 
					 | 
				
			||||||
      .container { max-width: 98vw; }
 | 
					 | 
				
			||||||
      form { padding: 1rem; }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  </style>
 | 
					 | 
				
			||||||
    <div class="container">
 | 
					    <div class="container">
 | 
				
			||||||
    <form method="post">
 | 
					    <form method="post">
 | 
				
			||||||
      <!-- Assume hidden id for backend use -->
 | 
					      <!-- Assume hidden id for backend use -->
 | 
				
			||||||
 | 
				
			|||||||
@ -11,47 +11,42 @@ from datetime import datetime
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""Run with:  python server.py  (Python ≥ 3.9)
 | 
					 | 
				
			||||||
Visit  http://localhost:8080  to try the demo.
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
from aiohttp import web
 | 
					from aiohttp import web
 | 
				
			||||||
from pathlib import Path
 | 
					from pathlib import Path
 | 
				
			||||||
import mimetypes, urllib.parse
 | 
					import mimetypes, urllib.parse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ---------- Configuration --------------------------------------------------
 | 
					 | 
				
			||||||
BASE_DIR   = Path(__file__).parent.resolve()
 | 
					 | 
				
			||||||
ROOT_DIR   = (BASE_DIR / "storage").resolve()   # files shown to the outside world
 | 
					 | 
				
			||||||
ASSETS_DIR = (BASE_DIR / "assets").resolve()    # JS & demo HTML
 | 
					 | 
				
			||||||
ROOT_DIR.mkdir(exist_ok=True)
 | 
					 | 
				
			||||||
ASSETS_DIR.mkdir(exist_ok=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# ---------- Helpers --------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def safe_resolve_path(rel: str) -> Path:
 | 
					 | 
				
			||||||
    """Return *absolute* path inside ROOT_DIR or raise FileNotFoundError."""
 | 
					 | 
				
			||||||
    target = (ROOT_DIR / rel.lstrip("/")).resolve()
 | 
					 | 
				
			||||||
    if target == ROOT_DIR or ROOT_DIR in target.parents:
 | 
					 | 
				
			||||||
        return target
 | 
					 | 
				
			||||||
    raise FileNotFoundError("Unsafe path")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# ---------- API view -------------------------------------------------------
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class DriveView(BaseView):
 | 
					class DriveView(BaseView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async def get(self):
 | 
					    async def get(self):
 | 
				
			||||||
 | 
					        target = await self.services.user.get_home_folder(self.session.get("uid"))
 | 
				
			||||||
 | 
					        rel_path = self.request.match_info.get("rel_path", "")
 | 
				
			||||||
 | 
					        if rel_path:
 | 
				
			||||||
 | 
					            target = target.joinpath(rel_path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not target.exists():
 | 
				
			||||||
 | 
					            return web.HTTPNotFound(reason="Path not found")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if target.is_dir():
 | 
				
			||||||
 | 
					            return await self.render_template("drive.html",{"path": rel_path})
 | 
				
			||||||
 | 
					        if target.is_file():
 | 
				
			||||||
 | 
					            return web.FileResponse(target)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DriveApiView(BaseView):
 | 
				
			||||||
 | 
					    async def get(self):
 | 
				
			||||||
 | 
					        target = await self.services.user.get_home_folder(self.session.get("uid"))
 | 
				
			||||||
        rel = self.request.query.get("path", "")
 | 
					        rel = self.request.query.get("path", "")
 | 
				
			||||||
        offset = int(self.request.query.get("offset", 0))
 | 
					        offset = int(self.request.query.get("offset", 0))
 | 
				
			||||||
        limit  = int(self.request.query.get("limit", 20))
 | 
					        limit  = int(self.request.query.get("limit", 20))
 | 
				
			||||||
        target = await self.services.user.get_home_folder(self.session.get("uid"))
 | 
					
 | 
				
			||||||
        if rel:
 | 
					        if rel:
 | 
				
			||||||
            target.joinpath(rel)
 | 
					            target = target.joinpath(rel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if not target.exists():
 | 
					        if not target.exists():
 | 
				
			||||||
            return web.json_response({"error": "Not found"}, status=404)
 | 
					            return web.json_response({"error": "Not found"}, status=404)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # ---- Directory listing -------------------------------------------
 | 
					 | 
				
			||||||
        if target.is_dir():
 | 
					        if target.is_dir():
 | 
				
			||||||
            entries = []
 | 
					            entries = []
 | 
				
			||||||
            # Directories first, then files – both alphabetical (case‑insensitive)
 | 
					 | 
				
			||||||
            for p in sorted(target.iterdir(), key=lambda p: (p.is_file(), p.name.lower())):
 | 
					            for p in sorted(target.iterdir(), key=lambda p: (p.is_file(), p.name.lower())):
 | 
				
			||||||
                item_path = (Path(rel) / p.name).as_posix()
 | 
					                item_path = (Path(rel) / p.name).as_posix()
 | 
				
			||||||
                mime = mimetypes.guess_type(p.name)[0] if p.is_file() else "inode/directory"
 | 
					                mime = mimetypes.guess_type(p.name)[0] if p.is_file() else "inode/directory"
 | 
				
			||||||
@ -73,10 +68,6 @@ class DriveView(BaseView):
 | 
				
			|||||||
                "pagination": {"offset": offset, "limit": limit, "total": total}
 | 
					                "pagination": {"offset": offset, "limit": limit, "total": total}
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
        with open(target, "rb") as f:
 | 
					 | 
				
			||||||
            content = f.read()
 | 
					 | 
				
			||||||
            return web.Response(body=content, content_type=mimetypes.guess_type(target.name)[0])
 | 
					 | 
				
			||||||
        # ---- Single file metadata ----------------------------------------
 | 
					 | 
				
			||||||
        url = self.request.url.with_path(f"/drive/{urllib.parse.quote(rel)}")
 | 
					        url = self.request.url.with_path(f"/drive/{urllib.parse.quote(rel)}")
 | 
				
			||||||
        return web.json_response({
 | 
					        return web.json_response({
 | 
				
			||||||
            "name": target.name,
 | 
					            "name": target.name,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user