Перейти к содержанию

MrShandy

Пользователи
  • Постов

    37
  • Зарегистрирован

  • Посещение

  • Победитель дней

    1

Сообщения, опубликованные MrShandy

  1. 2 часа назад, aLEX49566 сказал:

    Нет

    И в чем же вы видите разницу? Прицепились к слову dedicated? Все хостинги сейчас предоставляют виртуализацию KVM, ovz уже редкость (и никто в здравом уме не берет такое).

  2. Есть плагин или приложение для создания страниц коллекций/сборников файлов? Ну то есть я написал заголовок, описание, добавил туда файлы из списка загрузок в форуме, после этого создается страница с этими файлами

    Смотрел это приложение: 

    Либо я не разобрался, либо там вообще не такой функционал, который мне нужен

  3. 4 часа назад, 001 сказал:

    Timeweb отлично справляется с этой задачей. Тестил Хранилище S3 около 1 мес.

    gh.jpg.9cf597bb2c9c7afb8d75fe67a39f335d.jpg

    Таймвеб неудобный, потому что у них платишь за объём. У меня больше 10 гб, но не 100, так зачем мне платить столько?

    Pay-as-you-go в этом случае лучше подходит, на мой взгляд. У меня хранилище в Selectel и Yandex Cloud. Selectel из них подешевле будет вроде

  4. Да, без проблем

    import asyncio
    import base64
    import aiohttp
    
    url = "https://example.com/api/downloads/files"
    token = "токен"
    params = {
        "category": 5,
        "author": 1,
        "title": "archive.zip",
        "description": "<p>This is an archive file.</p>",
        "hidden": 1,
    }
    headers = {"Accept": "application/json"}
    
    
    async def upload_file(data_files: dict):
        auth = aiohttp.BasicAuth(token, "")
        async with aiohttp.ClientSession(auth=auth, headers=headers) as session:
            print("Params:", params)
            print("Data:", data_files)
            async with session.post(url, params=params, data=data_files) as response:
                print("Headers:", response.request_info.headers)
                print("Response JSON:", await response.json())
                print("Response text:", await response.text())
                print("Response status:", response.status)
                print("Response content-type:", response.content_type)
                print("=" * 10)
                if response.ok:
                    print("File uploaded successfully.")
                else:
                    print("Failed to upload file. Error:", await response.text())
    
    
    async def main():
        with open("archive.zip", "rb") as file_content:
            data_files = {
                "files[archive.zip]": base64.b64encode(file_content.read()).decode("utf-8")
            }
        await upload_file(data_files)
    
    
    loop = asyncio.new_event_loop()
    loop.run_until_complete(main())

    Думаю кому будет надо разберется где что менять :)

  5. 1 минуту назад, Desti сказал:

    Ну как затычка временная - пойдет, но проблема никуда не делась. Кстати, на их форуме есть обсуждение подобной проблемы, у человека тоже не получилось загрузить бинарный поток. 

    Какое API такое и решение) Ну если они не смогли даже нормально задокументировать всё, как я должен по другому действовать?

    Вариант рабочий, проблем не должен создать. Если найду решение лучше - обязательно напишу здесь, но пока будет так

  6. Можно закрывать тему, решил 🙂

    Просто заменил строку

    $fileObject = \IPS\File::create( 'downloads_Files', $name, $_POST['files'][ $name ] );

    на

    $fileObject = \IPS\File::create( 'downloads_Files', $name, base64_decode($_POST['files'][ $name ]) );

    На стороне клиента (в моём случае приложения на Python) так:

    "files[archive.zip]": base64.b64encode(file_content.read()).decode('utf-8')

     

  7. Только что, Desti сказал:

    {'files[archive.zip]': b'PK\x03.... это не строка

    Ну а как я должен отправить не текстовую информацию?)

    Не, можно впринципе сделать ход конем и отправлять base64, а на сервере это обратно. Вопрос в адекватности таких действий

  8. 5 минут назад, Desti сказал:

    image.thumb.png.ced5ae042d0d265a2c834d0680f221db.png

    Осталось только превратить содержимое файла в строку. 

    Окей, это работает

    Сейчас проверю с отправкой файла в байтах, иначе как условный архив туда закинуть

    3 минуты назад, MrShandy сказал:

    Сейчас проверю с отправкой файла в байтах, иначе как условный архив туда закинуть

    @Desti, проверил, текст отправляется без проблем. Байты нет, ошибка нет файлов

    Текст:
     

    Спойлер
    Params:
    {'category': 5, 'author': 1, 'title': 'archive.zip', 'description': '<p>This is an archive file.</p>', 'hidden': 1}
    Data:
    {'files[test.txt]': 'text for test'}
    Headers:
    <CIMultiDictProxy('Host': 'scrapmechanic.ru', 'Accept': 'application/json', 'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'Python/3.10 aiohttp/3.8.4', 'Authorization': 'Basic токен', 'Content-Length': '33', 'Content-Type': 'application/x-www-form-urlencoded')>
    Response JSON:
    {'id': 106, 'title': 'archive.zip', 'category': {'id': 5, 'name': 'Постройки', 'url': 'https://scrapmechanic.ru/files/category/5-%D0%BF%D0%BE%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B8/', 'class': 'IPS\\downloads\\Category', 'parentId': 0, 'permissions': {'perm_id': 110, 'perm_view': '*', 'perm_2': '*', 'perm_3': '8,4,7,6,3', 'perm_4': '*', 'perm_5': '8,4,7,6,3', 'perm_6': '8,4,7,6,3', 'perm_7': None}, 'club': 0}, 'author': {'id': 1, 'name': 'MrShandy', 'title': None, 'timeZone': 'Europe/Moscow', 'formattedName': '<strong class="site-administration">MrShandy</strong>', 'primaryGroup': {'id': 4, 'name': 'Администраторы', 'formattedName': '<strong class="site-administration">Администраторы</strong>'}, 'secondaryGroups': [], 'email': '[email protected]', 'joined': '2020-01-01T09:55:00Z', 'registrationIpAddress': '5.187.74.254', 'warningPoints': 0, 'reputationPoints': 20, 'photoUrl': 'https://b.cdn.scrapmechanic.ru/uploads/photos/monthly_2022_08/393072407_redditperson.png.cd76d868c8efde81a749aafb7fe4adbf.png', 'photoUrlIsDefault': False, 'coverPhotoUrl': 'https://b.cdn.scrapmechanic.ru/uploads/photos/monthly_2023_03/p1_3065335_a11db4bd.jpg.ee7c3210a58bc29b1ffe7c88ac7531ee.jpg', 'profileUrl': 'https://scrapmechanic.ru/profile/1-mrshandy/', 'validating': False, 'posts': 203, 'lastActivity': '2024-01-06T16:03:40Z', 'lastVisit': '2024-01-06T13:10:53Z', 'lastPost': '2024-01-06T16:09:18Z', 'birthday': '10/10', 'profileViews': 2188, 'customFields': {'1': {'name': 'Личная информация', 'fields': {'1': {'name': 'Обо мне', 'value': '<p>\n\tСоздатель этого сайта и сервера\xa0<a href="https://discord.gg/TTczVRpKdB" rel="external nofollow">Try Gaming</a>\xa0в discord\n</p>\n\n<p>\n\tПишу ботов на python и иногда стримлю на ютуб <span><span class="ipsEmoji">🙂</span></span>\n</p>\n'}, '2': {'name': 'Аккаунт Discord', 'value': '@mrshandy'}}}}, 'rank': {'id': 7, 'name': 'Техник', 'icon': 'https://a.cdn.scrapmechanic.ru/uploads/monthly_2023_12/8_Regular.svg.8fa0b9f78ee4a5928f9e6007432d4e17.svg', 'points': 1300}, 'achievements_points': 1451, 'allowAdminEmails': False, 'completed': True}, 'date': '2024-01-06T16:09:18Z', 'updated': '2024-01-06T16:09:18Z', 'description': '<p>This is an archive file.</p>', 'version': None, 'changelog': None, 'screenshots': [], 'screenshotsThumbnails': [], 'primaryScreenshot': None, 'primaryScreenshotThumb': None, 'downloads': None, 'comments': 0, 'reviews': 0, 'views': 0, 'prefix': None, 'tags': [], 'locked': False, 'hidden': True, 'pinned': False, 'featured': False, 'url': 'https://scrapmechanic.ru/files/file/106-archivezip/', 'topic': None, 'isPaid': False, 'isPurchasable': False, 'prices': None, 'canDownload': None, 'canBuy': None, 'canReview': None, 'rating': 0, 'purchases': None, 'renewalTerm': None, 'hasPendingVersion': False}
    Response text:
    {
        "id": 106,
        "title": "archive.zip",
        "category": {
            "id": 5,
            "name": "\u041f\u043e\u0441\u0442\u0440\u043e\u0439\u043a\u0438",
            "url": "https:\/\/scrapmechanic.ru\/files\/category\/5-%D0%BF%D0%BE%D1%81%D1%82%D1%80%D0%BE%D0%B9%D0%BA%D0%B8\/",
            "class": "IPS\\downloads\\Category",
            "parentId": 0,
            "permissions": {
                "perm_id": 110,
                "perm_view": "*",
                "perm_2": "*",
                "perm_3": "8,4,7,6,3",
                "perm_4": "*",
                "perm_5": "8,4,7,6,3",
                "perm_6": "8,4,7,6,3",
                "perm_7": null
            },
            "club": 0
        },
        "author": {
            "id": 1,
            "name": "MrShandy",
            "title": null,
            "timeZone": "Europe\/Moscow",
            "formattedName": "<strong class=\"site-administration\">MrShandy<\/strong>",
            "primaryGroup": {
                "id": 4,
                "name": "\u0410\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u044b",
                "formattedName": "<strong class=\"site-administration\">\u0410\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u044b<\/strong>"
            },
            "secondaryGroups": [],
            "email": "[email protected]",
            "joined": "2020-01-01T09:55:00Z",
            "registrationIpAddress": "1.1.1.1",
            "warningPoints": 0,
            "reputationPoints": 20,
            "photoUrl": "https:\/\/b.cdn.scrapmechanic.ru\/uploads\/photos\/monthly_2022_08\/393072407_redditperson.png.cd76d868c8efde81a749aafb7fe4adbf.png",
            "photoUrlIsDefault": false,
            "coverPhotoUrl": "https:\/\/b.cdn.scrapmechanic.ru\/uploads\/photos\/monthly_2023_03\/p1_3065335_a11db4bd.jpg.ee7c3210a58bc29b1ffe7c88ac7531ee.jpg",
            "profileUrl": "https:\/\/scrapmechanic.ru\/profile\/1-mrshandy\/",
            "validating": false,
            "posts": 203,
            "lastActivity": "2024-01-06T16:03:40Z",
            "lastVisit": "2024-01-06T13:10:53Z",
            "lastPost": "2024-01-06T16:09:18Z",
            "birthday": "10\/10",
            "profileViews": 2188,
            "customFields": {
                "1": {
                    "name": "\u041b\u0438\u0447\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f",
                    "fields": {
                        "1": {
                            "name": "\u041e\u0431\u043e \u043c\u043d\u0435",
                            "value": "<p>\n\t\u0421\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u044c \u044d\u0442\u043e\u0433\u043e \u0441\u0430\u0439\u0442\u0430 \u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u00a0<a href=\"https:\/\/discord.gg\/TTczVRpKdB\" rel=\"external nofollow\">Try Gaming<\/a>\u00a0\u0432 discord\n<\/p>\n\n<p>\n\t\u041f\u0438\u0448\u0443 \u0431\u043e\u0442\u043e\u0432 \u043d\u0430 python \u0438 \u0438\u043d\u043e\u0433\u0434\u0430 \u0441\u0442\u0440\u0438\u043c\u043b\u044e \u043d\u0430 \u044e\u0442\u0443\u0431 <span><span class=\"ipsEmoji\">\ud83d\ude42<\/span><\/span>\n<\/p>\n"
                        },
                        "2": {
                            "name": "\u0410\u043a\u043a\u0430\u0443\u043d\u0442 Discord",
                            "value": "@mrshandy"
                        }
                    }
                }
            },
            "rank": {
                "id": 7,
                "name": "\u0422\u0435\u0445\u043d\u0438\u043a",
                "icon": "https:\/\/a.cdn.scrapmechanic.ru\/uploads\/monthly_2023_12\/8_Regular.svg.8fa0b9f78ee4a5928f9e6007432d4e17.svg",
                "points": 1300
            },
            "achievements_points": 1451,
            "allowAdminEmails": false,
            "completed": true
        },
        "date": "2024-01-06T16:09:18Z",
        "updated": "2024-01-06T16:09:18Z",
        "description": "<p>This is an archive file.<\/p>",
        "version": null,
        "changelog": null,
        "screenshots": [],
        "screenshotsThumbnails": [],
        "primaryScreenshot": null,
        "primaryScreenshotThumb": null,
        "downloads": null,
        "comments": 0,
        "reviews": 0,
        "views": 0,
        "prefix": null,
        "tags": [],
        "locked": false,
        "hidden": true,
        "pinned": false,
        "featured": false,
        "url": "https:\/\/scrapmechanic.ru\/files\/file\/106-archivezip\/",
        "topic": null,
        "isPaid": false,
        "isPurchasable": false,
        "prices": null,
        "canDownload": null,
        "canBuy": null,
        "canReview": null,
        "rating": 0,
        "purchases": null,
        "renewalTerm": null,
        "hasPendingVersion": false
    }
    Response status:
    201
    Response content-type:
    application/json
    ==========
    File uploaded successfully.

    Для байтов:
     

    Спойлер
    Params:
    {'category': 5, 'author': 1, 'title': 'archive.zip', 'description': '<p>This is an archive file.</p>', 'hidden': 1}
    Data:
    {'files[archive.zip]': b'PK\x03\x04\x14\x00\x00\x00\x08\x00\x1d`\xf3V2\xc6\np\xbd\x01\x00\x00*\x03\x00\x00\x07\x00\x00\x00main.pymRM\x8f\xd30\x10\xbdG\xca\x7f\x18\x89\x83\x1b)\x9b\xb44\x9be#\xf5\xb0\x12 q\xe0\x06\x12\x12\xe2\xe0\xd8\x93\xc6\xda\xc46\xb6\x03t\x11\xff\x1d\xdbqKw\x85\xe5\x83g<\xef\xbd\xf9\x12\xb3V\xc6AO-\xb6M\x9e\xe5Yr\x18\xfc\xbe\xa0u6\xb8\x163\xc1\x01\xc8\xe8\x9c\xb6]][f\xa8\x9e\x91\x8dT\nV\x99\xa5\xa6Z\xd4\\\xfd\x94\x93\xa2\xdc\xd6\x83\x98\xd0\x92<s\xea\x11e\xc0\xe1\xb6i\x18\xc5v\x8b\x03\xbd\xc3\xfb\xbb}\xdb\xf48 \xbf\x7f\xd3\xb3]?\xec}\xac\xa6\x86\xce\xd6\x07\xff\xce3\xf0\x870\xea\xf0\xa8\xcc\x89t\xb0{\xbd/\x01^\xc1\x87\xb7 \x97\xb9G\x03j\x007"\x9cc\xa2\x11T\xc1\x8ej\x998\xf4\xfe\xcf\xa0\xff\xe5 d"\xa4\x8b\x1b\x95\xf1t\xcdm\xfb\x7f\xba\x19\xa3\x15\x91B\x1e/\xac\x89\xc0\t7\xa1\xc7\x13j\xd8(~`\xf5$4\x89LQZ\xd2\xf9\x1c\xc9\xd1wHh\'\x94\x0c\xf1\x9fFa\xc1_*!A#\xa2\xba\x02_!\x12\xc7\xda\xc4\xee\xdc\x8fp\x9e\tw\xa04\xca\xcd\x8bd\x88\xe9IqaeJ:\x94ne\xf8\x93g\xfe\x8eH9\x9a\xebF\x7f\xb9y\x88\x9d\x11O4%\xbc\xaeB\xd5\xb7\rJ\xa68n\xe2 \xabd\x14E\xc5q}\x95\x89\xe2\xb3Es\xf3p\xf4R\xa1\xdc\x8f\xa7`G\xb3\xdeU[\x12u\xf3\xcc\xa0\xd5JZ\x84\xc3e\xb5*\xad\xac\xdb\xf8\xe5*c\xbe\xf6\xb0n\xc1\xd7T\xfc\xb7\x128u4y\x0b\xbf\x99\x03\x9cY*\xf5\xd8\xad\xea\xda\x08\xe96\xe4}(x\xd1a\x03\xfd\xd4\xed\xc2\x18Z;,\xd3t\xaa\x88\x87\xe2d\xf1\x05\x80z\x04\x07\xa7\x12j\x9d\t\xbc3F\x99\x8e\x94\xff\x94\x1c\xferE\xa8\xe0/PK\x01\x02\x1f\x00\x14\x00\x00\x00\x08\x00\x1d`\xf3V2\xc6\np\xbd\x01\x00\x00*\x03\x00\x00\x07\x00$\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00main.py\n\x00 \x00\x00\x00\x00\x00\x01\x00\x18\x00\x9d\x82\xe6\x88\x1f\xba\xd9\x01\x9d\x82\xe6\x88\x1f\xba\xd9\x01\x07Rx\xa3\x1e\xba\xd9\x01PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00Y\x00\x00\x00\xe2\x01\x00\x00\x00\x00'}
    Headers:
    <CIMultiDictProxy('Host': 'scrapmechanic.ru', 'Accept': 'application/json', 'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'Python/3.10 aiohttp/3.8.4', 'Authorization': 'Basic токен', 'Content-Length': '826', 'Content-Type': 'multipart/form-data; boundary=33af861834ce49e583ecfc15980f1840')>
    Response JSON:
    {'errorCode': '1L296/B', 'errorMessage': 'NO_FILES'}
    Response text:
    {
        "errorCode": "1L296\/B",
        "errorMessage": "NO_FILES"
    }
    Response status:
    400
    Response content-type:
    application/json
    ==========
    Failed to upload file. Error: {
        "errorCode": "1L296\/B",
        "errorMessage": "NO_FILES"
    }

    Забавно на самом деле

  9. Только что, Desti сказал:

    files - Keys should be filename (e.g. 'file.txt') and values should be file content

    Только при этом ниже имеем:

    foreach ( array_keys( Request::i()->files ) as $name )
    		{
    			$fileObject = \IPS\File::create( 'downloads_Files', $name, $_POST['files'][ $name ] );
    			
    			Db::i()->insert( 'downloads_files_records', array(
    				'record_file_id'	=> $file->id,
    				'record_type'		=> 'upload',
    				'record_location'	=> (string) $fileObject,
    				'record_realname'	=> $fileObject->originalFilename,
    				'record_size'		=> $fileObject->filesize(),
    				'record_time'		=> time(),
    			) );
    		}

    То есть файлы должны быть и в $_POST? Я не знаю php, но $_POST это же data, а не параметры, правильно? 

    Ну и опять же, в параметры невозможно передать dict. Это как минимум не логично

    Traceback (most recent call last):
      File "C:\Users\MrSha\Documents\Projects\ICFileUploader\main.py", line 57, in <module>
        loop.run_until_complete(main())
      File "C:\Users\MrSha\AppData\Local\Programs\Python\Python310\lib\asyncio\base_events.py", line 649, in run_until_complete
        return future.result()
      File "C:\Users\MrSha\Documents\Projects\ICFileUploader\main.py", line 52, in main
        await upload_file(data_files)
      File "C:\Users\MrSha\Documents\Projects\ICFileUploader\main.py", line 27, in upload_file
        async with session.post(url, params=params, data=data_files) as response:
      File "C:\Users\MrSha\.virtualenvs\ICFileUploader-DZz49JbJ\lib\site-packages\aiohttp\client.py", line 1141, in __aenter__
        self._resp = await self._coro
      File "C:\Users\MrSha\.virtualenvs\ICFileUploader-DZz49JbJ\lib\site-packages\aiohttp\client.py", line 508, in _request
        req = self._request_class(
      File "C:\Users\MrSha\.virtualenvs\ICFileUploader-DZz49JbJ\lib\site-packages\aiohttp\client_reqrep.py", line 283, in __init__
        url2 = url.with_query(params)
      File "C:\Users\MrSha\.virtualenvs\ICFileUploader-DZz49JbJ\lib\site-packages\yarl\_url.py", line 1007, in with_query
        new_query = self._get_str_query(*args, **kwargs) or ""
      File "C:\Users\MrSha\.virtualenvs\ICFileUploader-DZz49JbJ\lib\site-packages\yarl\_url.py", line 968, in _get_str_query
        query = "&".join(self._query_seq_pairs(quoter, query.items()))
      File "C:\Users\MrSha\.virtualenvs\ICFileUploader-DZz49JbJ\lib\site-packages\yarl\_url.py", line 931, in _query_seq_pairs
        yield quoter(key) + "=" + quoter(cls._query_var(val))
      File "C:\Users\MrSha\.virtualenvs\ICFileUploader-DZz49JbJ\lib\site-packages\yarl\_url.py", line 946, in _query_var
        raise TypeError(
    TypeError: Invalid variable type: value should be str, int or float, got {'archive.zip': [b'PK\x03\x04\x14\x00\x00\x00\x08\x00\x1d`\xf3V2\xc6\np\xbd\x01\x00\x00*\x03\x00\x00\x07\x00\x00\x00main.pymRM\x8f\xd30\x10\xbdG\xca\x7f\x18\x89\x83\x1b)\x9b\xb44\x9be#\xf5\xb0\x12 q\xe0\x06\x12\x12\xe2\xe0\xd8\x93\xc6\xda\xc46\xb6\x03t\x11\xff\x1d\xdbqKw\x85\xe5\x83g<\xef\xbd\xf9\x12\xb3V\xc6AO-\xb6M\x9e\xe5Yr\x18\xfc\xbe\xa0u6\xb8\x163\xc1\x01\xc8\xe8\x9c\xb6]][f\xa8\x9e\x91\x8dT\nV\x99\xa5\xa6Z\xd4\\\xfd\x94\x93\xa2\xdc\xd6\x83\x98\xd0\x92<s\xea\x11e\xc0\xe1\xb6i\x18\xc5v\x8b\x03\xbd\xc3\xfb\xbb}\xdb\xf48 \xbf\x7f\xd3\xb3]?\xec}\xac\xa6\x86\xce\xd6\x07\xff\xce3\xf0\x870\xea\xf0\xa8\xcc\x89t\xb0{\xbd/\x01^\xc1\x87\xb7 \x97\xb9G\x03j\x007"\x9cc\xa2\x11T\xc1\x8ej\x998\xf4\xfe\xcf\xa0\xff\xe5 d"\xa4\x8b\x1b\x95\xf1t\xcdm\xfb\x7f\xba\x19\xa3\x15\x91B\x1e/\xac\x89\xc0\t7\xa1\xc7\x13j\xd8(~`\xf5$4\x89LQZ\xd2\xf9\x1c\xc9\xd1wHh\'\x94\x0c\xf1\x9fFa\xc1_*!A#\xa2\xba\x02_!\x12\xc7\xda\xc4\xee\xdc\x8fp\x9e\tw\xa04\xca\xcd\x8bd\x88\xe9IqaeJ:\x94ne\xf8\x93g\xfe\x8eH9\x9a\xebF\x7f\xb9y\x88\x9d\x11O4%\xbc\xaeB\xd5\xb7\rJ\xa68n\xe2 \xabd\x14E\xc5q}\x95\x89\xe2\xb3Es\xf3p\xf4R\xa1\xdc\x8f\xa7`G\xb3\xdeU[\x12u\xf3\xcc\xa0\xd5JZ\x84\xc3e\xb5*\xad\xac\xdb\xf8\xe5*c\xbe\xf6\xb0n\xc1\xd7T\xfc\xb7\x128u4y\x0b\xbf\x99\x03\x9cY*\xf5\xd8\xad\xea\xda\x08\xe96\xe4}(x\xd1a\x03\xfd\xd4\xed\xc2\x18Z;,\xd3t\xaa\x88\x87\xe2d\xf1\x05\x80z\x04\x07\xa7\x12j\x9d\t\xbc3F\x99\x8e\x94\xff\x94\x1c\xferE\xa8\xe0/PK\x01\x02\x1f\x00\x14\x00\x00\x00\x08\x00\x1d`\xf3V2\xc6\np\xbd\x01\x00\x00*\x03\x00\x00\x07\x00$\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00main.py\n\x00 \x00\x00\x00\x00\x00\x01\x00\x18\x00\x9d\x82\xe6\x88\x1f\xba\xd9\x01\x9d\x82\xe6\x88\x1f\xba\xd9\x01\x07Rx\xa3\x1e\xba\xd9\x01PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00Y\x00\x00\x00\xe2\x01\x00\x00\x00\x00']} of type <class 'dict'>
    

     

  10. 1 минуту назад, Desti сказал:

    У тебя в запрос улетает ...api/downloads/files?category=1&author=1&title=archive.zip&description=%3Cp%3EThis+is+an+archive+file.%3C/p%3E&hidden=1&files=archive.zip

    Т.е. files должен быть массивом, а уходит строка. Как это починить - не знаю, питон не мое.  

    Ну допустим так, но надо как то туда передать список? Если это вообще возможно передать в параметрах. Мне бы просто понять как отправлять, хотя бы через postman, а там уже разберусь как на питоне написать

    API у них убогий какой то, можно было в разы лучше сделать

  11. 11 минут назад, Desti сказал:

    там же просто всё - 

    isset( \IPS\Request::i()->files ) or !\is_array( \IPS\Request::i()->files ) or empty( \IPS\Request::i()->files ) )

    Ну я видел это, передаю список, но результат ошибка. Как мне запрос то делать надо?

  12. Только что, Desti сказал:

    print(params) чего показывает в upload_file?

    Params:
    {'category': 5, 'author': 1, 'title': 'archive.zip', 'description': '<p>This is an archive file.</p>', 'hidden': 1, 'files': ['archive.zip']}
    Data:
    {'archive.zip': [b'PK\x03\x04\x14\x00\x00\x00\x08\x00\x1d`\xf3V2\xc6\np\xbd\x01\x00\x00*\x03\x00\x00\x07\x00\x00\x00main.pymRM\x8f\xd30\x10\xbdG\xca\x7f\x18\x89\x83\x1b)\x9b\xb44\x9be#\xf5\xb0\x12 q\xe0\x06\x12\x12\xe2\xe0\xd8\x93\xc6\xda\xc46\xb6\x03t\x11\xff\x1d\xdbqKw\x85\xe5\x83g<\xef\xbd\xf9\x12\xb3V\xc6AO-\xb6M\x9e\xe5Yr\x18\xfc\xbe\xa0u6\xb8\x163\xc1\x01\xc8\xe8\x9c\xb6]][f\xa8\x9e\x91\x8dT\nV\x99\xa5\xa6Z\xd4\\\xfd\x94\x93\xa2\xdc\xd6\x83\x98\xd0\x92<s\xea\x11e\xc0\xe1\xb6i\x18\xc5v\x8b\x03\xbd\xc3\xfb\xbb}\xdb\xf48 \xbf\x7f\xd3\xb3]?\xec}\xac\xa6\x86\xce\xd6\x07\xff\xce3\xf0\x870\xea\xf0\xa8\xcc\x89t\xb0{\xbd/\x01^\xc1\x87\xb7 \x97\xb9G\x03j\x007"\x9cc\xa2\x11T\xc1\x8ej\x998\xf4\xfe\xcf\xa0\xff\xe5 d"\xa4\x8b\x1b\x95\xf1t\xcdm\xfb\x7f\xba\x19\xa3\x15\x91B\x1e/\xac\x89\xc0\t7\xa1\xc7\x13j\xd8(~`\xf5$4\x89LQZ\xd2\xf9\x1c\xc9\xd1wHh\'\x94\x0c\xf1\x9fFa\xc1_*!A#\xa2\xba\x02_!\x12\xc7\xda\xc4\xee\xdc\x8fp\x9e\tw\xa04\xca\xcd\x8bd\x88\xe9IqaeJ:\x94ne\xf8\x93g\xfe\x8eH9\x9a\xebF\x7f\xb9y\x88\x9d\x11O4%\xbc\xaeB\xd5\xb7\rJ\xa68n\xe2 \xabd\x14E\xc5q}\x95\x89\xe2\xb3Es\xf3p\xf4R\xa1\xdc\x8f\xa7`G\xb3\xdeU[\x12u\xf3\xcc\xa0\xd5JZ\x84\xc3e\xb5*\xad\xac\xdb\xf8\xe5*c\xbe\xf6\xb0n\xc1\xd7T\xfc\xb7\x128u4y\x0b\xbf\x99\x03\x9cY*\xf5\xd8\xad\xea\xda\x08\xe96\xe4}(x\xd1a\x03\xfd\xd4\xed\xc2\x18Z;,\xd3t\xaa\x88\x87\xe2d\xf1\x05\x80z\x04\x07\xa7\x12j\x9d\t\xbc3F\x99\x8e\x94\xff\x94\x1c\xferE\xa8\xe0/PK\x01\x02\x1f\x00\x14\x00\x00\x00\x08\x00\x1d`\xf3V2\xc6\np\xbd\x01\x00\x00*\x03\x00\x00\x07\x00$\x00\x00\x00\x00\x00\x00\x00 \x00\x00\x00\x00\x00\x00\x00main.py\n\x00 \x00\x00\x00\x00\x00\x01\x00\x18\x00\x9d\x82\xe6\x88\x1f\xba\xd9\x01\x9d\x82\xe6\x88\x1f\xba\xd9\x01\x07Rx\xa3\x1e\xba\xd9\x01PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00Y\x00\x00\x00\xe2\x01\x00\x00\x00\x00']}
    

     

  13. Только что, ryancoolround сказал:

    А если использовать форму multipart/form-data?

    Ну заголовками управляет aiohttp, моё дело рулить данными

    Вот какие он выставляет

    Headers:
    <CIMultiDictProxy('Host': 'scrapmechanic.ru', 'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'Python/3.10 aiohttp/3.8.4', 'Authorization': 'Basic токен', 'Content-Length': '1485', 'Content-Type': 'application/x-www-form-urlencoded')>

     

    Насильно выставить multipart/form-data не дало результата

    Headers:
    <CIMultiDictProxy('Host': 'scrapmechanic.ru', 'Accept': 'application/json', 'Content-Type': 'multipart/form-data', 'Accept-Encoding': 'gzip, deflate', 'User-Agent': 'Python/3.10 aiohttp/3.8.4', 'Authorization': 'Basic токен', 'Content-Length': '1485')>
    Response JSON:
    {'errorCode': '1L296/B', 'errorMessage': 'NO_FILES'}
    

     

  14. Не совсем понимаю как мне загружать файлы по REST API. Написал скрипт на python для загрузки, но как бы я не пробовал, ничего не получается. Если кто то делал, можете подсказать как именно отправляли файлы?

    Вот скрипт, может я в чем то ошибаюсь? Хотя мы с напарником многое перепробовали уже и пока никаких результатов.

    Спойлер
    import asyncio
    
    import aiohttp
    
    url = 'https://scrapmechanic.ru/api/downloads/files'
    token = 'API KEY'
    params = {
        'category': 5,
        'author': 1,
        'title': 'archive.zip',
        'description': '<p>This is an archive file.</p>',
        'hidden': 1,
    }
    
    
    async def upload_file(data_files: dict):
        auth = aiohttp.BasicAuth(token, "")
        async with aiohttp.ClientSession(auth=auth) as session:
            print("Params:")
            print(params)
            print("Data:")
            print(data_files)
            async with session.post(url, params=params, data=data_files) as response:
                print("Headers:")
                print(response.request_info.headers)
                print("Response JSON:")
                print(await response.json())
                print("Response text:")
                print(await response.text())
                print("Response status:")
                print(response.status)
                print("Response content-type:")
                print(response.content_type)
                print("=" * 10)
                if response.ok:
                    print('File uploaded successfully.')
                else:
                    print('Failed to upload file. Error:', await response.text())
    
    
    async def main():
        file_content = open('archive.zip', 'rb')
        data_files = {
            "archive.zip": [file_content.read()],
        }
        params['files'] = [key for key in data_files.keys()]
        await upload_file(data_files)
        file_content.close()
    
    
    loop = asyncio.new_event_loop()
    loop.run_until_complete(main())

    Вот часть кода API, ориентировался на него когда писал скрипт.

    Спойлер
    	/**
    	 * POST /downloads/files
    	 * Upload a file
    	 *
    	 * @note	For requests using an OAuth Access Token for a particular member, any parameters the user doesn't have permission to use are ignored (for example, locked will only be honoured if the authenticated user has permission to lock files).
    	 * @reqapiparam	int					category		The ID number of the category the file should be created in
    	 * @reqapiparam	int					author			The ID number of the member creating the file (0 for guest). Required for requests made using an API Key or the Client Credentials Grant Type. For requests using an OAuth Access Token for a particular member, that member will always be the author
    	 * @reqapiparam	string				title			The file name
    	 * @reqapiparam	string				description		The description as HTML (e.g. "<p>This is an file.</p>"). Will be sanatized for requests using an OAuth Access Token for a particular member; will be saved unaltered for requests made using an API Key or the Client Credentials Grant Type.
    	 * @apiparam	string				version			The version number
    	 * @reqapiparam	object				files			Files. Keys should be filename (e.g. 'file.txt') and values should be file content
    	 * @apiparam	object				screenshots		Screenshots. Keys should be filename (e.g. 'screenshot1.png') and values should be file content.
    	 * @apiparam	string				prefix			Prefix tag
    	 * @apiparam	string				tags			Comma-separated list of tags (do not include prefix)
    	 * @apiparam	datetime			date			The date/time that should be used for the file post date. If not provided, will use the current date/time. Ignored for requests using an OAuth Access Token for a particular member.
    	 * @apiparam	string				ip_address		The IP address that should be stored for the file. If not provided, will use the IP address from the API request. Ignored for requests using an OAuth Access Token for a particular member.
    	 * @apiparam	int					locked			1/0 indicating if the file should be locked
    	 * @apiparam	int					hidden			0 = unhidden; 1 = hidden, pending moderator approval; -1 = hidden (as if hidden by a moderator)
    	 * @apiparam	int					pinned			1/0 indicating if the file should be featured
    	 * @apiparam	int					featured		1/0 indicating if the file should be featured
    	 * @apiparam	bool				anonymous		If 1, the item will be posted anonymously.
    	 * @throws		1S303/7				NO_CATEGEORY	The category ID does not exist
    	 * @throws		1S303/8				NO_AUTHOR		The author ID does not exist
    	 * @throws		1S303/9				NO_TITLE		No title was supplied
    	 * @throws		1S303/A				NO_DESC			No description was supplied
    	 * @throws		1S303/B				NO_FILES		No files were supplied
    	 * @throws		2S303/H				NO_PERMISSION	The authorized user does not have permission to create a file in that category
    	 * @throws		1S303/I				BAD_FILE_EXT	One of the files has a file type that is not allowed
    	 * @throws		1S303/J				BAD_FILE_SIZE	One of the files is too big
    	 * @throws		1S303/K				BAD_SS			One of the screenshots is not a valid image
    	 * @throws		1S303/L				BAD_SS_SIZE		One of the screenshots is too big by filesize
    	 * @throws		1S303/M				BAD_SS_DIMS		One of the screenshots is too big by dimensions
    	 * @throws		1S303/N				NO_SS			No screenshots are provided, but screenshots are required for the category
    	 * @return		\IPS\downloads\File
    	 */
    	public function POSTindex()
    	{
    		/* Get category */
    		try
    		{
    			$category = \IPS\downloads\Category::load( \IPS\Request::i()->category );
    		}
    		catch ( \OutOfRangeException $e )
    		{
    			throw new \IPS\Api\Exception( 'NO_CATEGEORY', '1S303/7', 400 );
    		}
    		
    		/* Get author */
    		if ( $this->member )
    		{
    			if ( !$category->can( 'add', $this->member ) )
    			{
    				throw new \IPS\Api\Exception( 'NO_PERMISSION', '2S303/H', 403 );
    			}
    			$author = $this->member;
    		}
    		else
    		{
    			if ( \IPS\Request::i()->author )
    			{
    				$author = \IPS\Member::load( \IPS\Request::i()->author );
    				if ( !$author->member_id )
    				{
    					throw new \IPS\Api\Exception( 'NO_AUTHOR', '1S303/8', 400 );
    				}
    			}
    			else
    			{
    				if ( \IPS\Request::i()->author === 0 ) 
    				{
    					$author = new \IPS\Member;
    					$author->name = \IPS\Request::i()->author_name;
    				}
    				else 
    				{
    					throw new \IPS\Api\Exception( 'NO_AUTHOR', '1S303/8', 400 );
    				}
    			}
    		}
    		
    		/* Check we have a title and a description */
    		if ( !\IPS\Request::i()->title )
    		{
    			throw new \IPS\Api\Exception( 'NO_TITLE', '1S303/9', 400 );
    		}
    		if ( !\IPS\Request::i()->description )
    		{
    			throw new \IPS\Api\Exception( 'NO_DESC', '1S303/A', 400 );
    		}
    		
    		/* Validate files */
    		if ( !isset( \IPS\Request::i()->files ) or !\is_array( \IPS\Request::i()->files ) or empty( \IPS\Request::i()->files ) )
    		{
    			throw new \IPS\Api\Exception( 'NO_FILES', '1L296/B', 400 );
    		}
    		if ( $this->member )
    		{
    			$this->_validateFilesForMember( $category );
    		}
    		
    		/* Create file record */
    		$file = $this->_create( $category, $author );
    				
    		/* Save records */
    		foreach ( array_keys( \IPS\Request::i()->files ) as $name )
    		{
    			$fileObject = \IPS\File::create( 'downloads_Files', $name, $_POST['files'][ $name ] );
    			
    			\IPS\Db::i()->insert( 'downloads_files_records', array(
    				'record_file_id'	=> $file->id,
    				'record_type'		=> 'upload',
    				'record_location'	=> (string) $fileObject,
    				'record_realname'	=> $fileObject->originalFilename,
    				'record_size'		=> $fileObject->filesize(),
    				'record_time'		=> time(),
    			) );
    		}
    		if ( $category->bitoptions['allowss'] and isset( \IPS\Request::i()->screenshots ) )
    		{
    			$primary = 1;
    			foreach ( array_keys( \IPS\Request::i()->screenshots ) as $name )
    			{
    				$fileObject = \IPS\File::create( 'downloads_Screenshots', $name, $_POST['screenshots'][ $name ] );
    				
    				\IPS\Db::i()->insert( 'downloads_files_records', array(
    					'record_file_id'		=> $file->id,
    					'record_type'			=> 'ssupload',
    					'record_location'		=> (string) $fileObject,
    					'record_thumb'			=> (string) $fileObject->thumbnail( 'downloads_Screenshots' ),
    					'record_realname'		=> $fileObject->originalFilename,
    					'record_size'			=> \strlen( $fileObject->contents() ),
    					'record_time'			=> time(),
    					'record_no_watermark'	=> NULL,
    					'record_default'		=> $primary
    				) );
    				
    				$primary = 0;
    			}
    		}
    		
    		/* Recaluclate properties */
    		$file = $this->_recalculate( $file );
    		
    		/* Return */
    		$file->save();
    		return new \IPS\Api\Response( 201, $file->apiOutput( $this->member ) );
    	}

     

    Ошибку постоянно получаю эту:

    Failed to upload file. Error: {
        "errorCode": "1L296\/B",
        "errorMessage": "NO_FILES"
    }

    Если вывести \IPS\Request::i()->files вместо 'NO_FILES' выводится последний элемент массива files. Пока не понял логику этого

  15. 4 часа назад, Ronyk сказал:

    Да раньше из коробки было , но по пользоваться я не успел , а вот на xenforo данный способ хранения файлов очень даже хорошо заходил по своему опыту проверенно.

    Во дела, интересно

  16. 2 часа назад, Desti сказал:

    Как конкретно - без понятия. Есть ftp протокол, над ним надо сделать подходящий для движка интерфейс. 

    Нет, ну понятно, что протокол передачи есть, а как отдавать этот контент? Сам фтп на фронте по понятным причинам работать не будет, веб сервер на хранилище делать?

    Правда такое раньше было? Очень интересно узнать как работало

  17. 1 час назад, PiratRu сказал:

    Нтааак... вносились изменения в конфиг Nginx? 

    Что именно вносилось?

    Ну, все перечислять долго. Ну а если в общем, то изменение client_max_body_size и установка времени кэширования

    Проблема была в том, что когда то пытался перейти с apache на php-fpm, но затея провалилась и я забыл убрать локацию /api из конфига

    Но главное проблема решена, так что всё гуд

  18. Возникла потребность во внешнем инструменте, решил взаимодействовать через API, но обнаружил проблему. При попытке сделать GET запрос api/core/hello получаю это:

    {
        "errorCode": "3S290/3",
        "errorMessage": "INVALID_APP"
    }

    Не знаю когда и почему возникла ошибка, но раньше API работало без ошибок.

    Любой запрос возвращает такую ошибку. Ключ API действительный.

    На сайте https://invisioncommunity.com/developers/rest-api написано:

    3S290/3 INVALID_APP The endpoint the request was sent to does not exist (the first level contains an invalid character, only alphanumerics are acceptable).

    Но по идее у меня все правильно настроено, в т.ч. в .htaccess. Эндпоинт правильный

  19. 4 часа назад, Dusty сказал:

    в настройках плагина смотрели или в разделе звание/репутация вроде

    В настройках плагина ничего интересного нет
    image.png.4fed439ba7f8b46926c10c8ff807ce27.png

    В настройках званий или репутации тоже ничего интересного нет. Вообще судя по всему оно выводит уровень под текущим аккаунтом. Для гостя у всех будет 1 уровень

×
×
  • Создать...