{"id":20555172,"url":"https://github.com/angela-d/zendesk-multi-ticket","last_synced_at":"2025-07-24T11:40:08.019Z","repository":{"id":112030404,"uuid":"420327747","full_name":"angela-d/zendesk-multi-ticket","owner":"angela-d","description":"A single form to create multiple, simultaneous custom tickets based on form content.","archived":false,"fork":false,"pushed_at":"2021-10-23T06:04:04.000Z","size":1235,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-16T18:00:45.083Z","etag":null,"topics":["python-bottle","python-scripts","python-server","python3","zendesk","zendesk-api","zendesk-tickets"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/angela-d.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-23T05:58:28.000Z","updated_at":"2021-10-23T06:05:41.000Z","dependencies_parsed_at":"2023-04-19T08:32:08.425Z","dependency_job_id":null,"html_url":"https://github.com/angela-d/zendesk-multi-ticket","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angela-d%2Fzendesk-multi-ticket","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angela-d%2Fzendesk-multi-ticket/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angela-d%2Fzendesk-multi-ticket/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angela-d%2Fzendesk-multi-ticket/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/angela-d","download_url":"https://codeload.github.com/angela-d/zendesk-multi-ticket/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242160335,"owners_count":20081649,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["python-bottle","python-scripts","python-server","python3","zendesk","zendesk-api","zendesk-tickets"],"created_at":"2024-11-16T03:16:53.020Z","updated_at":"2025-03-06T06:29:05.772Z","avatar_url":"https://github.com/angela-d.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Zendesk Form to Multiple Tickets\nTicket generator to delegate IT tasks by opening multiple simultaneous, customized tickets from a single form (based on content or \"category\" from the ticket submitter).\n\nExample form is an IT onboarding request for a new hire at an organization.\n\nEach member of IT has a separate ticket generated, specifically for what they need to do.\n\n## Setup\nThis script uses Zendesk API tokens.\n\nModify the following to suit your agent/token (in **new.py**):\n```python\n# api config\nheaders = {'content-type': 'application/json'}\nuser = 'myagent@example.com/token'\napi_token = '2zFD893XpPWQFhj235FyHV5WpNGpTcdDFKk65n'\nurl = 'https://example.zendesk.com/api/v2/requests.json'\n```\n\nFor the agent(s) you want to pre-assign (this is currently non-functional but not in a breaking state, cc is working -- see 'Known Bugs' section.):\n```python\n# agent id\nphone_agent = '001'\ntech_trainer = '002'\nadmin_agent = '003'\nemail_agent = '004'\ncomputer_agent = '005'\n```\n\n- First, install dependencies to the server.  My OS of choice is Debian-based Linux, which uses the apt package manager.\n  ```bash\n  apt install python3-bottle nginx\n  ```\n\n- Make a directory for your form, for example:\n  ```bash\n  /var/www/employee-forms\n  ```\n\n- Go into the directory on the remote server where the application is kept, install Python dependencies:\n  - :warning: Do not use pip under sudo/root! *Standard user only!* -- it should be the user you want your Python server to run as (also, **should not be root**)\n  ```bash\n  cd /var/www/employee-forms\n  pip3 install -r requirements.txt\n  ```\n\n\n\n  \u003e It's worth noting that Pip isn't a package manager like apt.  These packages need to be *manually* updated, so a means to watch for security updates.\n  \u003e\n  \u003e Pip packages also aren't subject to being signed packages.  So it's not difficult at all for someone to get a hold of a package developer's credentials and upload an update  ([Has happened to Python, too](https://www.zdnet.com/article/malicious-python-libraries-targeting-linux-servers-removed-from-pypi/))\n\n\n- Create a service for the application; this is necessary as Python is not a \"web language,\" so it requires a server overlay to execute stuff for web-facing stuff like webpages.  This will launch the script that loads the server. (You can load modules to run Python through Nginx or Apache, optionally)\n  ```bash\n  pico /etc/systemd/system/newemployee.service\n  ```\n\n  - Populate with the following\n    ```bash\n    [Unit]\n    Description=New Employee Form\n    After=network.target\n\n    [Service]\n    User=YOUR_USER ### dont use root...\n    ExecStart=/var/www/employee-forms/new.py\n    WorkingDirectory=/var/www/employee-forms/\n    Restart=on-failure\n    RemainAfterExit=yes\n\n    [Install]\n    WantedBy=multi-user.target\n    ```\n\n- Test it\n  ```bash\n  systemctl service newemployee start\n  ```\n\n- Create a startup service (after server reboot, it will be auto-started):\n  ```bash\n  systemctl enable newemployee\n  ```\n\n### How does the Python server work?\nNote the following from the systemd unit file:\n```bash\nExecStart=/var/www/employee-forms/new.py\n```\nOpen that file:\n```bash\npico /var/www/employee-forms/new.py\n```\n\nThis is what speaks to nginx:\n```python\nrun(server='paste', host='localhost', port=8081, debug=True)\n```\nNote that the port can be anything; 8080 was already in use (for me), so I simply incremented to the next available port.\n\nTo change from dev to prod, change:\n```python\nrun(server='paste', host='localhost', port=8081, debug=True)\n```\n\nto:\n```python\nrun(server='paste', host='localhost', port=8081, debug=False)\n```\n\n\n## On an Nginx-based system - Virtualhost Setup\nThe following assumes you already have DNS pointed at the server for your subdomain.\n\nVirtualhost config for Nginx lives in `/etc/nginx`\nCopy a pre-configured virtualhost, to save time\n\n*(All of) the following steps are technically not required with Nginx (in this manner), but to keep similarity between Nginx and Apache systems, I keep the sites-available/sites-enabled setup.*\n\n- **Port 80/non-SSL (direct URL types)**\n  ```bash\n  cp /etc/nginx/sites-available/existing_site.conf /etc/nginx/sites-available/newemployee.conf\n  ```\n\n- Symlink it to sites-enabled (this is the only step you'd have to do if you didn't care about Apache synchronicity) -- to break Apache-like behavior, bypass *sites-available* \u0026 use *sites-enabled*, only.\n  ```bash\n  ln -s /etc/nginx/sites-available/newemployee.conf /etc/nginx/sites-enabled/newemployee.conf\n  ```\n\n  - Contents of *newemployee*:\n    ```bash\n    server {\n        listen 80;\n\n        server_name newemployee.example.com;\n        client_max_body_size 25m;\n\n        location / {\n            return 301 https://newemployee.example.com/create_ticket;\n        }\n    }\n    ```\n\n- **Port 443/SSL (destination)**\n  ```bash\n  cp /etc/nginx/sites-available/existing-site-ssl.conf /etc/nginx/sites-available/newemployee-ssl.conf\n  ```\n- Symlink it to sites-enabled\n  ```bash\n  ln -s /etc/nginx/sites-available/newemployee-ssl.conf /etc/nginx/sites-enabled/newemployee-ssl.conf\n  ```\n\n  - Contents of *newemployee-ssl.conf* (note the proxy_pass field):\n    ```bash\n    server {\n        listen 443;\n        ssl on;\n        server_name newmployee.example.com;\n        root /var/www/employee-forms/;\n        index new.py;\n        ssl_certificate /path/to/your/cert.pem;\n        ssl_certificate_key /path/to/your/key.pem;\n        client_max_body_size 25m;\n\n        location / {\n            proxy_pass http://127.0.0.1:8081;\n            proxy_set_header X-Forwarded-Host $server_name;\n            proxy_set_header X-Real-IP $remote_addr;\n            proxy_set_header X-Forwarded-Proto $scheme;\n            add_header P3P 'CP=\"ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV\"';\n        }\n    }\n    ```\n\n## Breakdown\n***\n\n- Form fields (template) are housed under `/var/www/employee-forms/views/ticket_form.tpl`\n  - Plain html, javascript just to prevent double-submissions\n- CSS/images/font are shared with the new employee form, at `/var/www/employee-forms/static/inc`\n  - Note that the woff files are an embedded font that load from the stylesheet (see the .css file); I used a public-domain font\n    - This bypasses the need of loading third party junk like Google fonts (aka Google tracking through website assets)\n\nServer details:\n- The Python server runs under the `YOUR_USER` user environment (customize to suit!)\n- This form was developed for and hosted on a restricted intranet IP only accessible to trusted users and is not accessible from the public web; so you should pentest before using this publicly!\n\nScript details:\n- The `new.py` script loads a third-party pip package, [paste](https://paste.readthedocs.io/en/latest/) which you can see from the .py script that it governs the server for the script to execute.  Updates are governed by pip and are done manually.\n- [bottle](https://bottlepy.org/docs/dev/) runs the templating, but comes from Debian's repos and is maintained by apt\n\n\n## Extending\nYou can have multiple servers/forms using the same assets and space.\n- Duplicate `new.py` and `views/ticket_form.tpl` (adjust ticket_form.tpl call in new.py copy, appropriately)\n- Modify newcopy.py and +1 the paste port\n- Create systemd services pointed at your new newcopy.py script\n- Create an nginx virtualhost for your new path\n\n### Known Bugs\nPre-assigning tickets to agents does not work.  There appears to be some joining of APIs that has to be done to pull the agent IDs successfully (so they're recognized by the right API), since it's more of an annoyance than a blockage, it's a low priority fix.\n\nAuto-adding of an agent to the ticket's CC is working.\n\n### Credits\n- Example company logo in the template from [DesignContest](https://iconarchive.com/show/ecommerce-business-icons-by-designcontest/company-building-icon.html)\n- Default motherboard background by [Athena](https://www.pexels.com/photo/black-and-gray-motherboard-2582937/)\n- Default font [Istok](https://www.fontsquirrel.com/fonts/istok) by Andrey V. Panov\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangela-d%2Fzendesk-multi-ticket","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fangela-d%2Fzendesk-multi-ticket","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangela-d%2Fzendesk-multi-ticket/lists"}