Added game last played, and total play time stats
* Added game last played, and total play time stats
This commit is contained in:
BIN
gaseous-server/.DS_Store
vendored
BIN
gaseous-server/.DS_Store
vendored
Binary file not shown.
99
gaseous-server/Classes/Statistics.cs
Normal file
99
gaseous-server/Classes/Statistics.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
using System.Data;
|
||||
using gaseous_server.Models;
|
||||
|
||||
namespace gaseous_server.Classes
|
||||
{
|
||||
public class Statistics
|
||||
{
|
||||
public StatisticsModel RecordSession(Guid SessionId, long GameId, string UserId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql;
|
||||
Dictionary<string, object> dbDict;
|
||||
|
||||
if (SessionId == Guid.Empty)
|
||||
{
|
||||
// new session required
|
||||
SessionId = Guid.NewGuid();
|
||||
|
||||
sql = "INSERT INTO UserTimeTracking (GameId, UserId, SessionId, SessionTime, SessionLength) VALUES (@gameid, @userid, @sessionid, @sessiontime, @sessionlength);";
|
||||
dbDict = new Dictionary<string, object>{
|
||||
{ "gameid", GameId },
|
||||
{ "userid", UserId },
|
||||
{ "sessionid", SessionId },
|
||||
{ "sessiontime", DateTime.UtcNow },
|
||||
{ "sessionlength", 1 }
|
||||
};
|
||||
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
|
||||
return new StatisticsModel{
|
||||
GameId = GameId,
|
||||
SessionId = SessionId,
|
||||
SessionStart = (DateTime)dbDict["sessiontime"],
|
||||
SessionLength = (int)dbDict["sessionlength"]
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// update existing session
|
||||
sql = "UPDATE UserTimeTracking SET SessionLength = SessionLength + @sessionlength WHERE GameId = @gameid AND UserId = @userid AND SessionId = @sessionid;";
|
||||
dbDict = new Dictionary<string, object>{
|
||||
{ "gameid", GameId },
|
||||
{ "userid", UserId },
|
||||
{ "sessionid", SessionId },
|
||||
{ "sessionlength", 1 }
|
||||
};
|
||||
|
||||
db.ExecuteNonQuery(sql, dbDict);
|
||||
|
||||
sql = "SELECT * FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid AND SessionId = @sessionid;";
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
return new StatisticsModel{
|
||||
GameId = (long)data.Rows[0]["GameId"],
|
||||
SessionId = Guid.Parse(data.Rows[0]["SessionId"].ToString()),
|
||||
SessionStart = (DateTime)data.Rows[0]["SessionTime"],
|
||||
SessionLength = (int)data.Rows[0]["SessionLength"]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public StatisticsModel? GetSession(long GameId, string UserId)
|
||||
{
|
||||
Database db = new Database(Database.databaseType.MySql, Config.DatabaseConfiguration.ConnectionString);
|
||||
string sql = "SELECT SUM(SessionLength) AS TotalLength FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid;";
|
||||
Dictionary<string, object> dbDict = new Dictionary<string, object>{
|
||||
{ "gameid", GameId },
|
||||
{ "userid", UserId }
|
||||
};
|
||||
|
||||
DataTable data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
if (data.Rows.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data.Rows[0]["TotalLength"] == DBNull.Value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
int TotalTime = int.Parse(data.Rows[0]["TotalLength"].ToString());
|
||||
|
||||
sql = "SELECT * FROM UserTimeTracking WHERE GameId = @gameid AND UserId = @userid ORDER BY SessionTime DESC LIMIT 1;";
|
||||
data = db.ExecuteCMD(sql, dbDict);
|
||||
|
||||
return new StatisticsModel{
|
||||
GameId = GameId,
|
||||
SessionLength = TotalTime,
|
||||
SessionStart = (DateTime)data.Rows[0]["SessionTime"]
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
104
gaseous-server/Controllers/V1.1/StatisticsController.cs
Normal file
104
gaseous-server/Controllers/V1.1/StatisticsController.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using gaseous_server.Models;
|
||||
using gaseous_server.Classes;
|
||||
using Authentication;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Asp.Versioning;
|
||||
|
||||
namespace gaseous_server.Controllers.v1_1
|
||||
{
|
||||
[Route("api/v{version:apiVersion}/[controller]")]
|
||||
[ApiVersion("1.0")]
|
||||
[ApiVersion("1.1")]
|
||||
[ApiController]
|
||||
public class StatisticsController: ControllerBase
|
||||
{
|
||||
private readonly UserManager<ApplicationUser> _userManager;
|
||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||
|
||||
public StatisticsController(
|
||||
UserManager<ApplicationUser> userManager,
|
||||
SignInManager<ApplicationUser> signInManager
|
||||
)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_signInManager = signInManager;
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPost]
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("Games/{GameId}/")]
|
||||
public async Task<ActionResult> NewRecordStatistics(long GameId)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
Statistics statistics = new Statistics();
|
||||
return Ok(statistics.RecordSession(Guid.Empty, GameId, user.Id));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpPut]
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("Games/{GameId}/{SessionId}")]
|
||||
public async Task<ActionResult> SubsequentRecordStatistics(long GameId, Guid SessionId)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
Statistics statistics = new Statistics();
|
||||
return Ok(statistics.RecordSession(SessionId, GameId, user.Id));
|
||||
}
|
||||
else
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
|
||||
[MapToApiVersion("1.0")]
|
||||
[MapToApiVersion("1.1")]
|
||||
[HttpGet]
|
||||
[Authorize]
|
||||
[ProducesResponseType(typeof(Models.StatisticsModel), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
[Route("Games/{GameId}")]
|
||||
public async Task<ActionResult> GetStatistics(long GameId)
|
||||
{
|
||||
var user = await _userManager.GetUserAsync(User);
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
Statistics statistics = new Statistics();
|
||||
StatisticsModel? model = statistics.GetSession(GameId, user.Id);
|
||||
if (model == null)
|
||||
{
|
||||
return NoContent();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Ok(model);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
gaseous-server/Models/StatisticsModel.cs
Normal file
17
gaseous-server/Models/StatisticsModel.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace gaseous_server.Models
|
||||
{
|
||||
public class StatisticsModel
|
||||
{
|
||||
public Guid SessionId { get; set; } = Guid.Empty;
|
||||
public long GameId { get; set; }
|
||||
public DateTime SessionStart { get; set; }
|
||||
public int SessionLength { get; set; }
|
||||
public DateTime SessionEnd
|
||||
{
|
||||
get
|
||||
{
|
||||
return SessionStart.AddMinutes(SessionLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
13
gaseous-server/Support/Database/MySQL/gaseous-1020.sql
Normal file
13
gaseous-server/Support/Database/MySQL/gaseous-1020.sql
Normal file
@@ -0,0 +1,13 @@
|
||||
CREATE TABLE `UserTimeTracking` (
|
||||
`GameId` BIGINT NULL,
|
||||
`UserId` VARCHAR(45) NULL,
|
||||
`SessionId` VARCHAR(45) NULL,
|
||||
`SessionTime` DATETIME NULL,
|
||||
`SessionLength` INT NULL,
|
||||
INDEX `UserId_idx` (`UserId` ASC) VISIBLE,
|
||||
INDEX `SessionId_idx` (`SessionId` ASC) VISIBLE,
|
||||
CONSTRAINT `UserId`
|
||||
FOREIGN KEY (`UserId`)
|
||||
REFERENCES `Users` (`Id`)
|
||||
ON DELETE CASCADE
|
||||
ON UPDATE NO ACTION);
|
@@ -61,6 +61,8 @@
|
||||
<None Remove="Support\Database\MySQL\gaseous-1016.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1017.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1018.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1019.sql" />
|
||||
<None Remove="Support\Database\MySQL\gaseous-1020.sql" />
|
||||
<None Remove="Classes\Metadata\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -102,5 +104,7 @@
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1016.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1017.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1018.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1019.sql" />
|
||||
<EmbeddedResource Include="Support\Database\MySQL\gaseous-1020.sql" />
|
||||
</ItemGroup>
|
||||
</Project>
|
BIN
gaseous-server/wwwroot/.DS_Store
vendored
BIN
gaseous-server/wwwroot/.DS_Store
vendored
Binary file not shown.
@@ -70,4 +70,30 @@
|
||||
bg.setAttribute('style', 'background-image: url("/api/v1.1/Games/' + gameId + '/artwork/' + artworks[artworksPosition] + '/image/original/' + artworks[artworksPosition] + '.jpg"); background-position: center; background-repeat: no-repeat; background-size: cover; filter: blur(10px); -webkit-filter: blur(10px);');
|
||||
}
|
||||
}
|
||||
|
||||
// statistics
|
||||
var SessionId = undefined;
|
||||
|
||||
function SaveStatistics() {
|
||||
var model;
|
||||
if (SessionId == undefined) {
|
||||
ajaxCall(
|
||||
'/api/v1.1/Statistics/Games/' + gameId,
|
||||
'POST',
|
||||
function (success) {
|
||||
SessionId = success.sessionId;
|
||||
}
|
||||
);
|
||||
} else {
|
||||
ajaxCall(
|
||||
'/api/v1.1/Statistics/Games/' + gameId + '/' + SessionId,
|
||||
'PUT',
|
||||
function (success) {
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(SaveStatistics, 60000);
|
||||
</script>
|
||||
|
@@ -63,6 +63,16 @@
|
||||
<div id="gamescreenshots_gallery_panel"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="gamestatistics">
|
||||
<div id="gamestatistics_lastplayed" class="gamestatistics_box">
|
||||
<span class="gamestatistics_label">Last Played</span>
|
||||
<span id="gamestatistics_lastplayed_value" class="gamestatistics_value">-</span>
|
||||
</div>
|
||||
<div id="gamestatistics_timeplayed" class="gamestatistics_box">
|
||||
<span class="gamestatistics_label">Total Play Time</span>
|
||||
<span id="gamestatistics_timeplayed_value" class="gamestatistics_value">-</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="gamesummarytext">
|
||||
<span id="gamesummarytext_label" class="line-clamp-4"></span>
|
||||
<p id="gamesummarytext_label_button_expand" class="text_link" style="display: none;" onclick="document.querySelector('#gamesummarytext_label').classList.remove('line-clamp-4'); document.querySelector('#gamesummarytext_label_button_expand').setAttribute('style', 'display: none;'); document.querySelector('#gamesummarytext_label_button_contract').setAttribute('style', '');">Read more...</p>
|
||||
@@ -256,6 +266,30 @@
|
||||
gamePublisherLabel.setAttribute('style', 'display: none;');
|
||||
}
|
||||
|
||||
// load statistics
|
||||
ajaxCall('/api/v1.1/Statistics/Games/' + gameId, 'GET', function (result) {
|
||||
var gameStat_lastPlayed = document.getElementById('gamestatistics_lastplayed_value');
|
||||
var gameStat_timePlayed = document.getElementById('gamestatistics_timeplayed_value');
|
||||
if (result) {
|
||||
// gameStat_lastPlayed.innerHTML = moment(result.sessionEnd).format("YYYY-MM-DD h:mm:ss a");
|
||||
const dateOptions = {
|
||||
//weekday: 'long',
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
};
|
||||
gameStat_lastPlayed.innerHTML = new Date(result.sessionEnd).toLocaleDateString(undefined, dateOptions);
|
||||
if (result.sessionLength >= 60) {
|
||||
gameStat_timePlayed.innerHTML = Number(result.sessionLength / 60) + " hours";
|
||||
} else {
|
||||
gameStat_timePlayed.innerHTML = Number(result.sessionLength) + " minutes";
|
||||
}
|
||||
} else {
|
||||
gameStat_lastPlayed.innerHTML = '-';
|
||||
gameStat_timePlayed.innerHTML = '-';
|
||||
}
|
||||
});
|
||||
|
||||
// load release date
|
||||
var gameSummaryRelease = document.getElementById('gamesummary_firstrelease');
|
||||
if (result.firstReleaseDate) {
|
||||
|
@@ -905,6 +905,31 @@ iframe {
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
#gamestatistics {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
background-color: rgba(56, 56, 56, 0.3);
|
||||
}
|
||||
|
||||
.gamestatistics_box {
|
||||
display: inline-block;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.gamestatistics_label {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.gamestatistics_value {
|
||||
display: block;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
#gamesummarytext_label {
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user