Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
AE
Sith
Commits
0d3c34c1
Commit
0d3c34c1
authored
Mar 20, 2018
by
Skia
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core/models: refactor SithFile moving and add methods to manage filesystem
Signed-off-by:
Skia
<
skia@libskia.so
>
parent
e9e51d34
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
161 additions
and
18 deletions
+161
-18
core/management/commands/check_fs.py
core/management/commands/check_fs.py
+42
-0
core/management/commands/repair_fs.py
core/management/commands/repair_fs.py
+42
-0
core/models.py
core/models.py
+64
-17
core/views/files.py
core/views/files.py
+13
-1
No files found.
core/management/commands/check_fs.py
0 → 100644
View file @
0d3c34c1
# -*- coding:utf-8 -*
#
# Copyright 2018
# - Skia <skia@libskia.so>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
import
os
from
django.core.management.base
import
BaseCommand
from
django.core.management
import
call_command
from
core.models
import
SithFile
class
Command
(
BaseCommand
):
help
=
"Recursively check the file system with respect to the DB"
def
add_arguments
(
self
,
parser
):
parser
.
add_argument
(
'ids'
,
metavar
=
'ID'
,
type
=
int
,
nargs
=
'+'
,
help
=
"The file IDs to process"
)
def
handle
(
self
,
*
args
,
**
options
):
root_path
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
))))
files
=
SithFile
.
objects
.
filter
(
id__in
=
options
[
'ids'
]).
all
()
for
f
in
files
:
f
.
_check_fs
()
core/management/commands/repair_fs.py
0 → 100644
View file @
0d3c34c1
# -*- coding:utf-8 -*
#
# Copyright 2018
# - Skia <skia@libskia.so>
#
# Ce fichier fait partie du site de l'Association des Étudiants de l'UTBM,
# http://ae.utbm.fr.
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License a published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Sofware Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.
#
#
import
os
from
django.core.management.base
import
BaseCommand
from
django.core.management
import
call_command
from
core.models
import
SithFile
class
Command
(
BaseCommand
):
help
=
"Recursively repair the file system with respect to the DB"
def
add_arguments
(
self
,
parser
):
parser
.
add_argument
(
'ids'
,
metavar
=
'ID'
,
type
=
int
,
nargs
=
'+'
,
help
=
"The file IDs to process"
)
def
handle
(
self
,
*
args
,
**
options
):
root_path
=
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
os
.
path
.
dirname
(
__file__
))))
files
=
SithFile
.
objects
.
filter
(
id__in
=
options
[
'ids'
]).
all
()
for
f
in
files
:
f
.
_repair_fs
()
core/models.py
View file @
0d3c34c1
...
...
@@ -759,25 +759,72 @@ class SithFile(models.Model):
self
.
save
()
def
move_to
(
self
,
parent
):
"""Move a file to somewhere else"""
"""
Move a file to a new parent.
`parent` must be a SithFile with the `is_folder=True` property. Otherwise, this function doesn't change
anything.
This is done only at the DB level, so that it's very fast for the user. Indeed, this function doesn't modify
SithFiles recursively, so it stays efficient even with top-level folders.
"""
if
not
parent
.
is_folder
:
return
import
shutil
import
os
with
transaction
.
atomic
():
if
self
.
is_folder
:
old_file_name
=
self
.
get_full_path
()
else
:
old_file_name
=
self
.
file
.
name
self
.
parent
=
parent
self
.
save
()
if
self
.
is_folder
:
for
c
in
self
.
children
.
all
():
c
.
move_to
(
self
)
shutil
.
rmtree
(
os
.
path
.
join
(
settings
.
MEDIA_ROOT
,
old_file_name
))
else
:
self
.
file
.
save
(
name
=
self
.
name
,
content
=
self
.
file
)
os
.
remove
(
os
.
path
.
join
(
settings
.
MEDIA_ROOT
,
old_file_name
))
self
.
parent
=
parent
self
.
clean
()
self
.
save
()
def
_repair_fs
(
self
):
"""
This function rebuilds recursively the filesystem as it should be
regarding the DB tree.
"""
if
self
.
is_folder
:
for
c
in
self
.
children
.
all
():
c
.
_repair_fs
()
return
else
:
import
os
# First get future parent path and the old file name
# Prepend "." so that we match all relative handling of Django's
# file storage
parent_path
=
"."
+
self
.
parent
.
get_full_path
()
parent_full_path
=
settings
.
MEDIA_ROOT
+
parent_path
print
(
"Parent full path: %s"
%
parent_full_path
)
os
.
makedirs
(
parent_full_path
,
exist_ok
=
True
)
old_path
=
self
.
file
.
name
# Should be relative: "./users/skia/bleh.jpg"
new_path
=
"."
+
self
.
get_full_path
()
print
(
"Old path: %s "
%
old_path
)
print
(
"New path: %s "
%
new_path
)
# Make this atomic, so that a FS problem rolls back the DB change
with
transaction
.
atomic
():
# Set the new filesystem path
self
.
file
.
name
=
new_path
self
.
save
()
print
(
"New file path: %s "
%
self
.
file
.
path
)
# Really move at the FS level
if
os
.
path
.
exists
(
parent_full_path
):
os
.
rename
(
settings
.
MEDIA_ROOT
+
old_path
,
settings
.
MEDIA_ROOT
+
new_path
)
# Empty directories may remain, but that's not really a
# problem, and that can be solved with a simple shell
# command: `find . -type d -empty -delete`
def
_check_path_consistence
(
self
):
file_path
=
str
(
self
.
file
)
db_path
=
".%s"
%
self
.
get_full_path
()
if
file_path
!=
db_path
:
print
(
"%s: "
%
self
.
id
,
end
=
''
)
print
(
"file path: %s"
%
file_path
,
end
=
''
)
print
(
" db path: %s"
%
db_path
)
return
False
else
:
return
True
def
_check_fs
(
self
):
if
self
.
is_folder
:
for
c
in
self
.
children
.
all
():
c
.
_check_fs
()
return
else
:
self
.
_check_path_consistence
()
def
__getattribute__
(
self
,
attr
):
if
attr
==
"is_file"
:
...
...
core/views/files.py
View file @
0d3c34c1
...
...
@@ -189,6 +189,18 @@ class FileView(CanViewMixin, DetailView, FormMixin):
form_class
=
AddFilesForm
def
handle_clipboard
(
request
,
object
):
"""
This method handles the clipboard in the view.
This method can fail, since it does not catch the exceptions coming from
below, allowing proper handling in the calling view.
Use this method like this:
FileView.handle_clipboard(request, self.object)
`request` is usually the self.request object in your view
`object` is the SithFile object you want to put in the clipboard, or
where you want to paste the clipboard
"""
if
'delete'
in
request
.
POST
.
keys
():
for
f_id
in
request
.
POST
.
getlist
(
'file_list'
):
sf
=
SithFile
.
objects
.
filter
(
id
=
f_id
).
first
()
...
...
@@ -200,7 +212,6 @@ class FileView(CanViewMixin, DetailView, FormMixin):
for
f_id
in
request
.
POST
.
getlist
(
'file_list'
):
f_id
=
int
(
f_id
)
if
f_id
in
[
c
.
id
for
c
in
object
.
children
.
all
()]
and
f_id
not
in
request
.
session
[
'clipboard'
]:
print
(
f_id
)
request
.
session
[
'clipboard'
].
append
(
f_id
)
if
'paste'
in
request
.
POST
.
keys
():
for
f_id
in
request
.
session
[
'clipboard'
]:
...
...
@@ -221,6 +232,7 @@ class FileView(CanViewMixin, DetailView, FormMixin):
if
'clipboard'
not
in
request
.
session
.
keys
():
request
.
session
[
'clipboard'
]
=
[]
if
request
.
user
.
can_edit
(
self
.
object
):
# XXX this call can fail!
FileView
.
handle_clipboard
(
request
,
self
.
object
)
self
.
form
=
self
.
get_form
()
# The form handle only the file upload
files
=
request
.
FILES
.
getlist
(
'file_field'
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment