Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[run]
omit = ./src/schedulebot.py, ./src/__init__.py.py,
16 changes: 16 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
language: python
python:
- "3.9"
# command to install dependencies
before_install:
- "pip install -U pip"
- "export PYTHONPATH=$PYTHONPATH:$(pwd)"
- "pip install coverage"
- "pip install coveralls"
install:
- pip install -r requirements.txt
# command to run tests
script:
- "coverage run --source 'src' -m pytest"
after_success:
coveralls
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

![Python v3.9](https://img.shields.io/badge/python-v3.9-blue)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![DOI](https://zenodo.org/badge/403393616.svg)](https://zenodo.org/badge/latestdoi/403393616)
![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/lyonva/ScheduleBot)
[![GitHub issues](https://img.shields.io/github/issues/lyonva/ScheduleBot)](https://github.com/lyonva/ScheduleBot/issues)
[![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/lyonva/ScheduleBot?include_prereleases)](https://github.com/lyonva/ScheduleBot/releases)
[![GitHub all releases](https://img.shields.io/github/downloads/lyonva/ScheduleBot/total)](https://github.com/lyonva/ScheduleBot/releases)
[![DOI](https://zenodo.org/badge/419116957.svg)](https://zenodo.org/badge/latestdoi/419116957)
[![Build Status](https://app.travis-ci.com/qchen59/ScheduleBot.svg?branch=main)](https://app.travis-ci.com/github/qchen59/ScheduleBot)
![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/qchen59/ScheduleBot)
[![GitHub issues](https://img.shields.io/github/issues/qchen59/ScheduleBot)](https://github.com/qchen59/ScheduleBot/issues)
[![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/qchen59/ScheduleBot?include_prereleases)](https://github.com/qchen59/ScheduleBot/releases)
[![GitHub all releases](https://img.shields.io/github/downloads/qchen59/ScheduleBot/total)](https://github.com/qchen59/ScheduleBot/releases)
[![Platform](https://img.shields.io/badge/platform-discord-blue)](https://discord.com/)
[![Test cases](https://github.com/lyonva/ScheduleBot/actions/workflows/python-app.yml/badge.svg)](https://github.com/lyonva/ScheduleBot/actions/workflows/python-app.yml)
[![Code coverage](https://raw.githubusercontent.com/lyonva/ScheduleBot/main/docs/img/coverage.svg)](https://github.com/lyonva/ScheduleBot/actions/workflows/python-app.yml)
[![Coverage Status](https://coveralls.io/repos/github/qchen59/ScheduleBot/badge.svg?branch=main)](https://coveralls.io/github/qchen59/ScheduleBot?branch=main)

# ScheduleBot

Expand Down Expand Up @@ -70,7 +70,8 @@ The bot will ask you for the name of the type and your preferred times.

## Releases

- [All releases](https://github.com/lyonva/ScheduleBot/releases)
- [All releases](https://github.com/
/ScheduleBot/releases)
- Latest: [v0](https://github.com/lyonva/ScheduleBot/releases/tag/v0)

## Documentation
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ coverage>=5.0.1
coverage-badge
lark
pdoc3
pandas
2 changes: 1 addition & 1 deletion src/functionality/create_event_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def check(m):
rows.append(line)
continue
else:
await channel.send("Inalid input, Time range is not changed.")
await channel.send("Invalid input, Time range is not changed.")
rows.append(line)
continue
else:
Expand Down
20 changes: 20 additions & 0 deletions src/functionality/export_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import os
import csv
import discord
from functionality.shared_functions import create_event_file


async def export_file(ctx):
channel = await ctx.author.create_dm()
print(ctx.author.id)

def check(m):
return m.content is not None and m.channel == channel and m.author == ctx.author

user_id = str(ctx.author.id)

# Checks if the calendar csv file exists, and creates it if it does not
if not os.path.exists(os.path.expanduser("~/Documents") + "/ScheduleBot/Event/" + user_id + ".csv"):
create_event_file(user_id)

await channel.send(file=discord.File(os.path.expanduser("~/Documents") + "/ScheduleBot/Event/" + user_id + ".csv"))
105 changes: 105 additions & 0 deletions src/functionality/import_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import os
import csv
import discord
import pandas as pd
import tempfile
from discord import Attachment
from functionality.shared_functions import create_event_tree, create_type_tree, add_event_to_file, turn_types_to_string
from Event import Event
from parse.match import parse_period

def verify_csv(data):
"""
Function:
verify_csv
Description:
Verifies that CSV data retrieved through pandas matches the expected format
Input:
data - A Pandas Dataframe of data pulled from a CSV
Output:
- True if the data matches the expectation, false otherwise
"""

if data.columns[0] != "ID":
return False
if data.columns[1] != "Name":
return False
if data.columns[2] != "Start Date":
return False
if data.columns[3] != "End Date":
return False
if data.columns[4] != "Type":
return False
if data.columns[5] != "Notes":
return False

return True

def convert_time(old_str):
"""
Function:
convert_time
Description:
Converts a time string from YYYY-MM-DD HH:MM:SS format to mm/dd/yy hh:mm am/pm format
Input:
old_str - The string to be converted
Output:
- the converted string
"""

new_str = old_str[5:7] + '/' + old_str[8:10] + '/' + old_str[2:4] + ' '

hour_int = int(old_str[11:13])
if (hour_int >= 12):
ap = "pm"
hour_int = hour_int - 12
else:
ap = "am"

hour = str(hour_int)
if len(hour) == 1:
hour = '0' + hour

new_str = new_str + hour + ':' + old_str[14:16] + ap

return new_str

async def import_file(ctx, client):
channel = await ctx.author.create_dm()

def check(m):
return m.content is not None and m.channel == channel and m.author == ctx.author

user_id = str(ctx.author.id)

# Checks if the calendar csv file exists, and creates it if it does not
await channel.send("Please upload your file below.")

# Loops until we receive a file.
while True:
event_msg = await client.wait_for("message", check=check)

if len(event_msg.attachments) != 1:
await channel.send("No file detected. Please upload your your file below.\nYou can do this by dropping "
"the file directly into Discord. Do not write out the file contents in the message.")
else:
break

temp_file = tempfile.TemporaryFile()
await event_msg.attachments[0].save(fp=temp_file.file, seek_begin=True, use_cached=False)
data = pd.read_csv(temp_file)

if not verify_csv(data):
await channel.send("Unexpected CSV Format. Import has failed.")
return

# creates an event tree if one doesn't exist yet.
create_event_tree(str(ctx.author.id))

for index, row in data.iterrows():
time_period = parse_period(convert_time(row['Start Date']) + ' ' + convert_time(row['End Date']))
current = Event(row['Name'], time_period[0], time_period[1], row['Type'], row['Notes'])
add_event_to_file(str(ctx.author.id), current)

await channel.send("Your events were successfully added!")

36 changes: 13 additions & 23 deletions src/functionality/shared_functions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import os
import csv
from pathlib import Path
from Event import Event
from src.Event import Event
from datetime import datetime


Expand Down Expand Up @@ -147,7 +147,6 @@ def read_event_file(user_id):
with open(os.path.expanduser("~/Documents") + "/ScheduleBot/Event/" + user_id + ".csv", "r") as calendar_lines:
calendar_lines = csv.reader(calendar_lines, delimiter=",")
rows = []

# Stores the current row in an array of rows if the row is not a new-line character
# This check prevents an accidental empty lines from being kept in the updated file
for row in calendar_lines:
Expand All @@ -168,9 +167,8 @@ def add_event_to_file(user_id, current):
line_number = 0
rows = read_event_file(user_id)
# If the file already has events
if len(rows) > 0:
if len(rows) > 1:
for i in rows:

# Skips check with empty lines
if len(i) > 0 and line_number != 0:

Expand All @@ -182,7 +180,6 @@ def add_event_to_file(user_id, current):
"",
"",
)

# If the current Event occurs before the temp Event, insert the current at that position
if current < temp_event:
rows.insert(line_number, [""] + current.to_list())
Expand All @@ -193,22 +190,15 @@ def add_event_to_file(user_id, current):
rows.insert(len(rows), [""] + current.to_list())
break
line_number += 1

# Open current user's calendar file for writing
with open(
os.path.expanduser("~/Documents") + "/ScheduleBot/Event/" + user_id + ".csv",
"w",
newline="",
) as calendar_file:
# Write to column headers and array of rows back to the calendar file
csvwriter = csv.writer(calendar_file)
csvwriter.writerows(rows)
# If the file has no events, add the current Event to the file
else:
with open(
os.path.expanduser("~/Documents") + "/ScheduleBot/Event/" + user_id + ".csv",
"w",
newline="",
) as calendar_file:
csvwriter = csv.writer(calendar_file)
csvwriter.writerow([""] + current.to_list())
rows.insert(len(rows), [""] + current.to_list())
# Open current user's calendar file for writing
with open(
os.path.expanduser("~/Documents") + "/ScheduleBot/Event/" + user_id + ".csv",
"w",
newline="",
) as calendar_file:
# Write to column headers and array of rows back to the calendar file
csvwriter = csv.writer(calendar_file)
csvwriter.writerows(rows)

33 changes: 33 additions & 0 deletions src/schedulebot.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from functionality.FindAvailableTime import find_avaialbleTime
from functionality.delete_event_type import delete_event_type
from functionality.DisplayFreeTime import get_free_time
from functionality.export_file import export_file
from functionality.import_file import import_file

bot = commands.Bot(command_prefix="!") # Creates the bot with a command prefix of '!'
bot.remove_command("help") # Removes the help command, so it can be created using Discord embed pages later
Expand Down Expand Up @@ -38,6 +40,8 @@ async def help(ctx):
em.add_field(name="day", value="Shows everything on your schedule for today", inline=False)
em.add_field(name="typecreate", value="Creates a new event type", inline=True)
em.add_field(name="typedelete", value="Deletes an event type", inline=True)
em.add_field(name="exportfile", value="Exports a CSV file of your events", inline=False)
em.add_field(name="importfile", value="Import events from a CSV file", inline=False)
await ctx.send(embed=em)


Expand Down Expand Up @@ -138,6 +142,35 @@ async def day(ctx):
"""
await get_highlight(ctx)

@bot.command()
async def exportfile(ctx):
"""
Function:
exportfile
Description:
Sends the user a CSV file containing their scheduled events.
Input:
ctx - Discord context window
Output:
- A CSV file sent to the context that contains a user's scheduled events.
"""

await export_file(ctx)

@bot.command()
async def importfile(ctx):
"""
Function:
importfile
Description:
Reads a CSV file containing events submitted by the user, and adds those events
Input:
ctx - Discord context window
Output:
- Events are added to a users profile.
"""

await import_file(ctx, bot)

# creating new event type
@bot.command()
Expand Down