• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SEED-platform / seed / #6556

pending completion
#6556

push

coveralls-python

web-flow
Bump future from 0.18.2 to 0.18.3 in /requirements (#3792)

Bumps [future](https://github.com/PythonCharmers/python-future) from 0.18.2 to 0.18.3.
- [Release notes](https://github.com/PythonCharmers/python-future/releases)
- [Changelog](https://github.com/PythonCharmers/python-future/blob/master/docs/changelog.rst)
- [Commits](https://github.com/PythonCharmers/python-future/compare/v0.18.2...v0.18.3)

---
updated-dependencies:
- dependency-name: future
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

15695 of 22613 relevant lines covered (69.41%)

0.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

24.04
/seed/views/column_mapping_presets.py
1
# !/usr/bin/env python
2
# encoding: utf-8
3

4
from django.http import JsonResponse
5
from rest_framework.decorators import action
1✔
6
from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST
1✔
7
from rest_framework.viewsets import ViewSet
1✔
8

9
from seed.lib.mcm import mapper
1✔
10
from seed.lib.superperms.orgs.decorators import has_perm_class
1✔
11
from seed.models import Column, ColumnMappingProfile, Organization
1✔
12
from seed.serializers.column_mapping_profiles import (
1✔
13
    ColumnMappingProfileSerializer
14
)
15
from seed.utils.api import api_endpoint_class
1✔
16

17

18
class ColumnMappingPresetViewSet(ViewSet):
1✔
19
    @api_endpoint_class
1✔
20
    @has_perm_class('requires_member')
1✔
21
    def list(self, request):
1✔
22
        """
23
        Retrieves all presets for an organization.
24
        parameters:
25
           - name: organization_id
26
             description: The organization_id for this user's organization
27
             required: true (at least, nothing will be returned if not provided)
28
             paramType: query
29
        """
30
        try:
×
31
            profile_types = request.GET.getlist('profile_type')
×
32
            profile_types = [ColumnMappingProfile.get_profile_type(pt) for pt in profile_types]
×
33
            filter_params = {'organizations__pk': request.query_params.get('organization_id', None)}
×
34
            if profile_types:
×
35
                filter_params['profile_type__in'] = profile_types
×
36
            presets = ColumnMappingProfile.objects.filter(**filter_params)
×
37
            data = [ColumnMappingProfileSerializer(p).data for p in presets]
×
38

39
            return JsonResponse({
×
40
                'status': 'success',
41
                'data': data,
42
            })
43
        except Exception as e:
×
44
            return JsonResponse({
×
45
                'status': 'error',
46
                'data': str(e),
47
            }, status=HTTP_400_BAD_REQUEST)
48

49
    @api_endpoint_class
1✔
50
    @has_perm_class('can_modify_data')
1✔
51
    def update(self, request, pk=None):
1✔
52
        """
53
        Updates a preset given appropriate request data. The body should contain
54
        only valid fields for ColumnMappingPreset objects.
55
        parameters:
56
            - name: pk
57
              description: ID of Preset
58
              required: true
59
              paramType: path
60
            - name: name
61
              description: Name of preset
62
              required: false
63
              paramType: body
64
            - name: mappings
65
              description: List of dictionaries
66
              required: false
67
              paramType: body
68
        """
69
        try:
×
70
            preset = ColumnMappingProfile.objects.get(pk=pk)
×
71
        except ColumnMappingProfile.DoesNotExist:
×
72
            return JsonResponse({
×
73
                'status': 'error',
74
                'data': 'No preset with given id'
75
            }, status=HTTP_400_BAD_REQUEST)
76

77
        if preset.profile_type == ColumnMappingProfile.BUILDINGSYNC_DEFAULT:
×
78
            return JsonResponse({
×
79
                'status': 'error',
80
                'data': 'Default BuildingSync presets are not editable'
81
            }, status=HTTP_400_BAD_REQUEST)
82

83
        updated_name, updated_mappings = request.data.get('name'), request.data.get('mappings')
×
84

85
        # update the name
86
        if updated_name is not None:
×
87
            preset.name = updated_name
×
88

89
        # update the mappings according to the preset type
90
        if updated_mappings is not None:
×
91
            if preset.profile_type == ColumnMappingProfile.BUILDINGSYNC_CUSTOM:
×
92
                # only allow these updates to the mappings
93
                # - changing the to_field or from_units
94
                # - removing mappings
95
                original_mappings_dict = {m['from_field']: m.copy() for m in preset.mappings}
×
96
                final_mappings = []
×
97
                for updated_mapping in updated_mappings:
×
98
                    from_field = updated_mapping['from_field']
×
99
                    original_mapping = original_mappings_dict.get(from_field)
×
100
                    if original_mapping is not None:
×
101
                        original_mapping['to_field'] = updated_mapping['to_field']
×
102
                        original_mapping['from_units'] = updated_mapping['from_units']
×
103
                        final_mappings.append(original_mapping)
×
104
                        del original_mappings_dict[from_field]
×
105

106
                preset.mappings = final_mappings
×
107
            elif updated_mappings:
×
108
                # indiscriminately update the mappings
109
                preset.mappings = updated_mappings
×
110

111
        preset.save()
×
112
        return JsonResponse({
×
113
            'status': 'success',
114
            'data': ColumnMappingProfileSerializer(preset).data,
115
        })
116

117
    @api_endpoint_class
1✔
118
    @has_perm_class('can_modify_data')
1✔
119
    def create(self, request, pk=None):
1✔
120
        """
121
        Creates a new preset given appropriate request data. The body should
122
        contain only valid fields for ColumnMappingPreset objects.
123
        parameters:
124
            - name: organization_id
125
              description: The organization_id for this user's organization
126
              required: true
127
              paramType: query
128
            - name: name
129
              description: Name of preset
130
              required: false
131
              paramType: body
132
            - name: mappings
133
              description: List of dictionaries
134
              required: false
135
              paramType: body
136
        """
137
        org_id = request.query_params.get('organization_id', None)
×
138
        try:
×
139
            # verify the org exists then validate and create the preset
140
            Organization.objects.get(pk=org_id)
×
141

142
            preset_data = request.data
×
143
            preset_data['organizations'] = [org_id]
×
144
            ser_preset = ColumnMappingProfileSerializer(data=preset_data)
×
145
            if ser_preset.is_valid():
×
146
                preset = ser_preset.save()
×
147
                response_status = 'success'
×
148
                response_data = ColumnMappingProfileSerializer(preset).data
×
149
                response_code = HTTP_200_OK
×
150
            else:
151
                response_status = 'error'
×
152
                response_data = ser_preset.errors
×
153
                response_code = HTTP_400_BAD_REQUEST
×
154

155
            return JsonResponse({
×
156
                'status': response_status,
157
                'data': response_data,
158
            }, status=response_code)
159
        except Exception as e:
×
160
            return JsonResponse({
×
161
                'status': 'error',
162
                'data': str(e),
163
            }, status=HTTP_400_BAD_REQUEST)
164

165
    @api_endpoint_class
1✔
166
    @has_perm_class('can_modify_data')
1✔
167
    def delete(self, request, pk=None):
1✔
168
        """
169
        Deletes a specific preset.
170
        parameters:
171
            - name: pk
172
              description: ID of Preset
173
              required: true
174
              paramType: path
175
        """
176
        try:
×
177
            preset = ColumnMappingProfile.objects.get(pk=pk)
×
178
        except Exception as e:
×
179
            return JsonResponse({
×
180
                'status': 'error',
181
                'data': str(e),
182
            }, status=HTTP_400_BAD_REQUEST)
183

184
        if preset.profile_type == ColumnMappingProfile.BUILDINGSYNC_DEFAULT:
×
185
            return JsonResponse({
×
186
                'status': 'error',
187
                'data': 'Not allowed to edit default BuildingSync presets'
188
            }, status=HTTP_400_BAD_REQUEST)
189
        else:
190
            preset.delete()
×
191
            return JsonResponse({
×
192
                'status': 'success',
193
                'data': "Successfully deleted",
194
            })
195

196
    @api_endpoint_class
1✔
197
    @has_perm_class('requires_member')
1✔
198
    @action(detail=False, methods=['POST'])
1✔
199
    def suggestions(self, request):
1✔
200
        """
201
        Retrieves suggestions given raw column headers.
202
        parameters:
203
           - headers:---------------------------------------------------------------------------------------------------------------------------
204
           - name: organization_id
205
             description: The organization_id for this user's organization
206
             required: true (at least, nothing will be returned if not provided)
207
             paramType: query
208
        """
209
        try:
×
210
            org_id = request.query_params.get('organization_id', None)
×
211
            raw_headers = request.data.get('headers', [])
×
212

213
            suggested_mappings = mapper.build_column_mapping(
×
214
                raw_headers,
215
                Column.retrieve_all_by_tuple(org_id),
216
                previous_mapping=None,
217
                map_args=None,
218
                thresh=80  # percentage match that we require. 80% is random value for now.
219
            )
220
            # replace None with empty string for column names and PropertyState for tables
221
            # TODO #239: Move this fix to build_column_mapping
222
            for m in suggested_mappings:
×
223
                table, destination_field, _confidence = suggested_mappings[m]
×
224
                if destination_field is None:
×
225
                    suggested_mappings[m][1] = ''
×
226

227
            # Fix the table name, eventually move this to the build_column_mapping
228
            for m in suggested_mappings:
×
229
                table, _destination_field, _confidence = suggested_mappings[m]
×
230
                # Do not return the created or updated fields... that is force them to be
231
                # in the property state. Not sure where this happens in this code block.
232
                if not table or table == 'Property':
×
233
                    suggested_mappings[m][0] = 'PropertyState'
×
234
                elif table == 'TaxLot':
×
235
                    suggested_mappings[m][0] = 'TaxLotState'
×
236

237
            return JsonResponse({
×
238
                'status': 'success',
239
                'data': suggested_mappings,
240
            })
241
        except Exception as e:
×
242
            return JsonResponse({
×
243
                'status': 'error',
244
                'data': str(e),
245
            }, status=HTTP_400_BAD_REQUEST)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc