feat: Refactor database access to use parameterized queries and improve error handling; update launch settings and add VSCode configuration files

This commit is contained in:
jim
2025-11-21 16:26:33 -06:00
parent 81e345b36f
commit 2640854f79
9 changed files with 216 additions and 75 deletions
+3 -1
View File
@@ -5,7 +5,9 @@
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"args": ["-pn"], // <--- ADD OR MODIFY THIS LINE "args": [
"-pn"
], // <--- ADD OR MODIFY THIS LINE
} }
] ]
} }
+3
View File
@@ -0,0 +1,3 @@
{
"dotnet.defaultSolution": "URLNotesGrabberCORE/URLNotesGrabberCORE.sln"
}
+41
View File
@@ -0,0 +1,41 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/URLNotesGrabberCORE.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/URLNotesGrabberCORE.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/URLNotesGrabberCORE.sln"
],
"problemMatcher": "$msCompile"
}
]
}
+41
View File
@@ -0,0 +1,41 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/URLNotesGrabberCORE.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/URLNotesGrabberCORE.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/URLNotesGrabberCORE.sln"
],
"problemMatcher": "$msCompile"
}
]
}
+114 -57
View File
@@ -194,11 +194,13 @@ namespace URLNotesGrabberCORE
{ {
connection.Open(); connection.Open();
string sql = "INSERT INTO DailyAPICount (Date) values('" + DateTime.Today.ToShortDateString() + "')"; string sql = "INSERT INTO DailyAPICount (Date) values(@date)";
SQLiteCommand command = new SQLiteCommand(sql, connection); using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{
command.Parameters.AddWithValue("@date", DateTime.Today.ToShortDateString());
command.ExecuteNonQuery(); command.ExecuteNonQuery();
} }
}
catch (Exception ex) catch (Exception ex)
{ {
//Console.WriteLine(ex.Message); //Console.WriteLine(ex.Message);
@@ -222,11 +224,18 @@ namespace URLNotesGrabberCORE
{ {
connection.Open(); connection.Open();
string sql = "INSERT INTO Notes (rootBlogName, noteBlogName, PostID, TimeStamp, Type) values('" + rootBlogName + "', '" + noteBlogName + "', " + postID + ", " + timestamp + ", '" + type + "')"; string sql = "INSERT INTO Notes (rootBlogName, noteBlogName, PostID, TimeStamp, Type) values(@rootBlogName, @noteBlogName, @PostID, @TimeStamp, @Type)";
SQLiteCommand command = new SQLiteCommand(sql, connection); using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{
command.Parameters.AddWithValue("@rootBlogName", rootBlogName);
command.Parameters.AddWithValue("@noteBlogName", noteBlogName);
command.Parameters.AddWithValue("@PostID", postID);
command.Parameters.AddWithValue("@TimeStamp", timestamp);
command.Parameters.AddWithValue("@Type", type ?? string.Empty);
command.ExecuteNonQuery(); command.ExecuteNonQuery();
} }
}
catch (Exception ex) catch (Exception ex)
{ {
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Notes.RootBlogName, Notes.PostID, Notes.TimeStamp, Notes.Type, Notes.NoteBlogName") if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Notes.RootBlogName, Notes.PostID, Notes.TimeStamp, Notes.Type, Notes.NoteBlogName")
@@ -377,15 +386,11 @@ namespace URLNotesGrabberCORE
{ {
connection.Open(); connection.Open();
string sql = "SELECT " + string sql = "SELECT APICount FROM DailyAPICount WHERE [Date] = @date";
" APICount " +
"FROM " +
" DailyAPICount " +
" WHERE [Date] = '" +
DateTime.Today.ToShortDateString() + "'";
using (SQLiteCommand command = new SQLiteCommand(sql, connection)) using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{ {
command.Parameters.AddWithValue("@date", DateTime.Today.ToShortDateString());
using (SQLiteDataReader reader = command.ExecuteReader()) using (SQLiteDataReader reader = command.ExecuteReader())
{ {
while (reader.Read()) while (reader.Read())
@@ -417,11 +422,15 @@ namespace URLNotesGrabberCORE
connection.Open(); connection.Open();
string sql = ""; string sql = "";
if (reblogsOnly) if (reblogsOnly)
sql = "SELECT NoteBlogName as blogName, count(*) from notes inner join blogs on blogs.BlogName = notes.NoteBlogName where type IN ('reblog', 'reply', 'posted') and HasBeenOutput = 0 group by NoteBlogName ORDER BY count(*) desc, BlogName LIMIT " + top; sql = "SELECT NoteBlogName as blogName, count(*) FROM notes INNER JOIN blogs ON blogs.BlogName = notes.NoteBlogName WHERE blogs.IsActive = @isActive AND type IN ('reblog', 'reply', 'posted') AND HasBeenOutput = 0 GROUP BY NoteBlogName ORDER BY count(*) DESC, BlogName LIMIT @top";
else else
sql = "SELECT NoteBlogName as blogName, count(*) from notes inner join blogs on blogs.BlogName = notes.NoteBlogName where type NOT IN ('reblog', 'reply', 'posted') and HasBeenOutput = 0 group by NoteBlogName ORDER BY count(*) desc, BlogName LIMIT " + top; sql = "SELECT NoteBlogName as blogName, count(*) FROM notes INNER JOIN blogs ON blogs.BlogName = notes.NoteBlogName WHERE blogs.IsActive = @isActive AND type NOT IN ('reblog', 'reply', 'posted') AND HasBeenOutput = 0 GROUP BY NoteBlogName ORDER BY count(*) DESC, BlogName LIMIT @top";
using (SQLiteCommand command = new SQLiteCommand(sql, connection)) using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{ {
command.Parameters.AddWithValue("@isActive", 1);
command.Parameters.AddWithValue("@top", top);
using (SQLiteDataReader reader = command.ExecuteReader()) using (SQLiteDataReader reader = command.ExecuteReader())
{ {
while (reader.Read()) while (reader.Read())
@@ -456,11 +465,15 @@ namespace URLNotesGrabberCORE
connection.Open(); connection.Open();
string sql = ""; string sql = "";
if (reblogsOnly) if (reblogsOnly)
sql = "SELECT NoteBlogName as blogName, count(*) from notes inner join blogs on blogs.BlogName = notes.NoteBlogName where type IN ('reblog', 'reply', 'posted') and HasBeenOutput = 0 group by NoteBlogName ORDER BY count(*) desc, BlogName LIMIT " + top; sql = "SELECT NoteBlogName as blogName, count(*) FROM notes INNER JOIN blogs ON blogs.BlogName = notes.NoteBlogName WHERE blogs.IsActive = @isActive AND type IN ('reblog', 'reply', 'posted') AND HasBeenOutput = 0 GROUP BY NoteBlogName ORDER BY count(*) DESC, BlogName LIMIT @top";
else else
sql = "SELECT NoteBlogName as blogName, count(*) from notes inner join blogs on blogs.BlogName = notes.NoteBlogName where HasBeenOutput = 0 group by NoteBlogName ORDER BY count(*) desc, BlogName LIMIT " + top; sql = "SELECT NoteBlogName as blogName, count(*) FROM notes INNER JOIN blogs ON blogs.BlogName = notes.NoteBlogName WHERE blogs.IsActive = @isActive AND HasBeenOutput = 0 GROUP BY NoteBlogName ORDER BY count(*) DESC, BlogName LIMIT @top";
using (SQLiteCommand command = new SQLiteCommand(sql, connection)) using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{ {
command.Parameters.AddWithValue("@isActive", 1);
command.Parameters.AddWithValue("@top", top);
using (SQLiteDataReader reader = command.ExecuteReader()) using (SQLiteDataReader reader = command.ExecuteReader())
{ {
while (reader.Read()) while (reader.Read())
@@ -497,11 +510,15 @@ namespace URLNotesGrabberCORE
{ {
connection.Open(); connection.Open();
string sql = "UPDATE Posts SET HasNotesGathered = 1, NotesGatheredDateTime = " + DateTimeOffset.UtcNow.ToUnixTimeSeconds() + " WHERE BlogName = '" + blogName + "' AND PostID = " + postID; string sql = "UPDATE Posts SET HasNotesGathered = 1, NotesGatheredDateTime = @notesGathered WHERE BlogName = @BlogName AND PostID = @PostID";
SQLiteCommand command = new SQLiteCommand(sql, connection); using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{
command.Parameters.AddWithValue("@notesGathered", DateTimeOffset.UtcNow.ToUnixTimeSeconds());
command.Parameters.AddWithValue("@BlogName", blogName);
command.Parameters.AddWithValue("@PostID", postID);
command.ExecuteNonQuery(); command.ExecuteNonQuery();
} }
}
catch (Exception ex) catch (Exception ex)
{ {
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID") if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
@@ -521,11 +538,14 @@ namespace URLNotesGrabberCORE
{ {
connection.Open(); connection.Open();
string sql = "UPDATE Posts SET NotFound = 1 WHERE BlogName = '" + blogName + "' AND PostID = " + postID; string sql = "UPDATE Posts SET NotFound = 1 WHERE BlogName = @BlogName AND PostID = @PostID";
SQLiteCommand command = new SQLiteCommand(sql, connection); using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{
command.Parameters.AddWithValue("@BlogName", blogName);
command.Parameters.AddWithValue("@PostID", postID);
command.ExecuteNonQuery(); command.ExecuteNonQuery();
} }
}
catch (Exception ex) catch (Exception ex)
{ {
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID") if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
@@ -545,11 +565,15 @@ namespace URLNotesGrabberCORE
{ {
connection.Open(); connection.Open();
string sql = "UPDATE Posts SET postDate = '" + postDate + "' WHERE BlogName = '" + blogName + "' AND PostID = " + postID; string sql = "UPDATE Posts SET postDate = @postDate WHERE BlogName = @BlogName AND PostID = @PostID";
SQLiteCommand command = new SQLiteCommand(sql, connection); using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{
command.Parameters.AddWithValue("@postDate", postDate ?? string.Empty);
command.Parameters.AddWithValue("@BlogName", blogName);
command.Parameters.AddWithValue("@PostID", postID);
command.ExecuteNonQuery(); command.ExecuteNonQuery();
} }
}
catch (Exception ex) catch (Exception ex)
{ {
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID") if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
@@ -574,11 +598,16 @@ namespace URLNotesGrabberCORE
{ {
connection.Open(); connection.Open();
string sql = string.Format("UPDATE Notes SET timestamp = '{0}' WHERE rootBlogName = '{1}' AND noteBlogName = '{2}' AND PostID = '{3}'", timestamp, rootBlogName, noteBlogName, postID); string sql = "UPDATE Notes SET timestamp = @timestamp WHERE rootBlogName = @rootBlogName AND noteBlogName = @noteBlogName AND PostID = @postID";
SQLiteCommand command = new SQLiteCommand(sql, connection); using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{
command.Parameters.AddWithValue("@timestamp", timestamp);
command.Parameters.AddWithValue("@rootBlogName", rootBlogName);
command.Parameters.AddWithValue("@noteBlogName", noteBlogName);
command.Parameters.AddWithValue("@postID", postID);
command.ExecuteNonQuery(); command.ExecuteNonQuery();
} }
}
catch (Exception ex) catch (Exception ex)
{ {
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Notes.RootBlogName, Notes.PostID, Notes.TimeStamp, Notes.Type, Notes.NoteBlogName") if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Notes.RootBlogName, Notes.PostID, Notes.TimeStamp, Notes.Type, Notes.NoteBlogName")
@@ -603,30 +632,54 @@ namespace URLNotesGrabberCORE
{ {
connection.Open(); connection.Open();
string sql = "UPDATE Posts "; string sql = "UPDATE Posts SET ";
sql += "SET postDate = " + Q(postDate) + ", "; sql += "postDate = @postDate, ";
sql += "reblogURL = " + Q(reblogURL) + ", "; sql += "reblogURL = @reblogURL, ";
sql += " postURL = " + Q(postURL) + ", "; sql += "postURL = @postURL, ";
sql += " slug = " + Q(slug) + ", "; sql += "slug = @slug, ";
sql += " reblogKey = " + Q(reblogKey) + ", "; sql += "reblogKey = @reblogKey, ";
sql += " reblogName = " + Q(reblogName) + ", "; sql += "reblogName = @reblogName, ";
sql += " summary = " + Q(summary) + ", "; sql += "summary = @summary, ";
sql += " quote = " + Q(quote) + ", "; sql += "quote = @quote, ";
sql += " body = " + Q(body) + ", "; sql += "body = @body, ";
sql += " tags = " + Q(tags) + ", "; sql += "tags = @tags, ";
sql += " link = " + Q(link) + ", "; sql += "link = @link, ";
sql += " photoURL = " + Q(photoURL) + ", "; sql += "photoURL = @photoURL, ";
sql += " photoCaption = " + Q(photoCaption) + ", "; sql += "photoCaption = @photoCaption, ";
sql += " downloadedFiles = " + Q(downloadedFiles) + ", "; sql += "downloadedFiles = @downloadedFiles, ";
sql += " audioCaption = " + Q(audioCaption) + ", "; sql += "audioCaption = @audioCaption, ";
sql += " question = " + Q(question) + ", "; sql += "question = @question, ";
sql += " answer = " + Q(answer) + ", "; sql += "answer = @answer, ";
sql += " title = " + Q(title) + ", "; sql += "title = @title, ";
sql += " hasImage = " + hasImage; sql += "hasImage = @hasImage ";
sql += " WHERE BlogName = " + Q(blogName) + " AND PostID = " + postID; sql += " WHERE BlogName = @BlogName AND PostID = @PostID";
SQLiteCommand command = new SQLiteCommand(sql, connection);
using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{
command.Parameters.AddWithValue("@postDate", postDate ?? string.Empty);
command.Parameters.AddWithValue("@reblogURL", reblogURL ?? string.Empty);
command.Parameters.AddWithValue("@postURL", postURL ?? string.Empty);
command.Parameters.AddWithValue("@slug", slug ?? string.Empty);
command.Parameters.AddWithValue("@reblogKey", reblogKey ?? string.Empty);
command.Parameters.AddWithValue("@reblogName", reblogName ?? string.Empty);
command.Parameters.AddWithValue("@summary", summary ?? string.Empty);
command.Parameters.AddWithValue("@quote", quote ?? string.Empty);
command.Parameters.AddWithValue("@body", body ?? string.Empty);
command.Parameters.AddWithValue("@tags", tags ?? string.Empty);
command.Parameters.AddWithValue("@link", link ?? string.Empty);
command.Parameters.AddWithValue("@photoURL", photoURL ?? string.Empty);
command.Parameters.AddWithValue("@photoCaption", photoCaption ?? string.Empty);
command.Parameters.AddWithValue("@downloadedFiles", downloadedFiles ?? string.Empty);
command.Parameters.AddWithValue("@audioCaption", audioCaption ?? string.Empty);
command.Parameters.AddWithValue("@question", question ?? string.Empty);
command.Parameters.AddWithValue("@answer", answer ?? string.Empty);
command.Parameters.AddWithValue("@title", title ?? string.Empty);
command.Parameters.AddWithValue("@hasImage", hasImage ? 1 : 0);
command.Parameters.AddWithValue("@BlogName", blogName);
command.Parameters.AddWithValue("@PostID", postID);
command.ExecuteNonQuery(); command.ExecuteNonQuery();
}
} }
catch (Exception ex) catch (Exception ex)
@@ -648,11 +701,13 @@ namespace URLNotesGrabberCORE
{ {
connection.Open(); connection.Open();
string sql = "UPDATE Blogs SET HasBeenOutput = 1 WHERE BlogName = '" + blogName + "'"; string sql = "UPDATE Blogs SET HasBeenOutput = 1 WHERE BlogName = @BlogName";
SQLiteCommand command = new SQLiteCommand(sql, connection); using (SQLiteCommand command = new SQLiteCommand(sql, connection))
{
command.Parameters.AddWithValue("@BlogName", blogName);
command.ExecuteNonQuery(); command.ExecuteNonQuery();
} }
}
catch (Exception ex) catch (Exception ex)
{ {
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID") if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
@@ -675,13 +730,14 @@ namespace URLNotesGrabberCORE
{ {
connection.Open(); connection.Open();
string sql = "UPDATE DailyAPICount SET APICount = " + APICount + string sql = "UPDATE DailyAPICount SET APICount = @APICount WHERE [Date] = @date";
" WHERE [Date] = '" + using (SQLiteCommand command = new SQLiteCommand(sql, connection))
DateTime.Today.ToShortDateString() + "'"; {
SQLiteCommand command = new SQLiteCommand(sql, connection); command.Parameters.AddWithValue("@APICount", APICount);
command.Parameters.AddWithValue("@date", DateTime.Today.ToShortDateString());
command.ExecuteNonQuery(); command.ExecuteNonQuery();
} }
}
catch (Exception ex) catch (Exception ex)
{ {
if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID") if (ex.Message != "constraint failed\r\nUNIQUE constraint failed: Posts.BlogName, Posts.PostID")
@@ -753,6 +809,7 @@ namespace URLNotesGrabberCORE
if (deserializedResult != null) if (deserializedResult != null)
{ {
myDeserializedClass = deserializedResult; myDeserializedClass = deserializedResult;
myDeserializedClass.rawJson = myJsonResponse;
} }
} }
catch (Exception ex) catch (Exception ex)
+1 -6
View File
@@ -364,6 +364,7 @@ namespace URLNotesGrabberCORE
else if (response.response == null) else if (response.response == null)
{ {
Console.WriteLine("##### Response Null - API Failure? ###"); Console.WriteLine("##### Response Null - API Failure? ###");
Console.WriteLine($"Raw JSON: {response.rawJson}");
return "FAILURE"; return "FAILURE";
} }
else if (response.response.notes == null) else if (response.response.notes == null)
@@ -373,12 +374,6 @@ namespace URLNotesGrabberCORE
} }
else else
{ {
if (response.response == null)
{
Console.WriteLine("response.response == null");
return "FAILURE";
}
while (response.response != null while (response.response != null
&& response.response._links != null && response.response._links != null
&& long.Parse(response.response._links.next.query_params.before_timestamp) >= post.Item3) && long.Parse(response.response._links.next.query_params.before_timestamp) >= post.Item3)
@@ -2,7 +2,7 @@
"profiles": { "profiles": {
"URLNotesGrabberCORE": { "URLNotesGrabberCORE": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "-collect 1" "commandLineArgs": "-collect 0"
} }
} }
} }
+2
View File
@@ -80,5 +80,7 @@ namespace URLNotesGrabberCORE
public string statusCode { get; set; } public string statusCode { get; set; }
public int retryInSeconds { get; set; } public int retryInSeconds { get; set; }
public string rawJson { get; set; }
} }
} }
Binary file not shown.