├── LICENSE ├── README.md ├── .gitignore ├── gsheet.py └── init.py /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, Hugonun(https://github.com/hugonun) 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # discord2sheet-bot 2 | 3 | This bot allows users to submit messages directly to your Google Sheet. 4 | 5 | Example: 6 | 7 | `!s Hello world, How are you today?` 8 | 9 | Output: 10 | 11 | Username - UserID - Date - Field 1 - Field 2 12 | 13 | ![Google Sheet](https://i.imgur.com/MFx25Ik.png) 14 | 15 | ## How to set it up 16 | 17 | **Step 1:** Enable the API and download credentials.json for desktop app (not web). This can be done here: https://developers.google.com/workspace/guides/create-credentials 18 | 19 | Make sure credentials.json is stored in the same directory as the bot. 20 | 21 | **Step 2:** Open init.py and change the following values(<>): 22 | 23 | SPREADSHEET_ID = <> - The ID of the spreashsheet to store the data. It can be found on the URL once opened. 24 | 25 | FIELDS = <> - Amount of fields/cells that get stored. They are on the user's message seperated by comma (!s field1, field2,field 3) 26 | 27 | client.run('<>') - The token of the Discord bot. 28 | 29 | **Step 3:** Install Python dependencies 30 | 31 | If you haven't installed Python yet, download it [here](https://www.python.org/). 32 | 33 | Install discordpy: `pip install discord.py` 34 | 35 | Run the pip command listed here: https://developers.google.com/sheets/api/quickstart/python#step_2_install_the_google_client_library 36 | 37 | **Step 4:** Run the bot 38 | 39 | `python init.py` 40 | 41 | ------ 42 | 43 | ## Additional configutations 44 | 45 | REQUIREDROLE = <> - If you want to restrict the command to a specific role, insert here the role id. If not, insert `None`. 46 | 47 | RANGE_NAME = <> - Where the data should go in the spreadsheet. Default value is `A1`. 48 | 49 | DATA = <> - What data goes to the rows, seperated by `[]`. Example: `DATA = [result[0]] + [''] + [result[1]]` 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /gsheet.py: -------------------------------------------------------------------------------- 1 | # BSD 3-Clause License 2 | # Copyright (c) 2019, Hugonun(https://github.com/hugonun) 3 | # All rights reserved. 4 | 5 | from __future__ import print_function 6 | import pickle 7 | import os.path 8 | from googleapiclient.discovery import build 9 | from google_auth_oauthlib.flow import InstalledAppFlow 10 | from google.auth.transport.requests import Request 11 | 12 | class gsheet(object): 13 | def __init__(self): 14 | SCOPES = ['https://www.googleapis.com/auth/spreadsheets'] 15 | self.creds = None 16 | # The file token.pickle stores the user's access and refresh tokens, and is 17 | # created automatically when the authorization flow completes for the first 18 | # time. 19 | if os.path.exists('token.pickle'): 20 | with open('token.pickle', 'rb') as token: 21 | self.creds = pickle.load(token) 22 | # If there are no (valid) credentials available, let the user log in. 23 | if not self.creds or not self.creds.valid: 24 | if self.creds and self.creds.expired and self.creds.refresh_token: 25 | self.creds.refresh(Request()) 26 | else: 27 | flow = InstalledAppFlow.from_client_secrets_file( 28 | 'credentials.json', SCOPES) 29 | self.creds = flow.run_local_server() 30 | # Save the credentials for the next run 31 | with open('token.pickle', 'wb') as token: 32 | pickle.dump(self.creds, token) 33 | 34 | self.service = build('sheets', 'v4', credentials=self.creds) 35 | def add(self,sheetid,sheetrange,ivalue): 36 | # Call the Sheets API 37 | sheet = self.service.spreadsheets() 38 | values = [] 39 | values.append(ivalue) 40 | body = { 41 | 'values': values 42 | } 43 | result = sheet.values().append( 44 | spreadsheetId=sheetid, range=sheetrange, 45 | valueInputOption='RAW', body=body).execute() 46 | 47 | -------------------------------------------------------------------------------- /init.py: -------------------------------------------------------------------------------- 1 | # BSD 3-Clause License 2 | # Copyright (c) 2019, Hugonun(https://github.com/hugonun) 3 | # All rights reserved. 4 | 5 | import discord 6 | 7 | from gsheet import * 8 | 9 | client = discord.Client() 10 | sheet = gsheet() 11 | 12 | @client.event 13 | async def on_ready(): 14 | print('We have logged in as {0.user}'.format(client)) 15 | 16 | @client.event 17 | async def on_message(message): 18 | if message.author == client.user: 19 | return 20 | 21 | # Command to insert data to excel 22 | if message.content.startswith('!s '): 23 | SPREADSHEET_ID = '2QkhiqSFomDLYYYQUt3LO_IuUu72qEtXsLDc4Blcf5dq' # Add ID here 24 | RANGE_NAME = 'A1' 25 | FIELDS = 2 # Amount of fields/cells 26 | 27 | # Restrict the command to a role 28 | # Change REQUIREDROLE to a role id or None 29 | REQUIREDROLE = None 30 | if REQUIREDROLE is not None and discord.utils.get(message.author.roles, id=int(REQUIREDROLE)) is None: 31 | await message.channel.send('You don\'t have the required role!') 32 | return 33 | 34 | # Code 35 | msg = message.content[3:] 36 | result = [x.strip() for x in msg.split(',')] 37 | if len(result) == FIELDS: 38 | # Add 39 | print(message.created_at) 40 | DATA = [message.author.name] + [str(message.author.id)] + [str(message.created_at)] + result 41 | sheet.add(SPREADSHEET_ID, RANGE_NAME, DATA) 42 | await message.channel.send('Your data has been successfully submitted!') 43 | else: 44 | # Needs more/less fields 45 | await message.channel.send('Error: You need to add {0} fields, meaning it can only have {1} comma.'.format(FIELDS,FIELDS-1)) 46 | 47 | # Whois 48 | # Please dont remove the copyright and github repo 49 | elif len(message.mentions) > 0: 50 | for muser in message.mentions: 51 | if muser.id == client.user.id: 52 | if any(word in message.content for word in ['whois','who is','Help','help','info']): 53 | await message.channel.send('This bot was made by hugonun(https://github.com/hugonun/).\nSource code: https://github.com/hugonun/discord2sheet-bot') 54 | 55 | 56 | client.run('') # Add bot token here 57 | --------------------------------------------------------------------------------