write_documents_reports.py 8.28 KB
Newer Older
Jonas Waeber's avatar
Jonas Waeber committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Import API Service
# Copyright (C) 2020-2021 Memobase Project
#
# 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 <https://www.gnu.org/licenses/>.
16
17
18
19
import json
from datetime import datetime

import requests
20
from flask_restful import Resource, request
Matthias's avatar
Matthias committed
21
from flask_restful import current_app
22
from import_api_app.helpers.error import ImportApiError
23
from requests.auth import HTTPBasicAuth
24
25
26


class WriteJobResultToDrupal(Resource):
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

    def __init__(self):
        self.logger = None
        self.headers = {
            'Content-Type': 'application/vnd.api+json',
            'Accept': 'application/vnd.api+json',
            'X-API-Key': current_app.config['drupal-api-key']
        }
        user = current_app.config['drupal-user']
        password = current_app.config['drupal-password']
        self.auth = HTTPBasicAuth(user, password)
        self.job_url = f'{current_app.config["drupal-api-url"]}/jsonapi/node/log_result/'
        self.import_process_endpoint = f'{current_app.config["drupal-api-url"]}' \
                                       f'/jsonapi/node/import_process/'

Matthias's avatar
Matthias committed
42
    def post(self, job_drupal_uuid, job_log_drupal_uuid):
43
        """
44
        Write the job summary to Drupal job log (in field_summary)
45
46
        ---
        tags:
47
          - reporting
48
49
        parameters:
        - in: path
Matthias's avatar
Matthias committed
50
          name: job_drupal_uuid
51
52
          required: true
          description: job log uuid
Matthias's avatar
Matthias committed
53
54
55
56
57
          type: string
        - in: path
          name: job_log_drupal_uuid
          required: true
          description: job report log uuid
58
          type: string
59
60
        - in: body
          name: body
61
          required: true
62
63
          schema:
              properties:
Matthias's avatar
Matthias committed
64
                sessionId:
65
                    type: string
Matthias's avatar
Matthias committed
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
                    example: "550e8400-e29b-11d4-a716-446655440000"
                step:
                    type: string
                    example: "media-metadata-extractor"
                total:
                    type: integer
                    example: 468
                success:
                    type: integer
                    example: 413
                ignore:
                    type: integer
                    example: 0
                warning:
                    type: integer
                    example: 455
                fatal:
                    type: integer
                    example: 0
                earliest:
                    type: string
                    example: "2021-03-08T14:02:23.232"
                latest:
                    type: string
                    example: "latest"
                elapsedTime:
                    type: string
                    example: "00:03:11.219"
                recordSetId:
                    type: string
                    example: "fss-001"
                institutionId:
                    type: string
                    example: "fss"
                messageId:
                    type: string
                    example: "1b7d8224-451a-4afb-b5d2-6537acb74051"
                previousMessageId:
                    type: string
                    example: "04543477-3bb5-4d01-a318-52ded1ce5e1c"
                version:
                    type: string
                    example: "3"
109
110
111
        responses:
          200:
            description: It was successful
Lionel Walter's avatar
Lionel Walter committed
112
113
          404:
            description: No log result with such a uuid
114
115
116
          500:
            description: There was a problem
        """
117
118
119
        self.logger = current_app.logger
        body = request.json
        current_app.logger.debug("Report Input Data: \n" + json.dumps(body, indent=2))
120
        try:
121
            fatal = body['fatal']
Matthias's avatar
Matthias committed
122
123
            if fatal == 0:
                status = 'SUCCESS'
124
125
126
            else:
                status = 'FAILED'
            return self.write_results(job_drupal_uuid, job_log_drupal_uuid, status, body)
Lionel Walter's avatar
Lionel Walter committed
127
        except ImportApiError as e:
Jonas Waeber's avatar
Jonas Waeber committed
128
            self.logger.error(e)
Lionel Walter's avatar
Lionel Walter committed
129
            return {'error': e.message}, 500
Matthias's avatar
Matthias committed
130

131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
    def write_results(self, job_drupal_uuid, job_log_drupal_uuid, status, report):
        self.logger.debug("Job UUID: " + job_drupal_uuid)
        self.logger.debug("Job Log Report UUID: " + job_log_drupal_uuid)
        get_url = self.job_url + job_log_drupal_uuid
        response = requests.get(get_url, headers=self.headers, auth=self.auth)
        if response.ok:
            try:
                job_log = response.json()
            except json.decoder.JSONDecodeError as ex:
                self.logger.error(f'Could not parse response as JSON: {response.text}.')
                raise ImportApiError(ex)
            log_data = job_log['data']
            previous_status = log_data['attributes']['field_status']
            previous_report = log_data['attributes']['field_message']
        else:
            raise ImportApiError(response.text)
Matthias's avatar
Matthias committed
147

148
149
150
151
152
153
154
155
156
        if previous_status == 'FAILED':
            status = previous_status
        if previous_report is None or previous_report == 'null':
            previous_report_json = {}
        else:
            previous_report_json = json.loads(previous_report)
        step = report['step']
        previous_report_json[step] = report
        report_as_string = json.dumps(previous_report_json)
Matthias's avatar
Matthias committed
157

158
159
160
161
162
163
164
165
166
167
        # updating the status of the import process.
        patch_calls = {}
        patch_url = self.import_process_endpoint + job_drupal_uuid
        patch_data = {
            "data": {
                "id": job_drupal_uuid,
                "type": "node--import_process",
                "attributes": {
                    "field_state": 0
                }
Matthias's avatar
Matthias committed
168
169
            }
        }
170
171
172
173
174
175
176
177
178
179
180
181
        # updating the content of the job log entity
        patch_calls[patch_url] = patch_data
        patch_url = self.job_url + job_log_drupal_uuid
        patch_data = {
            "data": {
                "id": job_log_drupal_uuid,
                "type": "node--job_result",
                "attributes": {
                    "field_end_date": datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%S+00:00"),
                    "field_status": status,
                    "field_message": report_as_string
                }
Matthias's avatar
Matthias committed
182
183
            }
        }
184
185
        patch_calls[patch_url] = patch_data
        result = {'message': ''}
Matthias's avatar
Matthias committed
186

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
        for patchCall in patch_calls:
            url = patchCall
            data = patch_calls[patchCall]
            try:
                response = requests.patch(
                    url,
                    headers=self.headers,
                    data=json.dumps(data)
                )
            except requests.exceptions.RequestException:
                message = "It was not possible to write to Drupal API \
                          via the following url " + url
                current_app.logger.error(message)
                raise ImportApiError(message)
            if response.status_code == 200:
                current_app.logger.debug('Updated: ' + url)
                result['message'] += 'Updated: ' + url + '\n'
            elif response.status_code == 403:
                message = "Not authorized to write to: " + url
                current_app.logger.error(message)
                raise ImportApiError(message)
            elif response.status_code == 404:
                message = 'Not Found: ' + url
                current_app.logger.error(message)
                raise ImportApiError(message)
            elif response.status_code == 500:
                message = 'There was an internal server error for ' + url + ': ' + str(response) + \
                          '. Check the logs for details.'
                current_app.logger.error(message)
                raise ImportApiError(message)
            else:
                message = "Unknown response status code for drupal api for url " + url
                current_app.logger.error(message)
                raise ImportApiError(message)
        return result