vespa: query/result.getContext(true).logValue(key,value) not working in accesslog - vespa

i want to add a custom key/value pair to the access log, as https://docs.vespa.ai/en/access-logging.html
test is
#Override
public HttpResponse handle(HttpRequest request) {
Result result = null;
try {
String queryString = properties.getOrDefault("query", "");
Query query = new Query("?query=" + encode(queryString, StandardCharsets.UTF_8));
query.getContext(true).logValue("this_is_key", "this_is_value");
return response(query.toDetailString(), 200);
} catch (Exception e) {
log.log(Level.SEVERE, e.getMessage(), e);
}
return response("Error handling search request", 400);
}
output: qrs/JsonAccessLog.container
{"ip":"172.20.0.1","time":1625813285.167,"duration":0.011,"responsesize":61,"requestsize":0,"code":200,"method":"GET","uri":"/test/","version":"HTTP/1.1","agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36","host":"localhost:8080","scheme":"http","localport":8080,"peeraddr":"172.20.0.1","peerport":42082}
i can't find below element in the accss log
"attributes": { "this_is_key": "this_is_value" }
what's the problem?

The query context will only be populated to the access log in the context of a search handler. You may populate the attributes section from a request handler (e.g ThreadedHttpRequestHandler) through request.getAccessLogEntry().get.().addKeyValue(key, value).

Related

Re-index items in DSpace 6.2 after updating through REST

We are trying to build an application to provide bulk editing of item metadata ingested in DSpace, using the REST API. The update operations are being reflected in the DSpace UI. However the metadata remains unchanged in Solr, unless we run index-discovery. Since we intend to work with a large amount of data, running index-discovery everytime a metadata is edited, would be expensive. Could someone suggest a workaround/solution for this?
You could trigger an item update in the Java class of the REST endpoint.
For example:
In method addItemMetadata of java class org.dspace.rest.ItemsResource which represents the /items REST endpoint you could add the following line after the item metadata has been changed:
itemService.update(context, dspaceItem);
This line of code triggers an index update for that specific item.
This is what the complete addItemMetadata method will look like after the above change:
#POST
#Path("/{item_id}/metadata")
#Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response addItemMetadata(#PathParam("item_id") String itemId, List<org.dspace.rest.common.MetadataEntry> metadata,
#QueryParam("userIP") String user_ip, #QueryParam("userAgent") String user_agent,
#QueryParam("xforwardedfor") String xforwardedfor, #Context HttpHeaders headers, #Context HttpServletRequest request)
throws WebApplicationException
{
log.info("Adding metadata to item(id=" + itemId + ").");
org.dspace.core.Context context = null;
try
{
context = createContext();
org.dspace.content.Item dspaceItem = findItem(context, itemId, org.dspace.core.Constants.WRITE);
writeStats(dspaceItem, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers, request, context);
for (MetadataEntry entry : metadata)
{
// TODO Test with Java split
String data[] = mySplit(entry.getKey()); // Done by my split, because of java split was not function.
if ((data.length >= 2) && (data.length <= 3))
{
itemService.addMetadata(context, dspaceItem, data[0], data[1], data[2], entry.getLanguage(), entry.getValue());
}
}
itemService.update(context, dspaceItem);
context.complete();
}
catch (SQLException e)
{
processException("Could not write metadata to item(id=" + itemId + "), SQLException. Message: " + e, context);
}
catch (ContextException e)
{
processException("Could not write metadata to item(id=" + itemId + "), ContextException. Message: " + e.getMessage(),
context);
} catch (AuthorizeException e) {
processException("Could not update item(id=" + itemId + "), AuthorizeException. Message: " + e.getMessage(),
context);
} finally
{
processFinally(context);
}
log.info("Metadata to item(id=" + itemId + ") were successfully added.");
return Response.status(Status.OK).build();
}

Upload File to ASP.net Core API using Angular

I have been searching for this for about 2 days and there are many posts about this, but I cannot wrap my head around what I want to do.
What I want:
I want to upload a single file to the API using angular, then return the files that are in that folder.
What I've got:
[HttpPost]
[Route("uploadFile/{regionName}/{propertyName}")]
public async Task<IEnumerable<FileModel>> Post(ICollection<IFormFile> files, string regionName,string propertyName)
{
IEnumerable<FileModel> fileModels = null;
var route = Path.Combine(_baseRoot, regionName, propertyName);
PathCreator.CreateFolder(route, null);
try
{
var file = files.FirstOrDefault();
if(file == null)
throw new ArgumentException("File Cannot be null");
var uploads = Path.Combine(route, file.FileName);
using (var fileStream = new FileStream(uploads,FileMode.Create))
{
await file.CopyToAsync(fileStream);
}
fileModels = FileFinder.GetFiles(route);
}
catch (Exception e)
{
throw new ArgumentException(e.Message);
}
return fileModels;
}
AngularJs
viewModel.uploadFile = function () {
let regionName = "TestRegion";
let propertyName = "TestProperty";
let data = viewModel.getFormData();
let request = new XMLHttpRequest();
request.addEventListener("progress", viewModel.updateProgressBar, false);
request.addEventListener("load", transferComplete, false);
viewModel.isUploading = true;
request.open("POST", "/api/file/uploadFile/" + regionName + "/" + propertyName);
request.send(data);
}
/*gets selected file converts to form data*/
viewModel.getFormData = function() {
var formData = new FormData();
if (viewModel.file) {
formData.append("myFile",viewModel.file);
}
return formData;
}
What is Happening
this makes it to the API and my file is null every time. I cannot figure out why.
UPDATE
after changes
angularJs:
viewModel.uploadFile = function() {
let regionName = viewModel.region.name;
let propertyName = viewModel.property.name;
let postUrl = "/api/file/uploadFile/" + regionName + "-" + propertyName;
let formData = new FormData();
if (viewModel.file) {
formData.append("file", viewModel.file);
}
let request = new XMLHttpRequest();
// request.addEventListener("progress", viewModel.updateProgressBar, false);
request.addEventListener("load", transferComplete, false);
viewModel.isUploading = true;
request.open("POST", postUrl);
request.setRequestHeader("Content-Type", "multipart/form-data");
request.send(formData[0]);
}
cs:
[HttpPost]
[Route("uploadFile/{path}")]
[Consumes("multipart/form-data")]
public async Task<IActionResult> Post(IFormFile file, string path)
{
var formattedPath = FilePathFormatter.FormatFolder(path);
var newPath = PathCreator.CreateFolder(_baseRoot,formattedPath);
var size = file.Length;
if (file.Length > 0)
{
using (var stream = new FileStream(newPath,FileMode.Create))
{
await file.CopyToAsync(stream);
}
}
return Ok(new {size, newPath});
}
Request Header
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Content-Length:0
Content-Type:multipart/form-data
Cookie:.AspNetCore.Identity.Application=CfDJ8Jb7vPJ0S0dGnlF8mEfQj9lVY7ccwabgngMkzgRgijxfOqen20J0y2DkgaND5M-EtULRMv8Kun0dSchlF22T6faFlxcybpMs5PhwJ6lRznXHBAV7irCmufJu1NhRUfIvMwQBwj9dE862lPsuKUa3sNh9kUYJ6C2pjiGymMNP25NZfJKwJuMA2ewzD9iZnlk5x5E2UMzbhZH9f6Ks_VPLZ4MlNNerwiLV2mya1QaeOv9AXFi4DKOkEu64IfCNGocipF4wP-anP4FkAN1sZOXJcD52KSruxxoj3Yagl6miAZ1788tT-CBZVvgbSWBHOei7Qcm8BiDdMp6KxtQs30m-_MyrbSnMP2GG26rjDwqwsoXopjU7G3KjLu8lc8dOjZGCGLa2Yc5WF63zOis4_5CZdYwFugqA5Mg1qo8mI5xxoYZVOUR1lWbtV5H-MC2geOMH06B4s_OBt59ZP6IJfIDeKpzcDB-hBmC3EE6pW9-wVSmTwfklyMkR2dsWfrKVcQBcQKUXRhSE8YaL6UARqLXBPP9RTbMV8gybZ6SX3h1lGvsp60wW__cRbo6mKwnko-JH-FiO6ctJzI6ciETCOcaz2QSTMYZVIwEX9CYKR9VKw9MUAZCzFguJSYzSCUPCG8TXGr9MyR6HoMgqCpkHfwc522o; io=7RfOJO9stPcX4wFFAAAB
Host:localhost:57155
Origin:http://localhost:57155
Pragma:no-cache
Referer:http://localhost:57155/Files/Upload
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
General
Request URL:some url here
Request Method:POST
Status Code:500 Internal Server Error
Remote Address:[::1]:57155
Request Payload
------WebKitFormBoundaryhpPhzjBM0NH4f7IA--
I think your problem is that the name of the file input element in your form must match the action method parameter name where you receive the uploaded file.
In your example, the parameter name in the action method is files but the file input element in your form is named myFile. Rename myFile to files and it should work.

How can I access sqlite database on a webserver in codename one

Pls How can I access sqlite database on the webserver in codename one? I can only use database API to access database on the device. In order to access this on the webserver I think is quite different thing. Pls I need a snippet code on this. Thanks
Use the code below, not tested and you may have to adjust it to suite your need. Leave a comment if there's an issue:
ConnectionRequest req = new ConnectionRequest() {
#Override
protected void handleException(Exception ex) {
//handle error
}
};
req.setUrl(YourURL);
req.setPost(true);
req.setHttpMethod("POST"); //Change to GET if necessary
req.setDuplicateSupported(true);
req.addArgument("argumentToSendThroughPostOrGet1", "value1");
req.addArgument("argumentToSendThroughPostOrGet2", "value2");
NetworkManager.getInstance().addToQueueAndWait(req);
if (req.getResponseCode() == 200) {
Map<String, Object> out = new HashMap<>();
Display.getInstance().invokeAndBlock(() -> {
JSONParser p = new JSONParser();
try (InputStreamReader r = new InputStreamReader(new ByteArrayInputStream(req.getResponseData()))) {
out.putAll(p.parseJSON(r));
} catch (IOException ex) {
//handle error
}
});
if (!out.isEmpty()) {
List<Map<String, Object>> responses = (List<Map<String, Object>>) out.get("response");
for (Object response : responses) {
Map res = (Map) response;
System.out.println(res.get("key"));
}
} else {
//handle error
}
} else {
//handle error
}
TEST JSON RESPONSE:
{
"response": [
{
"key": "I was returned",
}
]
}
EDIT:
To pass data from TextField:
req.addArgument("argumentToSendThroughPostOrGet1", myTextField.getText());
Based on your comment, you can read those arguments in PHP as simple as below:
$var1 = $_POST["argumentToSendThroughPostOrGet1"];
$var1 = $_GET["argumentToSendThroughPostOrGet1"]; // if GET method is used in Codename One
//Or use $_REQUEST which supports both methods but not advisable to be used for production
...
And you can use those variables in your php code normally.
Example of Usage with MySql Query:
class Connection {
function connect() {
$mysqli = mysqli_init();
$mysqli->real_connect("localhost", "username", "password", "databaseName") or die('Could not connect to database!');
$mysqli->query("SET NAMES 'UTF8'");
return $mysqli;
}
function close() {
mysqli_close($this->connect);
}
}
$connection = new Connection();
$mysqli = $connection->connect();
$mysqli->query("SELECT * FROM MyTable WHERE ColumnName LIKE '%$var1%' ORDER BY PrimaryKeyId ASC LIMIT 100");

Set field Accessibility to Custom Salesforce Lead field from Java code

I am working around with Salesforce and force.com API and metadata API, version 36.
I can create a custom field in a Lead object but by default I can see it's hidden and this means I cannot create a new Lead with these custom fields because it returns a bad request (400 status code).
Is there any way by Code to set the custom field Visible?
public boolean createCustomExtTextField(String name, LoginResult metadataLoginResult, int length) {
boolean success = false;
CustomField cs = new CustomField();
cs.setFullName("Lead."+name+"__c");
cs.setLabel("Custom"+name+"Field");
cs.setType(FieldType.LongTextArea);
cs.setLength(length);
cs.setVisibleLines(50); // max 50
try {
MetadataConnection metadataConnection = createMetadataConnection(metadataLoginResult);
SaveResult[] results = metadataConnection.createMetadata(new Metadata[] { cs });
for (SaveResult r : results) {
if (r.isSuccess()) {
success = true;
} else {
System.out.println("Errors were encountered while creating " + r.getFullName());
for (com.sforce.soap.metadata.Error e : r.getErrors()) {
System.out.println("Error message: " + e.getMessage());
System.out.println("Status code: " + e.getStatusCode());
}
}
}
} catch (ConnectionException e) {
e.printStackTrace();
}
return success;
}
I am googling a lot and don't find something that actually helped. So, any hints are welcomed. Thank you.
Finally found a solution to this. I final one for me was to make all custom fields REQUIRED.
CustomField cs = new CustomField();
cs.setFullName("Lead.YourCompanyName" + name + "__c");
cs.setLabel("YourCompanyName" + name);
cs.setRequired(true);
...
com.sforce.soap.enterprise.LoginResult metadataLoginResult = operations.loginToMetadata(username, password, "https://login.salesforce.com/services/Soap/c/36.0");
...
private boolean createFieldInMetadata(LoginResult metadataLoginResult, CustomField cs) {
boolean success = false;
try {
MetadataConnection metadataConnection = createMetadataConnection(metadataLoginResult);
SaveResult[] results = metadataConnection.createMetadata(new Metadata[] { cs });
for (SaveResult r : results) {
if (r.isSuccess()) {
success = true;
} else {
System.out.println("Errors were encountered while creating " + r.getFullName());
for (com.sforce.soap.metadata.Error e : r.getErrors()) {
System.out.println("Error message: " + e.getMessage());
System.out.println("Status code: " + e.getStatusCode());
}
}
}
} catch (Exception e) {
}
return success;
}
And so it will appear in the page layout. Very important to know, a required field cannot have just an empty value set, it must be something. So if not all custom fields are required in your logic and you wanna avoid the entire process of unzipping page layout and zipping it back (however it may be done) just add "N/A" or any char at choice to the required by code but not your project custom fields.
I managed to make the custom Field Level Security visible for "Admin" profile but not Field Accessability to visible. The latter is untested.

Get Unread emails from Google API

I'm trying to get the count of unread email using google API, but not able. ANy help is highly appreciated. I'm not getting any error, but the count doesnt match the actual number shown in gmail.
try
{
String serviceAccountEmail = "xxx#developer.gserviceaccount.com";
var certificate = new X509Certificate2(#"C:\Projects\xxx\xyz\API Project-xxxxx.p12", "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
User = "xxx#gmail.com",
Scopes = new[] { Google.Apis.Gmail.v1.GmailService.Scope.GmailReadonly }
}.FromCertificate(certificate));
var gmailservice = new Google.Apis.Gmail.v1.GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "GoogleApi3",
});
try
{
List<Message> lst = ListMessages(gmailservice, "xxx#gmail.com", "IN:INBOX IS:UNREAD");
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
}
}
catch (Exception ex)
{
}
Just do: labels.get(id="INBOX") and it has those types of stats (how many messages in that label, how many are unread, and same for threads).
https://developers.google.com/gmail/api/v1/reference/users/labels/get
You can use the ListMessages method from the API example (included for completeness) for searching:
private static List<Message> ListMessages(GmailService service, String userId, String query)
{
List<Message> result = new List<Message>();
UsersResource.MessagesResource.ListRequest request = service.Users.Messages.List(userId);
request.Q = query;
do
{
try
{
ListMessagesResponse response = request.Execute();
result.AddRange(response.Messages);
request.PageToken = response.NextPageToken;
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
}
} while (!String.IsNullOrEmpty(request.PageToken));
return result;
}
You can use this search method to find unread messages, for example like this:
List<Message> unreadMessageIDs = ListMessages(service, "me", "is:unread");
The q parameter (query) can be all kinds of stuff (it is the same as the gmail search bar on the top of the web interface), as documented here: https://support.google.com/mail/answer/7190?hl=en.
Note that you only a few parameters of the Message objects are set. If you want to retreive the messages you'll have to use GetMessage method from the api:
public static Message GetMessage(GmailService service, String userId, String messageId)
{
try
{
return service.Users.Messages.Get(userId, messageId).Execute();
}
catch (Exception e)
{
Console.WriteLine("An error occurred: " + e.Message);
}
return null;
}
I agree that the API is not straight forward and misses a lot of functionality.
Solution for .Net:
// Get UNREAD messages
public void getUnreadEmails(GmailService service)
{
UsersResource.MessagesResource.ListRequest Req_messages = service.Users.Messages.List("me");
// Filter by labels
Req_messages.LabelIds = new List<String>() { "INBOX", "UNREAD" };
// Get message list
IList<Message> messages = Req_messages.Execute().Messages;
if ((messages != null) && (messages.Count > 0))
{
foreach (Message List_msg in messages)
{
// Get message content
UsersResource.MessagesResource.GetRequest MsgReq = service.Users.Messages.Get("me", List_msg.Id);
Message msg = MsgReq.Execute();
Console.WriteLine(msg.Snippet);
Console.WriteLine("----------------------");
}
}
Console.Read();
}

Resources