1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2019 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# 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 Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# See the file COPYING for details.
import os.path
import sys
from ishtar_common.utils import get_used_media, try_fix_file, get_broken_links
from django.conf import settings
from django.core.management.base import BaseCommand
class Command(BaseCommand):
args = ''
help = 'Find missing files in media.'
def add_arguments(self, parser):
parser.add_argument(
'--exclude', nargs='?', dest='exclude', default=None,
help="Field to exclude separated with \",\". Example: "
"ishtar_common.Import.imported_file,"
"ishtar_common.Import.imported_images"
)
parser.add_argument(
'--limit', nargs='?', dest='limit', default=None,
help="Field to limit to. Separate field names with \",\"."
)
parser.add_argument(
'--try-fix', dest='try-fix', action='store_true',
default=False,
help='Try to find file with similar names and copy the file.')
parser.add_argument(
'--find-fix', dest='find-fix', action='store_true',
default=False,
help='Try to find file with similar names and print them.')
parser.add_argument(
'--hard', dest='hard', action='store_true',
default=False,
help='Search on the whole media dir.')
parser.add_argument(
'--set-empty-image', dest='set-empty-image', action='store_true',
default=False,
help='Set a link to empty-image for missing media.')
parser.add_argument(
'--set-alt-media-dir', dest='set-alt-media-dir', default=False,
help='Try to set link from an alt directory for missing media.')
def handle(self, *args, **options):
exclude = options['exclude'].split(',') if options['exclude'] else []
limit = options['limit'].split(',') if options['limit'] else []
try_fix = options['try-fix']
find_fix = options['find-fix']
hard = options['hard']
set_alt_media_dir = options["set-alt-media-dir"]
set_empty_image = options["set-empty-image"]
if set_alt_media_dir and not os.path.isdir(set_alt_media_dir):
self.stdout.write(f'set-alt-media-dir: "{set_alt_media_dir}" is not a valid path.\n')
return
if set_empty_image and set_alt_media_dir:
self.stdout.write("set-empty-image and set-alt-media-dir options are not "
"compatible.\n")
return
if try_fix and find_fix:
self.stdout.write("try-fix and find-fix options are not "
"compatible.\n")
return
if hard and not (try_fix or find_fix):
self.stdout.write("hard option has no effect if try-fix or "
"find-fix are not set.\n")
if try_fix:
# first try to fix broken links
out = None
for l in get_broken_links(settings.MEDIA_ROOT):
if not out:
self.stdout.write("* fixes broken links:\n")
out = True
try_fix_file(l, hard=hard)
missing = []
for media in get_used_media(exclude=exclude, limit=limit):
if not os.path.isfile(media):
missing.append(media)
if try_fix or find_fix:
if find_fix:
self.stdout.write("* potential similar file:\n")
else:
self.stdout.write("* fixes files:\n")
for item in missing[:]:
source_file = try_fix_file(item, make_copy=try_fix,
hard=hard)
if source_file:
missing.pop(missing.index(item))
sys.stdout.write(
"{} <- {}\n".format(item.encode('utf-8'),
source_file.encode('utf-8')))
if set_alt_media_dir:
total = 0
for f in missing:
f = os.path.abspath(f)
if not f.startswith(settings.MEDIA_ROOT):
continue
dest = os.path.join(set_alt_media_dir, f[len(settings.MEDIA_ROOT):])
if not os.path.isfile(dest):
continue
directory = f.split(os.path.sep)[:-1]
directory = os.sep + os.path.join(*directory)
if not os.path.isdir(directory):
os.makedirs(directory)
try:
os.symlink(dest, f)
except FileExistsError:
continue
total += 1
self.stdout.write(f"* {total} link to {set_alt_media_dir} created.\n")
return
if set_empty_image:
empty_image = os.path.abspath(
settings.LIB_BASE_PATH + "ishtar_common/static/media/images/empty-image"
)
total = 0
for f in missing:
f = os.path.abspath(f)
if not f.startswith(settings.MEDIA_ROOT):
continue
if f.lower().endswith(".jpg") or f.lower().endswith(".jpeg"):
cempty_image = empty_image + ".jpg"
elif f.lower().endswith(".png"):
cempty_image = empty_image + ".png"
else:
continue
directory = f.split(os.path.sep)[:-1]
directory = os.sep + os.path.join(*directory)
if not os.path.isdir(directory):
os.makedirs(directory)
os.symlink(cempty_image, f)
total += 1
self.stdout.write(f"* {total} missing files set to empty image\n")
elif missing:
if find_fix or try_fix:
self.stdout.write("* missing file with no similar file "
"found:\n")
for item in missing:
sys.stdout.write(item + "\n")
else:
self.stdout.write("No missing files.\n")
|