Episerver community query and sort by last activity - episerver

I'm trying to query Episerver Community to get paged approved topics within a date range (e.g. within the last 2 days) that are ordered by the thread's last activity (activity being the thread's last approved reply or the thread's creation date if approved replies are 0).
I've tried using the GetTopics() method and aside from not being able to pass a date range, LastReply includes replies that are still in the moderation queue so the sort doesn't work correctly.
I've also tried to use the Query API but I'm unsure if it's possible to construct a query as complex as this. Is there any way of including AND/OR in the sort as well as making sure that the LastReply is approved? This is as far as I've got:
var topicQuery = new TopicQuery
{
Created = new DateTimeCriterion(),
Status = new EntityStatusCriterion
{
Operator = FlagsOperator.Equal,
Value = EntityStatus.Approved
},
LastReply = new ReplyCriterion{
Status = new EntityStatusCriterion(),
Created = new DateTimeCriterion()
}
};
//filter by days
if (withinDays > 0)
{
topicQuery.Created.Operator = ComparisonOperator.GreaterThan | ComparisonOperator.Equals;
topicQuery.Created.Value = DateTime.Now.AddDays(-withinDays);
}
//sort, this is incorrect, I am trying to sort by last approved reply date or created date if not available
//Last reply is sometimes not approved and it needs to be...
topicQuery.OrderBy.Add(new CriterionSortOrder(topicQuery.Created, SortingDirection.Descending));
topicQuery.OrderBy.Add(new CriterionSortOrder(topicQuery.LastReply.Created, SortingDirection.Descending));
var result = QueryHandler.GetQueryResult<Topic, MessageCollection>(topicQuery, page, pageSize);

Related

Google Sheet Coinmarketcap requesting 1 single importxml instead of 1 request for each coin

I am developing a sheet in google sheet that pulls data from coinmarketcap with a script i've been trying to write.
I am a f. noob # coding.
I use the function importxml (i need to refresh the latest price for each coin, like 100 coins) in this script:
function CryptoRefresher() {
var spreadsheet = SpreadsheetApp.getActive();
var queryString = Math.random();
var link1 = "C";
var xpath = "D";
var destination = "E";
var Direction=SpreadsheetApp.Direction;
var NumeroRighe =spreadsheet.getRange("B"+(spreadsheet.getLastRow()+1)).getNextDataCell(Direction.UP).getRow();
for (var i = 2; i <= NumeroRighe; i++) {
var cellFunction1 = '=IMPORTXML("' + SpreadsheetApp.getActiveSheet().getRange(link1+i).getValue() + '?' + queryString + '", "'+ SpreadsheetApp.getActiveSheet().getRange(xpath+i).getValue() + '")';
SpreadsheetApp.getActiveSheet().getRange(destination+i).setValue(cellFunction1);
}
};
Example Data:
Cell B2 = "bitcoin"
cell C2 = "https://coinmarketcap.com/currencies/Bitcoin"
Cell D2 = "//div[#class='priceValue___11gHJ']"
Cell E2 = is the destination and will receive the bitcoin price
The problem is that it's really slow because it calls 1 coin per time.
Question: Is there a way to send ALL THE COINS REQUESTS in 1 single importxml call?
Like I'd like to collect all the coin names in column C (1 cell of column C has 1 different and unique Coin Name) to collect all the coin names that i am watching and ask for 1 single call to speed up the process?
(Is there a way to create an array, a list of the coin names and do 1 single call to coinmarketcap?)
I really can't figure that out and i hope what i'm asking is clear!
Thank you!
Alessandro
Given the structure of the webpage, it is currently not possible to have a single IMPORTXML call to pull multiple arbitrary currencies from the CoinMarketCap site.
However, they have a convenient API that can do that exactly, please see references below:
CoinMarketCap API / Cryptocurrency
And this should get you started in pulling information from the API:
Pulling Currency Data to Google Sheets
I'd suggest using a dedicated service to retrieve the data, for instance this request will give you the data you need without any parsing or signing up to 3rd party services
=IMPORTDATA("https://cryptoprices.cc/BTC")
Trying to parse a complex web page under active development is just prone to fail at some point.
As alternative, go straight to the source, by signing up to the CoinMarketCap api to get more up to date data. (Already mentioned above) You can sign up for the free tier API (333 req/day) at https://pro.coinmarketcap.com/signup/
Wow! Сryptoprices.cc it’s a great service.
But some cryptocurrencies don’t read clearly.
If you change the formula, add / the price is updated and it is correct.

Why does this get method stop returning correctly?

I am trying to write an app engine application for my university. What I am trying to achieve right now, is to create a method which takes in a Course name, and returns a list of all the CourseYears (think of that as being like a link table e.g. if Maths is the course, and it has Year 1, year 2 and Year 3; MathsYear1, MathsYear2 and MathsYear3 would be the names of the CourseYears).
This is the code for the module (WARING: super dirty code below!):
#ApiMethod(name = "courseYears")
public ArrayList<CourseYear> courseYears(#Named("name") String name){
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
Query.Filter keyFilter = new Query.FilterPredicate("name", Query.FilterOperator.EQUAL, name);
Query query = new Query("Course").setFilter(keyFilter);
PreparedQuery preparedQuery = datastore.prepare(query);
List<Entity> resultList = preparedQuery.asList(FetchOptions.Builder.withLimit(1));
Course course = ofy().load().type(Course.class).id(resultList.get(0).getKey().getId()).now();
ArrayList<String> courseYearNames = course.getAllCourseYearNames();
System.out.println(course.getName());
ArrayList<CourseYear> courseYears = new ArrayList<CourseYear>();
for(String courseYearName: courseYearNames){
Query.Filter courseNameFilter = new Query.FilterPredicate("name", Query.FilterOperator.EQUAL, courseYearName);
Query query2 = new Query("CourseYear").setFilter(courseNameFilter);
List<Entity> resL = preparedQuery.asList(FetchOptions.Builder.withLimit(1));
System.out.println("test");
CourseYear courseYear = ofy().load().type(CourseYear.class).id(resL.get(0).getKey().getId()).now();
courseYears.add(courseYear);
}
return courseYears;
}
It basically takes a Course name in, applies a filter on all courses to get the corresponding Course object, and then calls getAllCourseYearNames() on the course to get an array list containing all its CourseYears' names. (I would have loved to do this using Keys, but parameterised Objectify keys don't seem to be supported in this version of App Engine).
I then try and get the CourseYears by looping through the arraylist of names and applying the filter for each name. I print "test" each time to see how many times it is looping. Like I said, a super dirty way of doing it.
When I try passing a few course names as a parameters, it loops the correct number of times only once or twice, and after that does not loop at all (doesn't print "test"). I could understand if it never looped, but not doing it correctly once or twice and then never again. It doesn't successfully return a list of CourseYears when it does work, but rather the relevant number of NULLs - I don't know if this is relevant. I believe it successfully retrieves the course every time, as I print the name of the course after loading and it never fails to do this.
If anyone has ANY suggestions for why this may be happening, I would be incredibly grateful to hear them!
Thanks
query2 is never used in your code. You reuse preparedQuery from your previous query, which runs on a different entity kind.

Google Forms as Multiple Choice Quiz - How to Provide Results

I've built a google form for a multiple choice quiz, with a linked spreadsheet for results, which works very well. I have a specific problem, which is that I'd like to present the user's results to them (i.e. how many answers they got right/wrong). The approach I've taken so far is:
create an extra sheet on the spreadsheet with a formula to calculate the number of correct answers for each response. This gives me two columns "Full Name" and "Scores"
embed the form into a google site
create a google apps script to read the results sheet and display output
embed the above into the same site below the form as an Apps Script Gadget
Currently I am able to display all of the results recorded so far. See here:
https://sites.google.com/site/mcqtest123/home
The script looks like:
// Script-as-app template.
function doGet() {
var app = UiApp.createApplication();
var title = app.createLabel("Survey Results").setStyleAttribute("fontSize","16px");
app.add(title);
//readRows(app);
calculateScores(app);
return app;
};
function calculateScores(app) {
var sheet = SpreadsheetApp.openById("0AlNR-ou0QtandFFzX1JCU1VRdTl0NVBRNTFjOUFhd1E");
var responseSheet = sheet.getSheetByName("Form Responses");
var allData = responseSheet.getDataRange().getValues();
var correct = allData[1];
var responses = allData.slice(2);
//Logger.log("Timestamp, name, score");
Logger.log("Name, Score");
for (var i = 0; i < responses.length; i++) {
var timestamp = responses[i][0];
var name = responses[i][1];
var score = 0;
for (var j = 2; j < correct.length; j++) {
if(responses[i][j] == correct[j]) {
score += 1;
}
}
//var output = timestamp + ", " + name + ", " + score + "/" + correct.length
var output = name + ", " + score + "/" + correct.length
print(app, output);
}
};
function print(app, line) {
Logger.log(line);
app.add(app.createLabel(line));
};
So this leaves two problems:
When the page loads, it loads the scores for all the respondents. I'd like to be able to present only the score for the person who filled out the form.
The scores don't get updated when the form is completed - only when the page is refreshed.
For problem 1), I wondered if there was some way to access the data in the form iframe (e.g. using document.getElementById('targetFrame'), except that google scripts don't seem to have access to the document model) to only display results of the person whose full name matches the name in the form (of course you could then view someone else's results if you know what they'd put as their full name, but without using the timestamp I don't see away round this).
For problem 2), I wondered if there was some way to trigger the script when the responses sheet was updated. However when I go to the spreadsheet and Tools->Script Manager I get the message "No scripts found", so I don't know how to add this trigger.
If you make your own form using HtmlService or UiApp and then that POSTing to your script to populate the spreadsheet, then you can generate a UID in a hidden field and use this to determine the results someone needs to see.
This will be the results as instant feedback to their answers to the quiz. To see these at a later date, you could then also add a bookmarkable link that also included that UID as a parameter. So your doGet() would look for a e.parameters.uid for example.
From Google Forms as they stand I am not so sure. you could potentially, with the new form styles, offer a pre-filled field with such a UID, but the route from form submission to your webapp is again unclear.

Manipulating DocList in SOLR

I have written a custom request handler in solr to meet my business requirements. The handler involves getting data from two different from SolrIndexSearchers. I want the returned doclists from the two SolrIndexSearchers merged into one.
I tried iterating through one and adding doc by doc to another, but all I could get was an "Unsupported Operation" exception. Is there anyway to merge two doclists?
[Edit 1] : Code snippet inside the overridden handleRequestBody method
SolrCore core = new SolrCore("Desired Directory 1", schema);
reader = IndexReader.open("Desired Directory 1");
searcher = new SolrIndexSearcher(core, schema, getName(), reader, false);
Sort lsort = null;
FilteredQuery filter = null;
DocList results1 = searcher.getDocList(query, filter, lsort, 0, 10);
reader.close();
searcher.close();
core.close();
SolrCore core = new SolrCore("Desired Directory 2", schema);
reader = IndexReader.open("Desired Directory 2");
searcher = new SolrIndexSearcher(core, schema, getName(), reader, false);
Sort lsort = null;
FilteredQuery filter = null;
DocList results2 = searcher.getDocList(query, filter, lsort, 0, 10);
reader.close();
searcher.close();
core.close();
rsp.add("response",results1);
rsp.add("response",results2);
Now that I have two DocLists results1 and results2, how do I merge them?
[Edit 2] : The problem is not an exception/stack trace. When I add two responses, I get the results in two response sets when it is a single machine search. When it is a distributed search, I only get the distribution between response 1 of machine 1 and response 1 of machine 2. IN my understanding, only when I merge the responses to a single set, I will be able to get proper distribution. Hope I am understandable?
DocList is not supposed to be changed after you retrieve it from a search result.
I had the similar problem and, if I remember correctly, I used:
org.apache.solr.util.SolrPluginUtils.docListToSolrDocumentList
to convert DocList to SolrDocumentList, which extends ArrayList<SolrDocument>, which consequently supports add(SolrDocument).
So the worst case scenario (from the performance standpoint) is to convert the first DocList to SolrDocumentList and then loop through all other DocLists calling add on each doc.
You'll have to test how efficient this approach is. I'm not Solr expert, but this is where I'd start testing.

How do I SubmitChanges on multiple tables that are related in LinqToSql?

I'm making a Windows Phone 7.1 application, and I'm having a lot of trouble submitting changes to my database. Here is the structure of the tables in my database:
Day <-1-----*-> TrainingSession <-many-----1-> Sport
So, a single day can have many training sessions, and a training session has one sport. A single sport can naturally be in many different training sessions.
The primary keys look like this:
Day - DateTime
TrainingSession - int (DB generated)
Sport - nvarchar(200)
Sports will simply have attributes sportName, and an iconFileName.
I've set up Associations by putting EntitySet in both Day and Sport, and TrainingSession has EntityRef and EntityRef. I'm not 100% sure if Sport needs the EntitySet, so please correct me if I'm wrong. For the moment, I just hard-coded some sports in my Sport class for testing, and you'll see me retrieving an ObservableCollection to get those out.
Here is how I am trying to create a collection of days with training sessions, each training session having different sports:
public void CreateDay(DateTime date)
{
FitPlanDataContext calendarDatabase = new FitPlanDataContext(FitPlanDataContext.ConnectionString);
DateTime firstDate = new DateTime(date.Year, date.Month, 1);
DayItem dayItem = new DayItem();
dayItem.DateTime = firstDate;
fillTestDayItemWithRandomData(dayItem);
calendarDatabase.DayItems.InsertOnSubmit(dayItem);
calendarDatabase.SubmitChanges();
}
private void fillTestDayItemWithRandomData(DayItem dayItem)
{
ObservableCollection<SportArt> sportArtCollection = SportArtController.GetAllSports();
dayItem.TrainingSessions = new EntitySet<TrainingSession>();
ObservableCollection<TrainingSession> trainingSessionCollection = new ObservableCollection<TrainingSession>();
TrainingSession trainingSession1 = new TrainingSession();
trainingSession1.DayItem = dayItem;
trainingSession1.SportArt = sportArtCollection[1];
trainingSessionCollection.Add(trainingSession1);
TrainingSession trainingSession2 = new TrainingSession();
trainingSession2.DayItem = dayItem;
trainingSession2.SportArt = sportArtCollection[2];
trainingSessionCollection.Add(trainingSession2);
FitPlanDataContext calendarDatabase = new FitPlanDataContext(FitPlanDataContext.ConnectionString);
calendarDatabase.TrainingSessions.InsertAllOnSubmit<TrainingSession>(trainingSessionCollection);
}
This code is not working for me, and it is giving me the following error:
NotSupportedException was Unhandled:
An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported.
Before I got this error, I was also getting NullReferenceExceptions.
I've been looking around for a solution, and I saw some people used Detach or workarounds with Attach, but I havent figured out how I could implement it to my code. Could anyone give me a helping hand with this?
Also, I thought the NullReferenceException could be coming from the fact that I'm not saving any sports to the database, could this be so?
So I messed around with it a lot, and today I finally found the solution I was looking for.
It seems I asked the question wrong. I didn't include the query from the database, which is probably important to add. I actually omitted a lot of the code to keep things simple in my question, but looks like I omitted too much.
Anyways, it turned out the way I setup the database structure was correct, and nothing had to be changed there.
So here's what I did to get it working:
-The call to the method that fills the day with training sessions needed to go after submitting changes about the day. This is because days have training sessions, and I cant save training sessions without the day already in the database.
-I added using statements around the places where I need to use the datacontext instead of just creating an instance of the datacontext with a local variable. This ensures that the datacontext lives only in the scope of the using statment.
(I changed the DateTime of the day to be the date given as the parameter to the method)
public void CreateDay(DateTime date)
{
DayItem dayItem = new DayItem();
dayItem.DateTime = date;
using (FitPlanDataContext calendarDatabase = new FitPlanDataContext(FitPlanDataContext.ConnectionString))
{
calendarDatabase.DayItems.InsertOnSubmit(dayItem);
calendarDatabase.SubmitChanges();
}
fillTestDayItemWithRandomData(dayItem);
}
Then, the changes to the method that fills the day with training sessions go like this:
-I open a using statement where I instantiate a new datacontext. Then I access the database to retrieve a list of all the sports, and also the day that I need to update. I find the day I need to update by dayItemParameter. (Remember that retrieving from the database will give you a collection.)
-I create my new training sessions and fill their properties. Note that the day I retrieved from the database is the value of a training session's property because the training session is a child of day, and needs to know who its parent day is.
-I removed the instantiation of EntitySet because I realized that I already instantiate it in the constructor of the DayItem class.
-Lastly, I add all the new training sessions into a collection, and save them all to the database at once using InsertAllOnSubmit(collection).
private void fillTestDayItemWithRandomData(DayItem dayItemParameter)
{
using (FitPlanDataContext calendarDatabase = new FitPlanDataContext(FitPlanDataContext.ConnectionString))
{
ObservableCollection<SportArt> sportArtCollection;
var sportArts = (from SportArt sportArt in calendarDatabase.SportArts
select sportArt);
sportArtCollection = new ObservableCollection<SportArt>(sportArts);
ObservableCollection<DayItem> dayItemCollection;
var dayItems = (from DayItem dayItem in calendarDatabase.DayItems
where dayItem.DateTime == dayItemParameter.DateTime
select dayItem);
dayItemCollection = new ObservableCollection<DayItem>(dayItems);
DayItem foundDayItem = dayItemCollection[0];
ObservableCollection<TrainingSession> trainingSessionCollection = new ObservableCollection<TrainingSession>();
TrainingSession trainingSession1 = new TrainingSession();
trainingSession1.DayItem = foundDayItem;
trainingSession1.SportArt = sportArtCollection[1];
trainingSessionCollection.Add(trainingSession1);
TrainingSession trainingSession2 = new TrainingSession();
trainingSession2.DayItem = foundDayItem;
trainingSession2.SportArt = sportArtCollection[2];
trainingSessionCollection.Add(trainingSession2);
calendarDatabase.TrainingSessions.InsertAllOnSubmit<TrainingSession>(trainingSessionCollection);
calendarDatabase.SubmitChanges();
}
}
Conclusion:
The main problem I was having was that I was trying to save training sessions to a day that wasn't submitted to the database. The next big problem (that I think many others have) is that reading and updating of an entity has to be in the same datacontext. So, you can't create a datacontext to retrieve a day, then use another datacontext to add a training session to that day (even if you saved the value of the day to a local variable). You need to retrieve the day and save training sessions to it all in the same data context.
At the moment, my application is working, but it is quite sluggish. In this question, I'm asking about just one day, but in my actual program, I'm creating hundreds of days, which means a lot of opening and closing of the database. If anyone has suggestions to how I can
optimize the process, I'm open ears.
I realize and apologize that this post got so long, but writing it helped me to understand the situation with more depth, and I really hope that it'll help others too.

Resources