~widelands-dev/widelands-website/django_staticfiles

« back to all changes in this revision

Viewing changes to wlmaps/forms.py

  • Committer: franku
  • Date: 2016-12-12 18:22:47 UTC
  • mfrom: (442 trunk)
  • mto: This revision was merged to the branch mainline in revision 443.
  • Revision ID: somal@arcor.de-20161212182247-gyy7vv0byc366pgc
merged with trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
7
7
from django import forms
8
8
from django.forms import ModelForm
9
9
from django.core.files.storage import default_storage
10
 
from django.core.files.base import ContentFile
11
10
 
12
11
from settings import MEDIA_ROOT
13
12
from wlmaps.models import Map
14
13
 
15
14
 
16
15
class UploadMapForm(ModelForm):
 
16
    """
 
17
    We have to handle here three different kind of files:
 
18
    1. The map which is uploaded
 
19
    2. The files created by 'wl_map_info'
 
20
        a. The json file containing infos of the map
 
21
        b. The image of the minimap (png)
 
22
 
 
23
    The filename of uploaded maps may contain bad characters which must be handled.
 
24
 
 
25
    If a map get deleted in the database, the underlying files (.wmf, .png) still exists. Uploading
 
26
    a map with the same name does not overwrite the existing file(s), instead they get a
 
27
    name in form of 'filename_<random_chars>.wmf(.png)'. This is importand for linking the correct
 
28
    minimap.
 
29
    The map file and the minimap (png) have different random characters in such a case, because the map
 
30
    get saved twice: One time for the call to wl_map_info, and when the model is saved.
 
31
    """
17
32
 
18
33
    class Meta:
19
34
        model = Map
22
37
    def clean(self):
23
38
        cleaned_data = super(UploadMapForm, self).clean()
24
39
 
25
 
        file = cleaned_data.get('file')
26
 
        if not file:
 
40
        mem_file_obj = cleaned_data.get('file')
 
41
        if not mem_file_obj:
27
42
            # no clean file => abort
28
43
            return cleaned_data
29
44
 
30
 
        name = MEDIA_ROOT + 'wlmaps/maps/' + file.name
31
 
        default_storage.save(name, ContentFile(file.read()))
 
45
        try:
 
46
            # Try to make a safe filename
 
47
            safe_name = default_storage.get_valid_name(mem_file_obj.name)
 
48
            file_path = MEDIA_ROOT + 'wlmaps/maps/' + safe_name
 
49
            saved_file = default_storage.save(file_path, mem_file_obj)
 
50
        except UnicodeEncodeError:
 
51
            self._errors['file'] = self.error_class(
 
52
                ['The filename contains characters which cannot be handled. Please rename and upload again.'])
 
53
            del cleaned_data['file']
 
54
            return cleaned_data
 
55
 
32
56
        try:
33
57
            # call map info tool to generate minimap and json info file
34
 
            check_call(['wl_map_info', name])
 
58
            check_call(['wl_map_info', saved_file])
 
59
 
35
60
            # TODO(shevonar): delete file because it will be saved again when
36
61
            # the model is saved. File should not be saved twice
37
 
            default_storage.delete(name)
 
62
            default_storage.delete(saved_file)
38
63
        except CalledProcessError:
39
64
            self._errors['file'] = self.error_class(
40
65
                ['The map file could not be processed.'])
41
66
            del cleaned_data['file']
42
67
            return cleaned_data
43
68
 
44
 
        mapinfo = json.load(open(name + '.json'))
 
69
        mapinfo = json.load(open(saved_file + '.json'))
45
70
 
46
71
        if Map.objects.filter(name=mapinfo['name']):
47
72
            self._errors['file'] = self.error_class(
57
82
        self.instance.nr_players = mapinfo['nr_players']
58
83
        self.instance.descr = mapinfo['description']
59
84
        self.instance.hint = mapinfo['hint']
60
 
 
61
85
        self.instance.world_name = mapinfo['world_name']
62
 
        # mapinfo["minimap"] is an absolute path and cannot be used.
63
 
        self.instance.minimap = '/wlmaps/maps/' + file.name + '.png'
 
86
 
 
87
        # mapinfo["minimap"] is an absolute path.
 
88
        # We partition it to get the correct file path
 
89
        minimap_path = mapinfo['minimap'].partition(MEDIA_ROOT)[2]
 
90
        self.instance.minimap = '/' + minimap_path
64
91
 
65
92
        # the json file is no longer needed
66
 
        default_storage.delete(name + '.json')
67
 
        
 
93
        default_storage.delete(saved_file + '.json')
 
94
 
68
95
        return cleaned_data
69
96
 
70
97
    def save(self, *args, **kwargs):