Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plaintext votes 2 #141

Merged
merged 20 commits into from
Dec 13, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2e6f639
Create data structures necessary for plaintext voting.
vteague Dec 7, 2022
002cbcf
Added command and correct URL
vteague Dec 8, 2022
5eb629e
Shifting some of the commands into the QuestionViewModel or QuestionD…
vteague Dec 10, 2022
2339874
QuestionDisplayCards now displaying properly with new view model.
vteague Dec 10, 2022
fef1d9a
Remove SelectedQuestion from ReadingPage
vteague Dec 10, 2022
4a406f4
Merge remote-tracking branch 'origin/main' into plaintext-votes-2
vteague Dec 10, 2022
bf3013a
Only test now failing is the UpvoteQuestion test.
vteague Dec 11, 2022
a53b7b5
Added & modified some Question and QuestionViewModel tests.
vteague Dec 11, 2022
cdf3c90
Reformatted QuestionDisplayCard.xaml to fit upvote / total data.
vteague Dec 11, 2022
c31b3d8
Slightly better-spaced QuestionDisplayCard.xaml.
vteague Dec 11, 2022
099111f
Minimal plaintext up-voting working, but without keeping track of whi…
vteague Dec 11, 2022
3a78cf8
Explicit passing of question responses compiling but not implemented.
vteague Dec 11, 2022
d25eb15
Plaintext up-voting now working, but not Dismissing or down-voting. T…
vteague Dec 11, 2022
4e00ddd
Both plaintex up-voting and dismissing now working.
vteague Dec 11, 2022
a76c021
Both plaintext upvoting and vote-dismissing mostly working.
vteague Dec 11, 2022
b07d615
Slight refactor of some of the things that should be in QuestionViewM…
vteague Dec 11, 2022
270a5a9
Corrections to plaintext upvotes. Now seems to be working correctly, …
vteague Dec 12, 2022
de4ab96
Wrapped QuestionResponseRecords.cs Init in a test to see if it's alre…
vteague Dec 12, 2022
11df564
Preceded some more uploads with a check that you're already registere…
vteague Dec 12, 2022
5475eca
Remove commented-out code.
vteague Dec 13, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ public static class Constants
public static string IsVerifiedMPAccount = "IsVerifiedMPAccount";
public static string MPRegisteredAs= "MPRegisteredAs";
public static string Address = "Address";
public static string DownvotedQuestions = "DownvotedQuestions";
public static string UpvotedQuestions = "UpvotedQuestions";
public static string DismissedQuestions = "DismissedQuestions";
public static string ReportedQuestions = "ReportedQuestions";

// Special numbers
public static float similarityThreshold = 2.5F;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

public class TriedToUploadWhileNotRegisteredException : Exception
{
public TriedToUploadWhileNotRegisteredException()
{
}

public TriedToUploadWhileNotRegisteredException(string message)
: base(message)
{
}

public TriedToUploadWhileNotRegisteredException(string message, Exception inner)
: base(message, inner)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public static class RTAClient
private static readonly string EditUserUrl = BaseUrl + "/edit_user";
private static readonly string QnUrl = BaseUrl + "/new_question";
private static readonly string EditQnUrl = BaseUrl + "/edit_question";
private static readonly string PlaintextVoteQnUrl = BaseUrl + "/plaintext_vote_question";
private static readonly string MPListUrl = BaseUrl + "/MPs.json";
private static readonly string CommitteeListUrl = BaseUrl + "/committees.json";
private static readonly string HearingsListUrl = BaseUrl + "/hearings.json";
Expand Down Expand Up @@ -154,6 +155,11 @@ public static async Task<JOSResult<string>> UpdateExistingQuestion(QuestionSendT
{
return await SignAndSendDataToServer(existingQuestion, AppResources.QuestionErrorTypeDescription, EditQnUrl, "Error editing question", uid);
}

public static async Task<JOSResult<string>> SendPlaintextUpvote(PlainTextVoteOnQuestionCommand voteOnQuestion, string uid)
{
return await SignAndSendDataToServer(voteOnQuestion, AppResources.QuestionErrorTypeDescription, PlaintextVoteQnUrl, "Error voting on question", uid);
}

public static async Task<JOSResult<string>> RequestEmailValidation(ClientSignedUnparsed signedMsg, string email)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,6 @@ public static IndividualParticipant getInstance()
public bool AddressUpdated { get; set; }
public bool HasQuestions { get; set; }

// needs to be accessible on a few pages and VMs so I put it here
public List<string> UpvotedQuestionIDs { get; set; } = new List<string>();
public List<string> ReportedQuestionIDs { get; set; } = new List<string>();
public List<string> RemovedQuestionIDs { get; set; } = new List<string>();

public ClientSignedUnparsed SignMessage<T>(T message)
{
Expand Down
120 changes: 24 additions & 96 deletions RightToAskClient/RightToAskClient/RightToAskClient/Models/Question.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ public enum QuestionDetailsStatus

public class Question : ObservableObject
{
// Note these relate to whether this user up- or down-voted the question, not the global tally.
private int _upVotesByThisUser;
private int _downVotesByThisUser;

public QuestionDetailsStatus Status { get; set; }

private string _questionText = "";
Expand All @@ -36,7 +32,6 @@ public string QuestionText
set
{
SetProperty(ref _questionText, value);
//** QuestionViewModel.Instance.ServerQuestionUpdates.question_text = _questionText;
Updates.question_text = _questionText;
}
}
Expand Down Expand Up @@ -137,22 +132,6 @@ public RTAPermissions WhoShouldAnswerTheQuestionPermissions
}
}

public string QuestionAnswerers =>
Extensions.JoinFilter(", ",
string.Join(", ",Filters.SelectedAnsweringMPsNotMine.Select(mp => mp.ShortestName)),
string.Join(", ",Filters.SelectedAnsweringMPsMine.Select(mp => mp.ShortestName)),
string.Join(", ",Filters.SelectedAuthorities.Select(a => a.ShortestName)));

// The MPs or committee who are meant to ask the question
public string QuestionAskers =>
Extensions.JoinFilter(", ",
string.Join(", ", Filters.SelectedAskingMPsNotMine.Select(mp => mp.ShortestName)),
string.Join(", ", Filters.SelectedAskingMPsMine.Select(mp => mp.ShortestName)),
string.Join(",", Filters.SelectedCommittees.Select(com => com.ShortestName)));
// TODO add:
// + String.Join(",",Filters.SelectedAskingUsers.Select(....));



// Whether the person writing the question allows other users to add QuestionAnswerers
private RTAPermissions _whoShouldAskTheQuestionPermissions;
Expand Down Expand Up @@ -181,25 +160,11 @@ public List<Uri> HansardLink
//** QuestionViewModel.Instance.ServerQuestionUpdates.hansard_link = _hansardLink;
}

public int UpVotesByThisUser
{
get => _upVotesByThisUser;
set => SetProperty(ref _upVotesByThisUser, value);
}
public int DownVotesByThisUser
{
get => _downVotesByThisUser;
set
{
_downVotesByThisUser = value;
OnPropertyChanged();
}
}
private bool _alreadyUpvoted;
public bool AlreadyUpvoted
{
get => _alreadyUpvoted;
set => SetProperty(ref _alreadyUpvoted, value);
private set => SetProperty(ref _alreadyUpvoted, value);
}

private bool _alreadyReported;
Expand All @@ -216,73 +181,22 @@ public bool HasAnswer
set => SetProperty(ref _hasAnswer, value);
}

// constructor needed for command creation
// Explicit empty constructor, for use in the case we're generating our own question.
public Question()
{
UpvoteCommand = new Command(async () =>

{
// can only upvote questions if you are registered
if (IndividualParticipant.getInstance().ProfileData.RegistrationInfo.IsRegistered)
{
if (!AlreadyUpvoted)
{
UpVotesByThisUser += 1;
AlreadyUpvoted = true;
IndividualParticipant.getInstance().UpvotedQuestionIDs.Add(QuestionId);
}
else
{
UpVotesByThisUser -= 1;
AlreadyUpvoted = false;
IndividualParticipant.getInstance().UpvotedQuestionIDs.Remove(QuestionId);
}
}
else
{
await NavigationUtils.DoRegistrationCheck(
IndividualParticipant.getInstance().ProfileData.RegistrationInfo,
AppResources.NotNowAnswerText);
}
});
QuestionDetailsCommand = new Command(() =>
{
QuestionViewModel.Instance.Question = this;
QuestionViewModel.Instance.IsNewQuestion = false;
_ = Shell.Current.GoToAsync($"{nameof(QuestionDetailPage)}");
});
ShareCommand = new AsyncCommand(async() =>
{
await Share.RequestAsync(new ShareTextRequest
{
Text = QuestionText,
Title = "Share Text"
});
});
ReportCommand = new Command(() =>
{
AlreadyReported = !AlreadyReported;
if (AlreadyReported)
{
IndividualParticipant.getInstance().ReportedQuestionIDs.Add(QuestionId);
}
else
{
IndividualParticipant.getInstance().ReportedQuestionIDs.Remove(QuestionId);
}
});
}

// For questions we read off the server - check whether we've previously up-voted them or
// reported them.
public Question(in QuestionResponseRecords questionResponses) : base()
{
}

// commands
public Command UpvoteCommand { get; }
public Command ReportCommand { get; }
public Command QuestionDetailsCommand { get; }
public IAsyncCommand ShareCommand { get; }

// Call empty constructor to initialize commands etc.
// Then convert data downloaded from server into a displayable form.
public Question(QuestionReceiveFromServer serverQuestion) : this()
public Question(QuestionReceiveFromServer serverQuestion, QuestionResponseRecords questionResponses)
{

// question-defining fields
QuestionSuggester = serverQuestion.author ?? "";
QuestionText = serverQuestion.question_text ?? "";
Expand All @@ -301,6 +215,10 @@ public Question(QuestionReceiveFromServer serverQuestion) : this()
// question non-defining fields
Background = serverQuestion.background ?? "";

// Check whether the user has already responded to this question.
AlreadyUpvoted = questionResponses.IsAlreadyUpvoted(QuestionId);
AlreadyReported = questionResponses.IsAlreadyReported(QuestionId);

interpretFilters(serverQuestion);

WhoShouldAnswerTheQuestionPermissions = serverQuestion.who_should_answer_the_question_permissions;
Expand Down Expand Up @@ -451,6 +369,16 @@ public void AddAnswer(string answer)
};
}

public void ToggleUpvotedStatus()
{
AlreadyUpvoted = !AlreadyUpvoted;
}

public void ToggleReportStatus()
{
AlreadyReported = !AlreadyReported;
}

//validation
public bool ValidateNewQuestion()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using System;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would like some more tests for this. For example try and test what happens when you try to add something in the hashset

using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.Json;
using RightToAskClient.Helpers;
using Xamarin.Forms;

namespace RightToAskClient.Models
{
/*
* Stores information about this user's responses to questions: which ones
* they've up-voted, down-voted, dismissed, flagged.
*/
public class QuestionResponseRecords
{
private HashSet<string> _upvotedQuestionIDs;
private HashSet<string> _downvotedQuestionIDs;
private HashSet<string> _reportedQuestionIDs;
private HashSet<string> _dismissedQuestionIDs;
private bool _isInitialised;

public void Init()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation seems strange in this file, are the methods meant to be indented that far?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry about this

{
if (!_isInitialised)
{
// Retrieve from preferences.
_upvotedQuestionIDs = retrieveHashSetFromPreferences(Constants.UpvotedQuestions);
_downvotedQuestionIDs = retrieveHashSetFromPreferences(Constants.DownvotedQuestions);
_dismissedQuestionIDs = retrieveHashSetFromPreferences(Constants.DismissedQuestions);
_reportedQuestionIDs = retrieveHashSetFromPreferences(Constants.ReportedQuestions);
_isInitialised = true;
}
}


public void AddDownvotedQuestion(string questionID)
{
_downvotedQuestionIDs.Add(questionID);
storeHashSetInPreferences(Constants.DownvotedQuestions, _downvotedQuestionIDs);
}

public bool IsAlreadyDownvoted(string questionID) => _downvotedQuestionIDs.Contains(questionID);

public void AddUpvotedQuestion(string questionID)
{
_upvotedQuestionIDs.Add(questionID);
storeHashSetInPreferences(Constants.UpvotedQuestions, _upvotedQuestionIDs);
}

public bool IsAlreadyUpvoted(string questionID) => _upvotedQuestionIDs.Contains(questionID);

public void AddReportedQuestion(string questionID)
{
_reportedQuestionIDs.Add(questionID);
storeHashSetInPreferences(Constants.ReportedQuestions, _reportedQuestionIDs);
}

public bool IsAlreadyReported(string questionID) => _reportedQuestionIDs.Contains(questionID);

public void AddDismissedQuestion(string questionID)
{
_dismissedQuestionIDs.Add(questionID);
storeHashSetInPreferences(Constants.DismissedQuestions, _dismissedQuestionIDs);
}

public bool IsAlreadyDismissed(string questionID) => _dismissedQuestionIDs.Contains(questionID);

private void storeHashSetInPreferences(string key, HashSet<string> hashSet)
{
try
{
var hashSetString = JsonSerializer.Serialize(hashSet);
XamarinPreferences.shared.Set(key, hashSetString);
}
catch (Exception e)
{
Debug.WriteLine("Error storing "+key+" to preferences: "+e.Message);
}
}
private HashSet<string> retrieveHashSetFromPreferences(string key)
{
var retrievedSet = new HashSet<string>();

var retrievedString = XamarinPreferences.shared.Get(key, "");
if (!String.IsNullOrEmpty(retrievedString))
{
try
{
retrievedSet = JsonSerializer.Deserialize<HashSet<string>>(retrievedString);
}
catch (Exception e)
{
Debug.WriteLine("Error deserialising "+key+":"+e.Message);
}
}

return retrievedSet ?? new HashSet<string>();;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Text.Json.Serialization;

namespace RightToAskClient.Models.ServerCommsData
{
public class PlainTextVoteOnQuestionCommand
{

[JsonPropertyName("question_id")]
public string question_id { get; set; }

[JsonPropertyName("up")]
public bool up { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Text.Json.Serialization;

namespace RightToAskClient.Models.ServerCommsData
{
public class PlaintextVoteOnQuestionCommandPostedToBulletinBoard
{
[JsonPropertyName("command")]
public ClientSignedUnparsed command { get; set; }


}
}
Loading