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
85 changes: 75 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,79 @@
# Tarscord
# Tarscord 🤖

## Summary
Tarscord is a sarcastic discord bot that can help you manage your discord server. Some of the features that Tarscord supports are:
Named after TARS from Interstellar, Tarscord is a sarcastic Discord bot designed to help you manage your server with a touch of humor.

* Mute/Unmute members
* Add event and save them to a local database
* Generate random numbers
* Set reminders
* Others will be added soon...
✨ Features
• Moderation Tools: Mute and unmute members seamlessly.
• Event Management: Add events and save them to a local database for easy tracking.
• Random Number Generation: Generate random numbers for games or decision-making.
• Reminders: Set reminders to keep your community engaged and informed.
• More to Come: Continuous updates with new and exciting features.

📦 Installation

## Getting started
Create a new application inside the developer portal in Discord, then paste the Token Id inside the ```config.yml``` file and run the Tarscord.
1️⃣ Prerequisites
• .NET SDK: Ensure you have the latest version installed. You can download it from the .NET official website.

2️⃣ Clone the Repository

git clone https://github.com/armendu/Tarscord.git
cd Tarscord

3️⃣ Configure the Bot
1. Create a Discord Application:
• Navigate to the Discord Developer Portal.
• Click on “New Application” and provide a name.
• In the “Bot” section, add a new bot to your application.
• Copy the Token provided for the bot.
2. Set Up Configuration:
• In the src directory, locate the config.yml file.
• Replace the placeholder TokenId with the token you copied:

TokenId: "YOUR_DISCORD_BOT_TOKEN"



4️⃣ Build and Run

Navigate to the src directory and execute:

dotnet build
dotnet run

🔧 Configuration
• config.yml: Located in the src directory, this file contains essential configurations:
• TokenId: Your Discord bot token.
• Other settings can be adjusted as needed to customize Tarscord’s behavior.

💡 Usage

Once Tarscord is up and running:
1. Invite the Bot to Your Server:
• Generate an OAuth2 URL in the Discord Developer Portal with the necessary permissions.
• Use the URL to invite Tarscord to your server.
2. Interact with Tarscord:
• Use commands such as /mute, /unmute, /addevent, /random, and /remind to utilize its features.
• Tarscord responds with a unique, sarcastic flair to keep interactions entertaining.

🤝 Contributing

We welcome contributions! To get involved:
1. Fork the repository.
2. Create a new branch (feature/your-feature).
3. Commit your changes.
4. Push the branch and create a Pull Request.

Please ensure your code adheres to the project’s coding standards and includes appropriate tests.

📜 License

Tarscord is licensed under the MIT License. For more details, refer to the LICENSE file.

⭐ Support & Community

If you find Tarscord useful or entertaining:
• Star the Repository: Show your support by starring the project on GitHub!
• Report Issues: Encountered a bug or have a feature request? Open an issue.
• Stay Updated: Watch the repository for updates and new features.

Elevate your Discord server management with Tarscord’s unique blend of functionality and humor.
2 changes: 0 additions & 2 deletions src/Tarscord.Core/Extensions/UserExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using Discord;
using System.Collections.Generic;
using System.Linq;
using Tarscord.Core.Persistence.Entities;

namespace Tarscord.Core.Extensions;
Expand Down
36 changes: 14 additions & 22 deletions src/Tarscord.Core/Features/Loans/Create.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,27 @@ public class Command : IRequest<OneOf<LoanEnvelope, FailureResponse>>, IPerforme
public required string PerformedByUser { get; set; }
}

public class CreateLoanCommandValidator : AbstractValidator<Command>
public class CommandValidator : AbstractValidator<Command>
{
public CreateLoanCommandValidator()
public CommandValidator()
{
// TODO: Add proper validation
// RuleFor(x => x.Loan).NotNull();
RuleFor(x => x.Amount).GreaterThan(0);
}
}

public class CommandHandler : IRequestHandler<Command, OneOf<LoanEnvelope, FailureResponse>>
public class CommandHandler(
ILogger<CommandHandler> logger,
TarscordContext context,
TimeProvider timeProvider)
: IRequestHandler<Command, OneOf<LoanEnvelope, FailureResponse>>
{
private readonly ILogger<CommandHandler> _logger;
private readonly TarscordContext _context;
private readonly TimeProvider _timeProvider;

public CommandHandler(
ILogger<CommandHandler> logger,
TarscordContext context,
TimeProvider timeProvider)
{
_logger = logger;
_context = context;
_timeProvider = timeProvider;
}

public async Task<OneOf<LoanEnvelope, FailureResponse>> Handle(Command command,
CancellationToken cancellationToken)
{
var createdLoan = await _context.AddAsync(new Loan
logger.LogInformation("Command {Command} executed by {PerformedByUser}",
nameof(Command), command.PerformedByUser);

var createdLoan = await context.AddAsync(new Loan
{
LoanedFrom = command.LoanedFrom,
LoanedFromId = command.LoanedFromId,
Expand All @@ -61,10 +53,10 @@ public async Task<OneOf<LoanEnvelope, FailureResponse>> Handle(Command command,
AmountLoaned = command.Amount,
AmountPayed = 0,
Confirmed = false,
Created = _timeProvider.GetUtcNow().UtcDateTime
Created = timeProvider.GetUtcNow().UtcDateTime
}, cancellationToken);

await _context.SaveChangesAsync(cancellationToken);
await context.SaveChangesAsync(cancellationToken);

return LoanEnvelope.FromEntity(createdLoan.Entity);
}
Expand Down
4 changes: 3 additions & 1 deletion src/Tarscord.Core/Features/Loans/List.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ public async Task<ListResponse> Handle(Query request, CancellationToken cancella
logger.LogInformation("Query {Query} executed by {PerformedByUser}",
nameof(List), request.PerformedByUser);

var eventInfos = await context.Loans.ToListAsync(cancellationToken: cancellationToken);
var eventInfos = await context.Loans
.Where(x => x.LoanedFrom == request.PerformedByUser || x.LoanedTo == request.PerformedByUser)
.ToListAsync(cancellationToken: cancellationToken);

return new ListResponse(eventInfos.ConvertAll(LoanEnvelope.FromEntity));
}
Expand Down
5 changes: 4 additions & 1 deletion src/Tarscord.Core/Features/Loans/LoanEnvelope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public class LoanEnvelope
public required string LoanedTo { get; init; }
public string? Description { get; init; }

public decimal AmountPaid { get; init; }

public static LoanEnvelope FromEntity(Loan loan)
{
return new LoanEnvelope
Expand All @@ -22,7 +24,8 @@ public static LoanEnvelope FromEntity(Loan loan)
LoanedFromId = loan.LoanedFromId,
LoanedTo = loan.LoanedTo,
LoanedToId = loan.LoanedToId,
Description = loan.Description
Description = loan.Description,
AmountPaid = loan.AmountPayed
};
}

Expand Down
73 changes: 73 additions & 0 deletions src/Tarscord.Core/Features/Loans/Update.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using FluentValidation;
using MediatR;
using OneOf;
using Microsoft.Extensions.Logging;
using Microsoft.EntityFrameworkCore;
using Tarscord.Core.Features.Common;
using Tarscord.Core.Features.Events;
using Tarscord.Core.Persistence;

namespace Tarscord.Core.Features.Loans;

internal static class Update
{
public class Command : IRequest<OneOf<LoanEnvelope, FailureResponse>>, IPerformedByUser
{
public decimal Amount { get; set; }
public ulong LoanedFrom { get; set; }
public required string LoanedFromUsername { get; set; }
public ulong LoanedTo { get; set; }
public required string LoanedToUsername { get; set; }

public required string PerformedByUser { get; set; }
}

public class CommandValidator : AbstractValidator<Command>
{
public CommandValidator()
{
RuleFor(x => x.Amount).GreaterThan(0);
}
}

public class UpdateLoanCommandHandler(
ILogger<UpdateLoanCommandHandler> logger,
TarscordContext context)
: IRequestHandler<Command, OneOf<LoanEnvelope, FailureResponse>>
{
public async Task<OneOf<LoanEnvelope, FailureResponse>> Handle(Command request, CancellationToken cancellationToken)
{
logger.LogInformation("Command {Command} executed by {PerformedByUser}",
nameof(Command), request.PerformedByUser);

// Find the loan between the two users that isn't fully paid yet
var loan = await context.Loans
.LastOrDefaultAsync(x =>
x.LoanedFromId == request.LoanedTo &&
x.LoanedToId == request.LoanedFrom &&
x.AmountPayed < x.AmountLoaned,
cancellationToken);

if (loan is null)
{
return new FailureResponse("No active loan found between these users.");
}

// Calculate remaining balance before adding payment
var remainingBalance = loan.AmountLoaned - loan.AmountPayed;

// Ensure we don't overpay
if (request.Amount > remainingBalance)
{
return new FailureResponse($"Payment of {request.Amount:C} would exceed the remaining balance of {remainingBalance:C}");
}

// Add the payment amount to existing amount paid (supports partial payments)
loan.AmountPayed += request.Amount;

await context.SaveChangesAsync(cancellationToken);

return LoanEnvelope.FromEntity(loan);
}
}
}
60 changes: 0 additions & 60 deletions src/Tarscord.Core/Features/Loans/UpdateLoanCommand.cs

This file was deleted.

4 changes: 0 additions & 4 deletions src/Tarscord.Core/Features/Logging/ProcessLog.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Discord;
using MediatR;

Expand Down
Loading
Loading