Files
Discord.Net/src/Discord.Net/Models/User.cs

271 lines
8.4 KiB
C#

using Discord.API;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Discord
{
public class User : CachedObject<long>
{
internal struct CompositeKey : IEquatable<CompositeKey>
{
public long ServerId, UserId;
public CompositeKey(long userId, long? serverId)
{
ServerId = serverId ?? 0;
UserId = userId;
}
public bool Equals(CompositeKey other)
=> UserId == other.UserId && ServerId == other.ServerId;
public override int GetHashCode()
=> unchecked(ServerId.GetHashCode() + UserId.GetHashCode() + 23);
}
/// <summary> Returns a unique identifier combining this user's id with its server's. </summary>
internal CompositeKey UniqueId => new CompositeKey(_server.Id ?? 0, Id);
/// <summary> Returns the name of this user on this server. </summary>
public string Name { get; private set; }
/// <summary> Returns a by-name unique identifier separating this user from others with the same name. </summary>
public short Discriminator { get; private set; }
/// <summary> Returns the unique identifier for this user's current avatar. </summary>
public string AvatarId { get; private set; }
/// <summary> Returns the URL to this user's current avatar. </summary>
public string AvatarUrl => AvatarId != null ? Endpoints.UserAvatar(Id, AvatarId) : null;
/// <summary> Returns the datetime that this user joined this server. </summary>
public DateTime JoinedAt { get; private set; }
public bool IsSelfMuted { get; private set; }
public bool IsSelfDeafened { get; private set; }
public bool IsServerMuted { get; private set; }
public bool IsServerDeafened { get; private set; }
public bool IsServerSuppressed { get; private set; }
public bool IsPrivate => _server.Id == null;
public string SessionId { get; private set; }
public string Token { get; private set; }
/// <summary> Returns the id for the game this user is currently playing. </summary>
public int? GameId { get; private set; }
/// <summary> Returns the current status for this user. </summary>
public UserStatus Status { get; private set; }
/// <summary> Returns the time this user last sent/edited a message, started typing or sent voice data in this server. </summary>
public DateTime? LastActivityAt { get; private set; }
/// <summary> Returns the time this user was last seen online in this server. </summary>
public DateTime? LastOnlineAt => Status != UserStatus.Offline ? DateTime.UtcNow : _lastOnline;
private DateTime? _lastOnline;
//References
[JsonIgnore]
public GlobalUser Global => _globalUser.Value;
private readonly Reference<GlobalUser> _globalUser;
[JsonIgnore]
public Server Server => _server.Value;
private readonly Reference<Server> _server;
[JsonProperty]
private long? ServerId { get { return _server.Id; } set { _server.Id = value; } }
[JsonIgnore]
public Channel VoiceChannel => _voiceChannel.Value;
private Reference<Channel> _voiceChannel;
[JsonProperty]
private long? VoiceChannelId { get { return _voiceChannel.Id; } set { _voiceChannel.Id = value; } }
//Collections
[JsonIgnore]
public IEnumerable<Role> Roles => _roles.Select(x => x.Value);
private Dictionary<long, Role> _roles;
[JsonProperty]
private IEnumerable<long> RoleIds => _roles.Select(x => x.Key);
/// <summary> Returns a collection of all messages this user has sent on this server that are still in cache. </summary>
[JsonIgnore]
public IEnumerable<Message> Messages
{
get
{
if (_server.Id != null)
return Server.Channels.SelectMany(x => x.Messages.Where(y => y.User.Id == Id));
else
return Global.PrivateChannel.Messages.Where(x => x.User.Id == Id);
}
}
/// <summary> Returns a collection of all channels this user has permissions to join on this server. </summary>
[JsonIgnore]
public IEnumerable<Channel> Channels
{
get
{
if (_server.Id != null)
{
return Server.Channels
.Where(x => (x.Type == ChannelType.Text && x.GetPermissions(this).ReadMessages) ||
(x.Type == ChannelType.Voice && x.GetPermissions(this).Connect));
}
else
{
var privateChannel = Global.PrivateChannel;
if (privateChannel != null)
return new Channel[] { privateChannel };
else
return new Channel[0];
}
}
}
/// <summary> Returns the string used to mention this user. </summary>
public string Mention => $"<@{Id}>";
internal User(DiscordClient client, long id, long? serverId)
: base(client, id)
{
_globalUser = new Reference<GlobalUser>(id,
x => _client.GlobalUsers.GetOrAdd(x),
x => x.AddUser(this),
x => x.RemoveUser(this));
_server = new Reference<Server>(serverId,
x => _client.Servers[x],
x =>
{
x.AddMember(this);
if (Id == _client.CurrentUser.Id)
x.CurrentUser = this;
},
x =>
{
x.RemoveMember(this);
if (Id == _client.CurrentUser.Id)
x.CurrentUser = null;
});
_voiceChannel = new Reference<Channel>(x => _client.Channels[x]);
_roles = new Dictionary<long, Role>();
Status = UserStatus.Offline;
if (serverId == null)
UpdateRoles(null);
}
internal override bool LoadReferences()
{
return _globalUser.Load() &&
(IsPrivate || _server.Load());
}
internal override void UnloadReferences()
{
_globalUser.Unload();
_server.Unload();
}
internal void Update(UserReference model)
{
if (model.Username != null)
Name = model.Username;
if (model.Discriminator != null)
Discriminator = model.Discriminator.Value;
if (model.Avatar != null)
AvatarId = model.Avatar;
}
internal void Update(MemberInfo model)
{
if (model.User != null)
Update(model.User);
if (model.JoinedAt.HasValue)
JoinedAt = model.JoinedAt.Value;
if (model.Roles != null)
UpdateRoles(model.Roles.Select(x => _client.Roles[x]));
}
internal void Update(ExtendedMemberInfo model)
{
Update(model as API.MemberInfo);
if (model.IsServerDeafened != null)
IsServerDeafened = model.IsServerDeafened.Value;
if (model.IsServerMuted != null)
IsServerMuted = model.IsServerMuted.Value;
}
internal void Update(PresenceInfo model)
{
if (model.User != null)
Update(model.User as UserReference);
if (model.Roles != null)
UpdateRoles(model.Roles.Select(x => _client.Roles[x]));
if (model.Status != null && Status != model.Status)
{
Status = UserStatus.FromString(model.Status);
if (Status == UserStatus.Offline)
_lastOnline = DateTime.UtcNow;
}
GameId = model.GameId; //Allows null
}
internal void Update(VoiceMemberInfo model)
{
if (model.IsServerDeafened != null)
IsServerDeafened = model.IsServerDeafened.Value;
if (model.IsServerMuted != null)
IsServerMuted = model.IsServerMuted.Value;
if (model.SessionId != null)
SessionId = model.SessionId;
if (model.Token != null)
Token = model.Token;
if (model.IsSelfDeafened != null)
IsSelfDeafened = model.IsSelfDeafened.Value;
if (model.IsSelfMuted != null)
IsSelfMuted = model.IsSelfMuted.Value;
if (model.IsServerSuppressed != null)
IsServerSuppressed = model.IsServerSuppressed.Value;
_voiceChannel.Id = model.ChannelId; //Allows null
}
private void UpdateRoles(IEnumerable<Role> roles)
{
Dictionary<long, Role> newRoles = new Dictionary<long, Role>();
if (roles != null)
{
foreach (var r in roles)
newRoles[r.Id] = r;
}
if (_server.Id != null)
{
var everyone = Server.EveryoneRole;
newRoles.Add(everyone.Id, everyone);
}
_roles = newRoles;
if (!IsPrivate)
Server.UpdatePermissions(this);
}
internal void UpdateActivity(DateTime? activity = null)
{
if (LastActivityAt == null || activity > LastActivityAt.Value)
LastActivityAt = activity ?? DateTime.UtcNow;
}
public ServerPermissions ServerPermissions => Server.GetPermissions(this);
public ChannelPermissions GetPermissions(Channel channel)
{
if (channel == null) throw new ArgumentNullException(nameof(channel));
return channel.GetPermissions(this);
}
public bool HasRole(Role role)
{
if (role == null) throw new ArgumentNullException(nameof(role));
return _roles.ContainsKey(role.Id);
}
public override bool Equals(object obj) => obj is User && (obj as User).Id == Id;
public override int GetHashCode() => unchecked(Id.GetHashCode() + 7230);
public override string ToString() => Name ?? IdConvert.ToString(Id);
}
}