Skip to content

Commit

Permalink
Added user profiles
Browse files Browse the repository at this point in the history
  • Loading branch information
byBlurr committed Jan 19, 2021
1 parent 526cf89 commit 940dac1
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 7 deletions.
273 changes: 273 additions & 0 deletions LorisAngel/Database/ProfileDatabase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
using Discord;
using Discord.Net.Bot;
using Discord.Net.Bot.Database.Sql;
using MySql.Data.MySqlClient;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace LorisAngel.Database
{
public class ProfileDatabase
{
private static List<LoriUser> Users;
private static bool ReadyToUpdate = false;

// Loop through all users
public static async Task ProcessUsers()
{
var SaveUsers = Task.Run(async () =>
{
await Util.Logger(new LogMessage(LogSeverity.Info, "Profiles", "Start of SaveUsers thread."));
await Task.Delay(5000);

int newUsers = 0;
foreach (var g in CommandHandler.GetBot().Guilds)
{
foreach (var u in CommandHandler.GetBot().GetGuild(g.Id).Users)
{
if(!DoesUserExist(u.Id))
{
LoriUser newUser = new LoriUser(u.Id, u.Username, u.CreatedAt.DateTime, DateTime.Now, new DateTime(), u.Status.ToString(), "");
await AddUserToDatabaseAsync(newUser);
newUsers++;
}
}
}

if (newUsers > 0) await Util.Logger(new LogMessage(LogSeverity.Info, "Profiles", $"Added {newUsers} new users."));
Users = await GetAllUsersAsync();
ReadyToUpdate = true;

await Task.Delay(5000);
while (true)
{
DateTime startTime = DateTime.Now;
await SaveAllUsersAsync(Users);
int timetosave = (int)((DateTime.Now - startTime).TotalSeconds);
if (timetosave > 5) await Util.Logger(new LogMessage(LogSeverity.Warning, "Profiles", $"Saving users took {timetosave} seconds"));
await Task.Delay(60000); // Save users once a minute
}
});

var UpdateUsers = Task.Run(async () =>
{
await Util.Logger(new LogMessage(LogSeverity.Info, "Profiles", "Start of UpdateUsers thread."));
var bot = CommandHandler.GetBot();
while (!ReadyToUpdate) await Task.Delay(500);
while (true)
{
if (Users.Count != 0)
{
DateTime startTime = DateTime.Now;

foreach (LoriUser usr in Users)
{
var discUsr = bot.GetUser(usr.Id);
if (discUsr != null)
{
usr.UpdateStatus(discUsr.Status);
usr.UpdateName(discUsr.Username);
}
}

int timetoupdate = (int)((DateTime.Now - startTime).TotalSeconds);
if (timetoupdate > 5) await Util.Logger(new LogMessage(LogSeverity.Warning, "Profiles", $"Updating users took {timetoupdate} seconds"));
}
await Task.Delay(500);
}
});
}

// Get all users
private static async Task<List<LoriUser>> GetAllUsersAsync()
{
List<LoriUser> users = new List<LoriUser>();

var dbCon = DBConnection.Instance();
dbCon.DatabaseName = LCommandHandler.DATABASE_NAME;

if (dbCon.IsConnect())
{
var cmd = new MySqlCommand($"SELECT * FROM users", dbCon.Connection);
var reader = cmd.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
ulong id = reader.GetUInt64(0);
string name = reader.GetString(1);
DateTime createdOn = reader.GetDateTime(2);
DateTime joinedOn = reader.GetDateTime(3);
DateTime lastSeen = reader.GetDateTime(4);
string status = reader.GetString(5);

LoriUser newUser = new LoriUser(id, name, createdOn, joinedOn, lastSeen, status, "");
users.Add(newUser);
}
}

reader.Close();
cmd.Dispose();
dbCon.Close();
}

return users;
}

// Save all users
private static async Task SaveAllUsersAsync(List<LoriUser> users)
{
var dbCon = DBConnection.Instance();
dbCon.DatabaseName = LCommandHandler.DATABASE_NAME;
if (dbCon.IsConnect())
{
foreach (LoriUser user in users)
{
if (user.HasChanged)
{
var cmd = new MySqlCommand($"UPDATE users SET name = @name, lastseen = @lastseen, status = @status WHERE id = @id", dbCon.Connection);
cmd.Parameters.Add("@id", MySqlDbType.UInt64).Value = user.Id;
cmd.Parameters.Add("@name", MySqlDbType.String).Value = "";
cmd.Parameters.Add("@lastseen", MySqlDbType.DateTime).Value = user.LastSeen;
cmd.Parameters.Add("@status", MySqlDbType.String).Value = user.Status;

try
{
await cmd.ExecuteNonQueryAsync();
user.HasChanged = false;
cmd.Dispose();
}
catch (Exception e)
{
Console.WriteLine($"Failed to save user: {e.Message}");
cmd.Dispose();
}
}
}

dbCon.Close();
}
}


// Check if user exists in database
private static bool DoesUserExist(ulong id)
{
var dbCon = DBConnection.Instance();
dbCon.DatabaseName = LCommandHandler.DATABASE_NAME;

if (dbCon.IsConnect())
{
var cmd = new MySqlCommand($"SELECT * FROM users WHERE id = '{id}'", dbCon.Connection);
var reader = cmd.ExecuteReader();
if (reader.HasRows)
{
reader.Close();
cmd.Dispose();
dbCon.Close();
return true;
}
else
{
reader.Close();
cmd.Dispose();
dbCon.Close();
return false;
}
}

return false;
}


// Add user to database
private static async Task AddUserToDatabaseAsync(LoriUser user)
{
var dbCon = DBConnection.Instance();
dbCon.DatabaseName = LCommandHandler.DATABASE_NAME;
if (dbCon.IsConnect())
{
var cmd = new MySqlCommand($"INSERT INTO users (id, name, createdon, joinedon, lastseen, status, badges) VALUES (@id, @name, @createdon, @joinedon, @lastseen, @status, @badges)", dbCon.Connection);
cmd.Parameters.Add("@id", MySqlDbType.UInt64).Value = user.Id;
cmd.Parameters.Add("@name", MySqlDbType.String).Value = "";
cmd.Parameters.Add("@createdon", MySqlDbType.DateTime).Value = user.CreatedOn;
cmd.Parameters.Add("@joinedon", MySqlDbType.DateTime).Value = user.JoinedOn;
cmd.Parameters.Add("@lastseen", MySqlDbType.DateTime).Value = user.LastSeen;
cmd.Parameters.Add("@status", MySqlDbType.String).Value = user.Status;
cmd.Parameters.Add("@badges", MySqlDbType.String).Value = "";

try
{
await cmd.ExecuteNonQueryAsync();
cmd.Dispose();
}
catch (Exception e)
{
Console.WriteLine($"Failed to save user: {e.Message}");
cmd.Dispose();
}

dbCon.Close();
}
}

// Remove user from database
private static async Task RemoveUserAsync(ulong id)
{

}
}

public class LoriUser
{
public ulong Id { get; private set; }
public string Name { get; private set; }
public DateTime CreatedOn { get; private set; }
public DateTime JoinedOn { get; private set; }
public DateTime LastSeen { get; private set; }
public string Status { get; private set; }
public string Badges { get; private set; } // WILL BE A LIST OF BADGES ONCE BADGES ADDED
public bool HasChanged { get; set; }

public LoriUser(ulong id, string name, DateTime createdOn, DateTime joinedOn, DateTime lastSeen, string status, string badges = "")
{
Id = id;
Name = name.Normalize() ?? throw new ArgumentNullException(nameof(name));
CreatedOn = createdOn;
JoinedOn = joinedOn;
LastSeen = lastSeen;
Status = status ?? throw new ArgumentNullException(nameof(status));
Badges = badges;
HasChanged = false;
}

public void UpdateStatus(UserStatus newStatus)
{
if (!newStatus.ToString().Equals(Status))
{
Status = newStatus.ToString();
HasChanged = true;
}
if (!(newStatus == UserStatus.Offline || newStatus == UserStatus.Invisible))
{
LastSeen = DateTime.Now;
HasChanged = true;
}
}

public void UpdateName(string newName)
{
if (newName.Normalize() == Name) return;
Name = newName.Normalize();
HasChanged = true;
}

public override bool Equals(object obj)
{
return obj is LoriUser user &&
Id == user.Id;
}
}
}
7 changes: 1 addition & 6 deletions LorisAngel/Files/SQLPlan.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
UserProfile
ulong id
string profile


On start up, load the users from database
On start up, load the users from database
Loop every user of every guild every 5 seconds
Add any missing user to the stored list of users
Check status of any user, if changed store last seen as current time and update status
Expand Down
5 changes: 4 additions & 1 deletion LorisAngel/Files/changelog.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Version 2.0.2
# Version 2.0.3
-

# Version 2.0.2
- Added better command error feedback
- Added command to add censored words (-settings addcensor <word>)
- Fixed SQL error on relationship command
Expand Down
2 changes: 2 additions & 0 deletions LorisAngel/LCommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ private async Task ReadyAsync()
await Task.Delay(15000);
}
});

await ProfileDatabase.ProcessUsers();
}

private async Task JoinedGuildAsync(SocketGuild guild)
Expand Down
34 changes: 34 additions & 0 deletions users.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
-- --------------------------------------------------------
-- Host: 127.0.0.1
-- Server version: 10.4.14-MariaDB - mariadb.org binary distribution
-- Server OS: Win64
-- HeidiSQL Version: 10.1.0.5464
-- --------------------------------------------------------

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET NAMES utf8 */;
/*!50503 SET NAMES utf8mb4 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;


-- Dumping database structure for lorisangel
CREATE DATABASE IF NOT EXISTS `lorisangel` /*!40100 DEFAULT CHARACTER SET latin1 */;
USE `lorisangel`;

-- Dumping structure for table lorisangel.users
CREATE TABLE IF NOT EXISTS `users` (
`id` bigint(20) NOT NULL COMMENT 'Discord ID',
`name` varchar(50) DEFAULT NULL COMMENT 'Discord username',
`createdon` datetime DEFAULT NULL COMMENT 'Discord Account Creation Time',
`joinedon` datetime DEFAULT NULL COMMENT 'Lori''s Angel Profile Creating Time',
`lastseen` datetime DEFAULT NULL COMMENT 'Last Seen Active Time',
`status` varchar(50) DEFAULT NULL COMMENT 'Discord Status',
`badges` longtext DEFAULT NULL COMMENT 'List of all Lori''s Angel badges',
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT='A table of all the Lori''s Angels users';

-- Data exporting was unselected.
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

0 comments on commit 940dac1

Please sign in to comment.