Skip to content

Commit

Permalink
Extracting usage info
Browse files Browse the repository at this point in the history
  • Loading branch information
allomanta committed Mar 26, 2024
1 parent bbf315a commit 2421cd8
Show file tree
Hide file tree
Showing 6 changed files with 361 additions and 286 deletions.
330 changes: 179 additions & 151 deletions IguideME.Web/Services/CanvasSyncService.cs
Original file line number Diff line number Diff line change
@@ -1,151 +1,179 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using IguideME.Web.Models.Service;
using IguideME.Web.Services.LMSHandlers;
using IguideME.Web.Services.Workers;
using Microsoft.Extensions.Logging;

namespace IguideME.Web.Services
{
// Not strictly necessary since we only have 1 class but apparently good practice for DI and testing.
public interface ICanvasSyncService
{
Task<JobResultModel> DoWorkAsync(string jobId, JobParametersModel work,
CancellationToken cancellationToken);
}

/// <summary>
/// Class <a>CanvasSyncService</a> implements ICanvasSyncService and is a service that manages syncs. .
/// </summary>
public sealed class CanvasSyncService : ICanvasSyncService
{
private readonly ILogger<SyncManager> _logger;
private readonly IComputationJobStatusService _computationJobStatus;
private readonly ILMSHandler _lmsHandler;

/// <summary>
/// This constructor initializes the new CanvasSyncService to
/// (<paramref name="computationJobStatus"/>, <paramref name="lmsHandler"/>, <paramref name="logger"/>).
/// </summary>
/// <param name="computationJobStatus"></param>
/// <param name="lmsHandler"></param>
/// <param name="logger"></param>
public CanvasSyncService(
IComputationJobStatusService computationJobStatus,
ILMSHandler lmsHandler,
ILogger<SyncManager> logger)
{
_logger = logger;
_computationJobStatus = computationJobStatus;
_lmsHandler = lmsHandler;
}

/// <summary>
/// Performs the sync with camvas.
/// </summary>
/// <param name="jobId">The id of the job in storage.</param>
/// <param name="work">Data for the service.</param>
/// <param name="cancellationToken">Token used to cancel the sync.</param>
/// <returns>A task containging the result of the sync</returns>
public async Task<JobResultModel> DoWorkAsync(string jobId, JobParametersModel work,
CancellationToken cancellationToken)
{
JobResultModel result = new();
int courseID = work.CourseID;
bool notifications_bool = false;

static bool isBetweenDates(DateTime input, DateTime startDate, DateTime endDate)
{
return (input >= startDate && input <= endDate);
}

List<string> notificationDates = DatabaseManager.Instance.GetNotificationDates(courseID);
if (notificationDates[0].Contains("-"))
{
// We are looking in a range of dates
foreach (string datepair in notificationDates)
{
string[] splittedDates = datepair.Split("-");
if (isBetweenDates(DateTime.Parse(String.Format("{0:yyyy/MM/dd}", DateTime.Now)), DateTime.Parse(splittedDates[0]), DateTime.Parse(splittedDates[1])))
{
notifications_bool = work.Notifications_bool; // What is this bool??
break;
}
}
}
else
notifications_bool = work.Notifications_bool && notificationDates.Contains(String.Format("{0:yyyy/MM/dd}", DateTime.Now));

_logger.LogInformation("{Time}: Starting sync for course {CourseID}", DateTime.Now, courseID);

string timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();

// Renew the connection with canvas.
_lmsHandler.SyncInit();

// Don't keep ancient syncs in the database.
DatabaseManager.Instance.CleanupSync(courseID);

// Register the new sync in the database.
DatabaseManager.Instance.RegisterSync(courseID, timestamp);
_logger.LogInformation("Sync hash: {Hash}", timestamp);
_logger.LogInformation("Course: {Course}", work.CourseID);

// Time how long the sync takes.
Stopwatch sw = new();
sw.Start();

new UserWorker(courseID, timestamp, _lmsHandler, _logger).Start();
await _computationJobStatus.UpdateJobProgressInformationAsync(
jobId, $"tasks.students", 0
).ConfigureAwait(false);

new QuizWorker(courseID, timestamp, _lmsHandler, _logger).Start();
await _computationJobStatus.UpdateJobProgressInformationAsync(
jobId, $"tasks.quizzes", 0
).ConfigureAwait(false);

new DiscussionWorker(courseID, timestamp, _lmsHandler, _logger).Start();
await _computationJobStatus.UpdateJobProgressInformationAsync(
jobId, $"tasks.discussions", 0
).ConfigureAwait(false);

new AssignmentWorker(courseID, timestamp, _lmsHandler, _logger).Start();
await _computationJobStatus.UpdateJobProgressInformationAsync(
jobId, $"tasks.assignments", 0
).ConfigureAwait(false);

_logger.LogInformation("Starting recycleexternaldata");
DatabaseManager.Instance.RecycleExternalData(courseID, timestamp);

new GradePredictorWorker(courseID, timestamp, _logger).Start();
await _computationJobStatus.UpdateJobProgressInformationAsync(
jobId, $"tasks.grade-predictor", 0
).ConfigureAwait(false);

new PeerGroupWorker(courseID, timestamp, _logger).Start();
await _computationJobStatus.UpdateJobProgressInformationAsync(
jobId, $"tasks.peer-groups", 0
).ConfigureAwait(false);

new NotificationsWorker(courseID, timestamp, _lmsHandler, notifications_bool, _logger).Start();
await _computationJobStatus.UpdateJobProgressInformationAsync(
jobId, $"tasks.notifications", 0
).ConfigureAwait(false);

_logger.LogInformation("Finishing sync");
await _computationJobStatus.UpdateJobProgressInformationAsync(
jobId, $"tasks.done", 0
).ConfigureAwait(false);

long duration = sw.ElapsedMilliseconds;
Console.WriteLine("Took: " + duration.ToString() + "ms");
DatabaseManager.Instance.CompleteSync(timestamp);

return result;
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using IguideME.Web.Models.Service;
using IguideME.Web.Services.LMSHandlers;
using IguideME.Web.Services.Workers;
using Microsoft.Extensions.Logging;

namespace IguideME.Web.Services
{
// Not strictly necessary since we only have 1 class but apparently good practice for DI and testing.
public interface ICanvasSyncService
{
Task<JobResultModel> DoWorkAsync(
string jobId,
JobParametersModel work,
CancellationToken cancellationToken
);
}

/// <summary>
/// Class <a>CanvasSyncService</a> implements ICanvasSyncService and is a service that manages syncs. .
/// </summary>
public sealed class CanvasSyncService : ICanvasSyncService
{
private readonly ILogger<SyncManager> _logger;
private readonly IComputationJobStatusService _computationJobStatus;
private readonly ILMSHandler _lmsHandler;

/// <summary>
/// This constructor initializes the new CanvasSyncService to
/// (<paramref name="computationJobStatus"/>, <paramref name="lmsHandler"/>, <paramref name="logger"/>).
/// </summary>
/// <param name="computationJobStatus"></param>
/// <param name="lmsHandler"></param>
/// <param name="logger"></param>
public CanvasSyncService(
IComputationJobStatusService computationJobStatus,
ILMSHandler lmsHandler,
ILogger<SyncManager> logger
)
{
_logger = logger;
_computationJobStatus = computationJobStatus;
_lmsHandler = lmsHandler;
}

/// <summary>
/// Performs the sync with camvas.
/// </summary>
/// <param name="jobId">The id of the job in storage.</param>
/// <param name="work">Data for the service.</param>
/// <param name="cancellationToken">Token used to cancel the sync.</param>
/// <returns>A task containging the result of the sync</returns>
public async Task<JobResultModel> DoWorkAsync(
string jobId,
JobParametersModel work,
CancellationToken cancellationToken
)
{
JobResultModel result = new();
int courseID = work.CourseID;
bool notifications_bool = false;

static bool isBetweenDates(DateTime input, DateTime startDate, DateTime endDate)
{
return (input >= startDate && input <= endDate);
}

List<string> notificationDates = DatabaseManager.Instance.GetNotificationDates(
courseID
);
if (notificationDates[0].Contains("-"))
{
// We are looking in a range of dates
foreach (string datepair in notificationDates)
{
string[] splittedDates = datepair.Split("-");
if (
isBetweenDates(
DateTime.Parse(String.Format("{0:yyyy/MM/dd}", DateTime.Now)),
DateTime.Parse(splittedDates[0]),
DateTime.Parse(splittedDates[1])
)
)
{
notifications_bool = work.Notifications_bool; // What is this bool??
break;
}
}
}
else
notifications_bool =
work.Notifications_bool
&& notificationDates.Contains(String.Format("{0:yyyy/MM/dd}", DateTime.Now));

_logger.LogInformation(
"{Time}: Starting sync for course {CourseID}",
DateTime.Now,
courseID
);

string timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString();

// Renew the connection with canvas.
_lmsHandler.SyncInit();

// Don't keep ancient syncs in the database.
DatabaseManager.Instance.CleanupSync(courseID);

// Register the new sync in the database.
DatabaseManager.Instance.RegisterSync(courseID, timestamp);
_logger.LogInformation("Sync hash: {Hash}", timestamp);
_logger.LogInformation("Course: {Course}", work.CourseID);

// Time how long the sync takes.
Stopwatch sw = new();
sw.Start();

new UserWorker(courseID, timestamp, _lmsHandler, _logger).Start();
await _computationJobStatus
.UpdateJobProgressInformationAsync(jobId, $"tasks.students", 0)
.ConfigureAwait(false);

new QuizWorker(courseID, timestamp, _lmsHandler, _logger).Start();
await _computationJobStatus
.UpdateJobProgressInformationAsync(jobId, $"tasks.quizzes", 0)
.ConfigureAwait(false);

new DiscussionWorker(courseID, timestamp, _lmsHandler, _logger).Start();
await _computationJobStatus
.UpdateJobProgressInformationAsync(jobId, $"tasks.discussions", 0)
.ConfigureAwait(false);

new AssignmentWorker(courseID, timestamp, _lmsHandler, _logger).Start();
await _computationJobStatus
.UpdateJobProgressInformationAsync(jobId, $"tasks.assignments", 0)
.ConfigureAwait(false);

_logger.LogInformation("Starting recycleexternaldata");
DatabaseManager.Instance.RecycleExternalData(courseID, timestamp);

new GradePredictorWorker(courseID, timestamp, _logger).Start();
await _computationJobStatus
.UpdateJobProgressInformationAsync(jobId, $"tasks.grade-predictor", 0)
.ConfigureAwait(false);

new PeerGroupWorker(courseID, timestamp, _logger).Start();
await _computationJobStatus
.UpdateJobProgressInformationAsync(jobId, $"tasks.peer-groups", 0)
.ConfigureAwait(false);

new NotificationsWorker(
courseID,
timestamp,
_lmsHandler,
notifications_bool,
_logger
).Start();
await _computationJobStatus
.UpdateJobProgressInformationAsync(jobId, $"tasks.notifications", 0)
.ConfigureAwait(false);

DatabaseManager.Instance.GetUsage(courseID, timestamp);
_logger.LogInformation("Finishing sync");
await _computationJobStatus
.UpdateJobProgressInformationAsync(jobId, $"tasks.done", 0)
.ConfigureAwait(false);

long duration = sw.ElapsedMilliseconds;
Console.WriteLine("Took: " + duration.ToString() + "ms");
DatabaseManager.Instance.CompleteSync(timestamp);

return result;
}
}
}
11 changes: 11 additions & 0 deletions IguideME.Web/Services/Constants/DatabaseQueries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1150,6 +1150,17 @@ ORDER BY `end_timestamp` DESC
AND `sync_hash`='{1}'
ORDER BY `name` ASC;";

public const string QUERY_USAGE =
@"SELECT `user_tracker`.`user_id`,
count(`user_tracker`.`user_id`)
FROM `user_tracker`
INNER JOIN `canvas_users`
ON `canvas_users`.`user_id`=`user_tracker`.`user_id`
WHERE `canvas_users`.`sync_hash`=@hash
AND `canvas_users`.`course_id`=@courseID
GROUP BY `user_tracker`.`user_id`
;";

public const string QUERY_USERS_WITH_ROLE_FOR_COURSE =
@"SELECT `id`,
`studentnumber`,
Expand Down
18 changes: 18 additions & 0 deletions IguideME.Web/Services/DatabaseManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,24 @@ public void RegisterDiscussionReply(AppDiscussion reply)
);
}

public void GetUsage(int courseID, string hash)
{
_logger.LogInformation("userID: #actions");
using (
SQLiteDataReader r = Query(
DatabaseQueries.QUERY_USAGE,
new SQLiteParameter("courseID", courseID),
new SQLiteParameter("hash", hash)
)
)
{
while (r.Read())
{
_logger.LogInformation("{}: {}", r.GetValue(0).ToString(), r.GetInt32(1));
}
}
}

public List<User> GetUsers(int courseID, string role = "%", string hash = null)
{
string activeHash = hash ?? this.GetCurrentHash(courseID);
Expand Down
1 change: 0 additions & 1 deletion IguideME.Web/Services/Workers/AssignmentWorker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ private void RegisterSubmissions(
break;
}

_logger.LogInformation("processing entryid {}", submission.EntryID);
DatabaseManager.Instance.CreateUserSubmission(
this._courseID,
submission,
Expand Down
Loading

0 comments on commit 2421cd8

Please sign in to comment.