Spring WebFlux check user exists - spring

I want to check that the user has not been created yet before creating a new one, if there is then create an error... I found a similar question, but I can't remake it =(
Spring WebFlux: Emit exception upon null value in Spring Data MongoDB reactive repositories?
public Mono<CustomerDto> createCustomer(Mono<CustomerDto> dtoMono) {
//How Create Mono error???
Mono<Customer> fallback = Mono.error(new DealBoardException("Customer with email: " + dtoMono ???));
return dtoMono.map(customerConverter::convertDto) //convert from DTO to Document
.map(document -> {
customerRepository.findByEmailOrPhone(document.getEmail(), document.getPhone())
})
.switchIfEmpty() //How check such customer doesn't exists?
.map(document -> { //Filling in additional information from other services
var customerRequest = customerConverter.convertDocumentToStripe(document);
var customerStripe = customerExternalService.createCustomer(customerRequest);
document.setCustomerId(customerStripe.getId());
return document;
})
.flatMap(customerRepository::save) //Save to MongoDB
.map(customerConverter::convertDocument); //convert from Document to Dto
}

public Mono<User> create(String username, String password) {
User user = new User();
user.setUsername(username);
user.setPassword(encoder.encode(password));
return userRepo.existsUserByUsername(username)
.flatMap(exists -> (exists) ? Mono.error(UserAlreadyExists::new) : userRepo.save(user));
}

Add the following index declaration on the top of your Customer class:
#CompoundIndex(def = "{'email': 1, 'phone': 1}", unique = true)
That will prevent duplicate entries to be inserted in the database.
You can catch your org.springframework.dao.DuplicateKeyException with the following construct:
customerService.save(newCustomer).onErrorMap(...);
Ref: MongoDB Compound Indexes official documentation

Related

How to implement a list of DB update queries in one call with SpringBoot Webflux + R2dbc application

The goal of my springBoot webflux r2dbc application is Controller accepts a Request including a list of DB UPDATE or INSERT details, and Response a result summary back.
I can write a ReactiveCrudRepository based repository to implement each DB operation. But I don't know how to write the Service to group the executions of the list of DB operations and compose a result summary response.
I am new to java reactive programing. Thanks for any suggestions and help.
Chen
I get the hint from here: https://www.vinsguru.com/spring-webflux-aggregation/ . Ideas are :
From request to create 3 Monos
Mono<List> monoEndDateSet -- DB Row ids of update operation;
Mono<List> monoCreateList -- DB Row ids of new inserted;
Mono monoRespFilled -- partly fill some known fields;
use Mono.zip aggregate the 3 monos, map and aggregate the Tuple3 to Mono to return.
Below are key part of codes:
public Mono<ChangeSupplyResponse> ChangeSupplies(ChangeSupplyRequest csr){
ChangeSupplyResponse resp = ChangeSupplyResponse.builder().build();
resp.setEventType(csr.getEventType());
resp.setSupplyOperationId(csr.getSupplyOperationId());
resp.setTeamMemberId(csr.getTeamMemberId());
resp.setRequestTimeStamp(csr.getTimestamp());
resp.setProcessStart(OffsetDateTime.now());
resp.setUserId(csr.getUserId());
Mono<List<Long>> monoEndDateSet = getEndDateIdList(csr);
Mono<List<Long>> monoCreateList = getNewSupplyEntityList(csr);
Mono<ChangeSupplyResponse> monoRespFilled = Mono.just(resp);
return Mono.zip(monoRespFilled, monoEndDateSet, monoCreateList).map(this::combine).as(operator::transactional);
}
private ChangeSupplyResponse combine(Tuple3<ChangeSupplyResponse, List<Long>, List<Long>> tuple){
ChangeSupplyResponse resp = tuple.getT1().toBuilder().build();
List<Long> endDateIds = tuple.getT2();
resp.setEndDatedDemandStreamSupplyIds(endDateIds);
List<Long> newIds = tuple.getT3();
resp.setNewCreatedDemandStreamSupplyIds(newIds);
resp.setSuccess(true);
Duration span = Duration.between(resp.getProcessStart(), OffsetDateTime.now());
resp.setProcessDurationMillis(span.toMillis());
return resp;
}
private Mono<List<Long>> getNewSupplyEntityList(ChangeSupplyRequest csr) {
Flux<DemandStreamSupplyEntity> fluxNewCreated = Flux.empty();
for (SrmOperation so : csr.getOperations()) {
if (so.getType() == SrmOperationType.createSupply) {
DemandStreamSupplyEntity e = buildEntity(so, csr);
fluxNewCreated = fluxNewCreated.mergeWith(this.demandStreamSupplyRepository.save(e));
}
}
return fluxNewCreated.map(e -> e.getDemandStreamSupplyId()).collectList();
}
...

How to use ES Java API to create a new type of an index

I have succeed create an index use Client , the code like this :
public static boolean addIndex(Client client,String index) throws Exception {
if(client == null){
client = getSettingClient();
}
CreateIndexRequestBuilder requestBuilder = client.admin().indices().prepareCreate(index);
CreateIndexResponse response = requestBuilder.execute().actionGet();
return response.isAcknowledged();
//client.close();
}
public static boolean addIndexType(Client client, String index, String type) throws Exception {
if (client == null) {
client = getSettingClient();
}
TypesExistsAction action = TypesExistsAction.INSTANCE;
TypesExistsRequestBuilder requestBuilder = new TypesExistsRequestBuilder(client, action, index);
requestBuilder.setTypes(type);
TypesExistsResponse response = requestBuilder.get();
return response.isExists();
}
however, the method of addIndexType is not effected, the type is not create .
I don't know how to create type ?
You can create types when you create the index by providing a proper mapping configuration. Alternatively a type gets created when you index a document of a certain type. However the first suggestion is the better one, because then you can control the full mapping of that type instead of relying on dynamic mapping.
You can set types in the following way:
// JSON schema is the JSON mapping which you want to give for the index.
JSONObject builder = new JSONObject().put(type, JSONSchema);
// And then just fire the below command
client.admin().indices().preparePutMapping(indexName)
.setType(type)
.setSource(builder.toString(), XContentType.JSON)
.execute()
.actionGet();

How to query relational data using subclasses? parse.com and Unity

Im trying to query all elements of subclass in Unity. I have found SDK constraint or missing something here.
According to documentation querying subclasses is possible.
> var query = new ParseQuery<Armor>()
.WhereLessThanOrEqualTo("rupees", ((Player)ParseUser.CurrentUser).Rupees);
query.FindAsync().ContinueWith(t =>
{
IEnumerable<Armor> result = t.Result;
});
Im however using relation table and cannot specify
Here is my code:
IEnumerator LoadMyDesigns(Action<RequestResult> result) {
ParseUser user = ParseUser.CurrentUser;
ParseRelation<Design> relation = user.GetRelation<Design>("designs");
Task<IEnumerable<Design>> task = relation.Query.FindAsync();
while (!task.IsCompleted) yield return new WaitForEndOfFrame();
if (task.IsFaulted) {
//error
foreach(var e in task.Exception.InnerExceptions) {
ParseException parseException = (ParseException) e;
Debug.LogError("Error message " + parseException.Message);
Debug.LogError("Error code: " + parseException.Code);
result(new RequestResult(true, parseException.Message));
}
}
else {
result(new RequestResult(true, new List<Design>(task.Result)));
}
}
And error:
ArgumentNullException: Must specify a ParseObject class name when creating a ParseQuery.
So the question is how do I specify query subclass type when using relations?
Thanks.
I've struggled with the same problem and in my case I needed to provide the propertyName again in de GetRelationProperty call.
For example:
[ParseFieldName("designs")]
public ParseRelation<Design> Designs
{
get { return GetRelationProperty<Design>("Designs"); }
}
Try querying your designs Table.
Make a new query for class "Designs" where equal("owner", PFUser.currentUser())
This should return all of the designs for the current User.

OrientDB POJO Method proxy not working properly

I am using the OObjectDatabaseTx implementation of OrientDB to store my POJOs in the database. When I try to retrieve some POJOs with a SQL commant, I get the result set but the attributes of the POJOs seem to be empty (getters regurning null).
I register my classes properly with
db.getEntityManager().registerEntityClass(MyUser.class);
The following code describes my problem:
Map<String, String> params = new HashMap<String, String>();
params.put("name", username);
List<MyUser> users = db.command(
new OSQLSynchQuery<MyUser>(
"select * from MyUser where "
+ "name = :name"))
.execute(params);
for (MyUser founduser : users) {
ODocument doc = db.getRecordByUserObject(founduser, false);
String pass = doc.field("pwd");
assertEquals(pass != null, true); // passes
assertEquals(founduser.getPwd() != null, true); // fails
}
How can I get the method getPwd to return the proper value?
I am now using Version 1.3.0 and this has worked before (afaik in 1.1.0).
Can you see if the POJO has the "pwd" field set inside of it?

PrepareResponse().AsActionResult() throws unsupported exception DotNetOpenAuth CTP

Currently I'm developing an OAuth2 authorization server using DotNetOpenAuth CTP version. My authorization server is in asp.net MVC3, and it's based on the sample provided by the library. Everything works fine until the app reaches the point where the user authorizes the consumer client.
There's an action inside my OAuth controller which takes care of the authorization process, and is very similar to the equivalent action in the sample:
[Authorize, HttpPost, ValidateAntiForgeryToken]
public ActionResult AuthorizeResponse(bool isApproved)
{
var pendingRequest = this.authorizationServer.ReadAuthorizationRequest();
if (pendingRequest == null)
{
throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request.");
}
IDirectedProtocolMessage response;
if (isApproved)
{
var client = MvcApplication.DataContext.Clients.First(c => c.ClientIdentifier == pendingRequest.ClientIdentifier);
client.ClientAuthorizations.Add(
new ClientAuthorization
{
Scope = OAuthUtilities.JoinScopes(pendingRequest.Scope),
User = MvcApplication.LoggedInUser,
CreatedOn = DateTime.UtcNow,
});
MvcApplication.DataContext.SaveChanges();
response = this.authorizationServer.PrepareApproveAuthorizationRequest(pendingRequest, User.Identity.Name);
}
else
{
response = this.authorizationServer.PrepareRejectAuthorizationRequest(pendingRequest);
}
return this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();
}
Everytime the program reaches this line:
this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();
The system throws an exception which I have researched with no success. The exception is the following:
Only parameterless constructors and initializers are supported in LINQ to Entities.
The stack trace: http://pastebin.com/TibCax2t
The only thing I've done differently from the sample is that I used entity framework's code first approach, an I think the sample was done using a designer which autogenerated the entities.
Thank you in advance.
If you started from the example, the problem Andrew is talking about stays in DatabaseKeyNonceStore.cs. The exception is raised by one on these two methods:
public CryptoKey GetKey(string bucket, string handle) {
// It is critical that this lookup be case-sensitive, which can only be configured at the database.
var matches = from key in MvcApplication.DataContext.SymmetricCryptoKeys
where key.Bucket == bucket && key.Handle == handle
select new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc());
return matches.FirstOrDefault();
}
public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) {
return from key in MvcApplication.DataContext.SymmetricCryptoKeys
where key.Bucket == bucket
orderby key.ExpiresUtc descending
select new KeyValuePair<string, CryptoKey>(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc()));
}
I've resolved moving initializations outside of the query:
public CryptoKey GetKey(string bucket, string handle) {
// It is critical that this lookup be case-sensitive, which can only be configured at the database.
var matches = from key in db.SymmetricCryptoKeys
where key.Bucket == bucket && key.Handle == handle
select key;
var match = matches.FirstOrDefault();
CryptoKey ck = new CryptoKey(match.Secret, match.ExpiresUtc.AsUtc());
return ck;
}
public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) {
var matches = from key in db.SymmetricCryptoKeys
where key.Bucket == bucket
orderby key.ExpiresUtc descending
select key;
List<KeyValuePair<string, CryptoKey>> en = new List<KeyValuePair<string, CryptoKey>>();
foreach (var key in matches)
en.Add(new KeyValuePair<string, CryptoKey>(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc())));
return en.AsEnumerable<KeyValuePair<string,CryptoKey>>();
}
I'm not sure that this is the best way, but it works!
It looks like your ICryptoKeyStore implementation may be attempting to store CryptoKey directly, but it's not a class that is compatible with the Entity framework (due to not have a public default constructor). Instead, define your own entity class for storing the data in CryptoKey and your ICryptoKeyStore is responsible to transition between the two data types for persistence and retrieval.

Resources