summaryrefslogtreecommitdiffstats
path: root/app.py
blob: dd494630208c99c9b5ef78d6c86440f990bcd4df (plain)
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
166
167
168
169
170
171
172
173
174
175
176
177
178
import os
import re
import uuid
from flask import Flask, request, jsonify, send_from_directory
import datetime
from flasgger import Swagger, swag_from

app = Flask(__name__)
swagger = Swagger(app)
app.config['UPLOAD_DIRECTORY'] = os.environ.get('UPLOAD_DIRECTORY', '/uploads')
app.config['MAX_CONTENT_LENGTH'] = int(os.environ.get('MAX_CONTENT_LENGTH', '5')) * 1024 * 1024  # in MB

VALID_FILENAME_REGEX = r'^[a-zA-Z0-9\-_\.]+$'

AUTH_TOKEN = os.environ.get('AUTH_TOKEN', 'myuploadtoken')

def is_valid_filename(filename):
    return bool(re.match(VALID_FILENAME_REGEX, filename))

@app.route('/health', methods=['GET'])
def health_check():
    """
    Endpoint for health check.
    ---
    responses:
        200:
            description: OK
    """
    return 'OK'

@app.route('/upload', methods=['POST'])
def upload_file():
    """
    Endpoint for uploading files.
    Filename can only contain alphanumeric characters, hyphens, underscores, and periods.
    If the filename is the same as an existing file, this file will be overwritten.
    ---
    parameters:
        - name: file
          in: formData
          type: file
          required: true
          description: The file to upload.
        - name: token
          in: header
          type: string
          required: true
          description: Authentication token.
    responses:
        200:
            description: File uploaded successfully.
        400:
            description: Bad request.
        401:
            description: Unauthorized.
    """
    if 'file' not in request.files:
        return jsonify({'error': 'No file part in the request'}), 400

    if 'token' not in request.headers:
        return jsonify({'error': 'No token supplied'}), 401

    if request.headers['token'] != AUTH_TOKEN:
        return jsonify({'error': 'Invalid token supplied'}), 401

    file = request.files['file']
    if file.filename == '':
        return jsonify({'error': 'No file selected for upload'}), 400

    if not is_valid_filename(file.filename):
        return jsonify({'error': 'Invalid filename. Only alphanumeric characters, hyphens, underscores, and periods are allowed.'}), 400

    filename = file.filename
    file.save(os.path.join(app.config['UPLOAD_DIRECTORY'], filename))
    return jsonify({'success': 'File \'{}\' successfully uploaded'.format(filename)})

@app.route('/download/<filename>', methods=['GET'])
def download_file(filename):
    """
    Endpoint for downloading files.
    ---
    parameters:
        - name: filename
          in: path
          type: string
          required: true
          description: The name of the file to download.
    responses:
        200:
            description: File downloaded successfully.
        404:
            description: File not found.
    """
    try:
        return send_from_directory(app.config['UPLOAD_DIRECTORY'], filename)
    except FileNotFoundError:
        return jsonify({'error': 'File \'{}\' not found'}), 404

@app.route('/delete/<filename>', methods=['DELETE'])
def delete_file(filename):
    """
    Endpoint for deleting files.
    ---
    parameters:
        - name: filename
          in: path
          type: string
          required: true
          description: The name of the file to delete.
        - name: token
          in: header
          type: string
          required: true
          description: Authentication token.
    responses:
        200:
            description: File deleted successfully.
        401:
            description: Unauthorized.
        404:
            description: File not found.
    """
    if 'token' not in request.headers:
        return jsonify({'error': 'No token supplied'}), 401

    if request.headers['token'] != AUTH_TOKEN:
        return jsonify({'error': 'Invalid token supplied'}), 401

    file_path = os.path.join(app.config['UPLOAD_DIRECTORY'], filename)
    if not os.path.isfile(file_path):
        return jsonify({'error': 'File not found'}), 404

    os.remove(file_path)
    return jsonify({'success': 'File \'{}\' successfully deleted'.format(filename)})


@app.route('/list', methods=['GET'])
def list_files():
    """
    Endpoint for listing  files.
    ---
    parameters:
        - name: token
          in: header
          type: string
          required: true
          description: Authentication token.
    responses:
        200:
            description: Listed files successfully.
        400:
            description: Bad request.
        401:
            description: Unauthorized.
    """
    if 'token' not in request.headers:
        return jsonify({'error': 'No token supplied'}), 401

    if request.headers['token'] != AUTH_TOKEN:
        return jsonify({'error': 'Invalid token supplied'}), 401

    files = []
    for filename in os.listdir(app.config['UPLOAD_DIRECTORY']):
        file_path = os.path.join(app.config['UPLOAD_DIRECTORY'], filename)
        if os.path.isfile(file_path):
            stats = os.stat(file_path)
            size = stats.st_size
            last_modified = datetime.datetime.fromtimestamp(stats.st_mtime).strftime('%Y-%m-%d %H:%M:%S')
            files.append({
                'name': filename,
                'size': size,
                'last_modified': last_modified
            })

    return jsonify({'files': files})

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 5000)))