diff --git a/api/urls.py b/api/urls.py index 31f2307..0ea172b 100644 --- a/api/urls.py +++ b/api/urls.py @@ -3,5 +3,6 @@ urlpatterns = [ path('execute/', api_views.exec_command, name='exec-command'), + path('copy/', api_views.copy_to_clipboard, name='copy-to-clipboard'), path('commands/', api_views.list_commands, name='list-of-commands'), ] diff --git a/api/views.py b/api/views.py index ef663eb..f342225 100644 --- a/api/views.py +++ b/api/views.py @@ -7,7 +7,7 @@ from utils.api.tools import save_received_request, api_response, get_request_data, get_search_query from utils.core import http_status as sc -from utils.core.tools import execute_command +from utils.core.tools import execute_command, copy_content_to_clipboard, linux_package_installed from utils.auth.http.decorators import login_required @@ -106,3 +106,38 @@ def list_commands(request): } return api_response(request, data, commit=True) + + +@require_POST +@csrf_exempt +@login_required(api_endpoint=True) +def copy_to_clipboard(request): + + if not linux_package_installed('xclip'): + return api_response( + request, + status_code=sc.HTTP_400_BAD_REQUEST, + message='xclip package is not installed' + ) + + data = get_request_data(request) + content = data.get('content') + + if not content: + return api_response( + request, + status_code=sc.HTTP_400_BAD_REQUEST, + message='no content provided', + ) + + output = copy_content_to_clipboard(content) + + status_code = sc.HTTP_200_OK if output else sc.HTTP_400_BAD_REQUEST + + return api_response( + request, + data={'content': content}, + status=output, + status_code=status_code, + ) + diff --git a/control/tests.py b/control/tests.py index 165345b..274f9bc 100644 --- a/control/tests.py +++ b/control/tests.py @@ -5,6 +5,8 @@ from utils import generators from utils.generators import stylers +from utils.core.tools import copy_content_to_clipboard, linux_package_installed + import string @@ -70,6 +72,17 @@ def test_render_json_tool(self): self.assertEqual(stylers.render_json(1), 1) +class TestTools(TestCase): + + def test_copy_to_clipboard_tool(self): + if not linux_package_installed('xclip'): + return # stop test if xclip is not installed + + for content in ['hello world', '*', 123, None, '\n', '']: + status = copy_content_to_clipboard(content) + self.assertEqual(status, True) + + class TestMainPage(TestCase): fixtures = ['test_fixtures/fixtures.json'] diff --git a/utils/core/tools.py b/utils/core/tools.py index 0dde02d..fe4150d 100644 --- a/utils/core/tools.py +++ b/utils/core/tools.py @@ -1,4 +1,6 @@ import os +import subprocess +import tempfile def execute_command(command: str) -> [None, str]: @@ -13,3 +15,47 @@ def execute_command(command: str) -> [None, str]: """ return os.popen(command).read() + + +def copy_content_to_clipboard(content): + """ + Copy content to clipboard + + Args: + content (str): content to be copied + + Returns: + bool: True if content is copied + """ + + content = str(content) + with tempfile.NamedTemporaryFile(mode='w+t') as f: + f.write(content) + f.flush() + return_code = subprocess.call( + ['xclip', '-d', ':0', '-selection', 'clipboard', f.name], + stdout=subprocess.PIPE, + ) + + status = True if return_code == 0 else False + return status + + +def linux_package_installed(package_name: str) -> bool: + """ + Check if a linux package is installed + + Args: + package_name (str): package name + + Returns: + bool: True if package is installed + """ + + return_code = subprocess.call( + ['which', package_name], + stdout=subprocess.PIPE, + ) + + status = True if return_code == 0 else False + return status