How can I get country's timezone? - android-studio

I want to get the country's timezone to prevent a user to change his time to be able to use my application. Now, I set my application's opening hours between 8AM to 5PM. When a user change his time to the opening hours even if it is not yet the time in his country, the user cannot proceed to the restaurant fragment but I don't have any idea how do it. I have searched Google yet didn't find any solutions. I hope someone can help me.
This is my current code:
val tz = TimeZone.getTimeZone("GMT+8")
val c = Calendar.getInstance(tz)
val mHour = c.get(Calendar.HOUR_OF_DAY)
val mMinute = c.get(Calendar.MINUTE);
if (mHour >= 8 && mHour <= 17) {
viewModel.getMessageError().observe(this, Observer {
Toast.makeText(context, it, Toast.LENGTH_SHORT).show()
})
viewModel.getRestaurantList().observe(this, Observer {
dialog.dismiss()
adapter = MyRestaurantAdapter(requireContext(), it)
recycler_restaurant!!.adapter = adapter
recycler_restaurant!!.layoutAnimation = layoutAnimationCotroller
})
}
else {
dialog.dismiss()
Toast.makeText(
context,
"Shop is closed. We're open between 8AM to 5PM",
Toast.LENGTH_SHORT
).show()
}

If i understand correctly, you want to get Calendar with local timezone. So you can do this by removing parameter.
val c = Calendar.getInstance()

Related

Update textfields to CoreData without destroying unchanged data

When I change any textfield on my update form with new information ONLY that change is saved. All other previously saved data for the entity is lost in the process.
func updateDog (
id: String,
dogName: String,
activeStatus: Int16,
breed: String,
//etc (about 30 attributes below here )
)
{
let fetchDog: NSFetchRequest<Dog> = Dog.fetchRequest()
fetchDog.predicate = NSPredicate(format: "id == %#", id)
do {
let dog = try self.moc.fetch(fetchDog).first
dog?.dogName = dogName
dog?.activeStatus = activeStatus
dog?.breed = breed
//etc
if self.fetchDog(dogName: dogName)?.hasChanges ?? true {
try self.moc.save()
}
} catch
let error as NSError {
print(error)
}
There are no errors messages, but any attributes already stored, which are left unchanged during the updating are lost in the self.moc.save process. Only the edited fields are updated.
I want it to ignore any attribute that has not been altered and simply update the changed data. I've been going around in circles but cannot achieve the correct behaviour. I am not very experienced as have only been learning to code for a few months, and my advancing years probably add to my struggles to grasp the problem I'm having. Any help is gratefully recieved

Security - The view and edit id is visible in the address bar

CakePHP Version 3.5.5
The id is visible in the address bar for view and edit which for my application creates a security risk. Any logged in user at the same company can change the id in the address bar and view or edit the details
of users they are not allowed to.
IE: https://localhost/crm/users/edit/1378 can be manually changed in the address bar to https://localhost/crm/users/edit/1215 and entered. This would display the details of user 1215 which is not allowed.
To overcome this I am selecting the ids which the user is allowed to edit and checking that the id from the url is one of these ids with the following code:
public function view($id = null)
{
if ($this->request->is('get')) {
// Select the permitted ids.
if (superuser) { // example to explain only
$query = $this->Users->find()
->where(['companyid' => $cid])
->andWhere(['status' => 1])
->toArray();
}
elseif (manager) { // example to explain only
$query = $this->Users->find()
->where(['areaid' => $areaid])
->andWhere(['status' => 1])
->toArray();
}
elseif (team leader) { // example to explain only
$query = $this->Users->find()
->where(['teamid' => $teamid])
->andWhere(['status' => 1])
->toArray();
}
// Check if the edit id is in the array of permitted ids.
$ids = array_column($query, 'id');
$foundKey = array_search($id, $ids);
// If the edit id is not in the array of permitted ids redirect to blank.
if (empty($foundKey)) {
// Handle error.
}
$user = $this->Users->get($id);
$this->set('user', $user);
$this->set('_serialize', ['user']);
}
else {
// Handle error.
}
}
My question: Is the above code the best cake way of achieving this or is there a better way to do it?
This code does work but because it's to do with security I'd appreciate any input which would improve it or point out it's weakness/es.
/////////////////////////////////////////////////////////////////////////////
As requested by cgTag please see below.
My app has superusers, managers, team leaders and users.
Managers manage one area which can contain many teams.
Team Leaders lead one team and must belong to an area.
Users are assigned to an area or a team.
For example:
Area is UK
Team is England
Team is Scotland
Team is Wales
Area is USA
Team is Florida
Team is California
Team is Texas
On index - superusers see all the superusers, managers, team leaders and users in the company.
On index - managers see themself and users in their area, team leaders in their area and users in the teams.
On index - team leaders see themself and users in their team
My problem is say the manager of area UK clicks edit on one of the records and that record is displayed with a url of https://localhost/crm/users/edit/1378
Then say this disgruntled manager makes a guess and changes the url to https://localhost/crm/users/edit/1215 and submits it then this record is displayed. (This record could be anyone, a superuser, another manager, a team leader who is not in their area or a user not in their area.
This manager could then change say the email address and submit this and it's this type of situation that I need to protect against.
My fix is to reiterate the find for the superuser, manager and team leader I've done on index in the view and edit class. This ensures that say a manager can only view or edit someone in their area.
Hopefully I've explained it well enough but if not just let me know and I'll have another go.
Thanks. Z.
/////////////////////////////////////////////////////////////////////////////
Thanks cgTag, I feel a lot more confident with this approach but I cannot use this code because you have correctly assumed that I am using an id to select all the companies results but I'm using a 40 char string. I do this so I can make my sql queries more robust.
It's impossible for you to help me unless you have all the info required so I have posted an accurate representation below:
public function view($id = null)
{
if(!$this->request->is('get') || !$id) {
//throw new ForbiddenException();
echo 'in request is NOT get or id NOT set ' . '<hr />';
}
$user_id = $this->Auth->user('id');
// regular users can never view other users.
if($user_id !== $id) {
//throw new ForbiddenException();
echo 'in $user_id !== $id ' . '<hr />';
}
// Declare client id 1.
if ($this->cid1() === false) {
echo 'in throw exception ' . '<hr />';
}
else {
$c1 = null;
$c1 = $this->cid1();
}
$company_ids = $this->getCompanyIds($c1);
$area_ids = $this->getAreaIds($user_id, $c1);
$team_ids = $this->getTeamIds($user_id, $c1);
// company_id does not exist which will cause an unknown column error.
// The column I select by is cid_1 so I have changed this column to cid_1 as shown below.
$user = $this->Users->find()
->where([
'id' => $id,
'cid_1 IN' => $company_ids,
'area_id IN' => $area_ids,
'team_id IN' => $team_ids,
'status' => 1
])
->firstOrFail();
$this->set(compact('user'));
}
The functions:
public function cid1()
{
$session = $this->request->session();
if ($session->check('Cid.one')) {
$c1 = null;
$c1 = $session->read('Cid.one');
if (!is_string($c1) || is_numeric($c1) || (strlen($c1) !== 40)) {
return false;
}
return $c1;
}
return false;
}
public function getCompanyIds($c1 = null)
{
$query = $this->Users->find()
->where(['status' => 1])
->andWhere(['cid_1' => $c1]);
return $query;
}
public function getAreaIds($c1 = null, $user_id = null)
{
$query = $this->Users->find()
->where(['status' => 1])
->andWhere(['cid_1' => $c1])
->andWhere(['area_id' => $user_id]);
return $query;
}
public function getTeamIds($c1 = null, $user_id = null)
{
$query = $this->Users->find()
->where(['status' => 1])
->andWhere(['cid_1' => $c1])
->andWhere(['team_id' => $user_id]);
return $query;
}
With this code I get the following error:
Error: SQLSTATE[21000]: Cardinality violation: 1241 Operand should contain 1 column(s)
I don't know if your example will work with this new information but at least you have all the information now.
If it can be ammended great but if not I really don't mind. And I do appreciate the time you've put aside to try to help.
Thanks Z
/////////////////////////////////////////////////////////////////////////////
#tarikul05 - Thanks for the input.
Your suggestion is very similar to my first effort at addressing this security issue but I went for security through obscurity and hid the id in a 80 char string, example below.
// In a cell
public function display($id = null)
{
// Encrypt the id to pass with view and edit links.
$idArray = str_split($id);
foreach($idArray as $arrkey => $arrVal) {
$id0 = "$idArray[0]";
$id1 = "$idArray[1]";
$id2 = "$idArray[2]";
$id3 = "$idArray[3]";
}
// Generate string for the id to be obscured in.
$enc1 = null;
$enc1 = sha1(uniqid(mt_rand(), true));
$enc2 = null;
$enc2 = sha1(uniqid(mt_rand(), true));
$encIdStr = $enc1 . $enc2;
// Split the string.
$encIdArray = null;
$encIdArray = str_split($encIdStr);
// Generate the coded sequence.
$codedSequence = null;
$codedSequence = array(9 => "$id0", 23 => "$id1", 54 => "$id2", 76 => "$id3");
// Replace the id in the random string.
$idTemp = null;
$idTemp = array_replace($encIdArray, $codedSequence);
// Implode the array.
$encryptedId = null;
$encryptedId = implode("",$idTemp);
// Send the encrypted id to the view.
$this->set('encryptedId', $encryptedId);
}
And then decrypted with
// In function in the app controller
public function decryptTheId($encryptedId = null)
{
$idArray = str_split($encryptedId);
foreach($idArray as $arrkey => $arrVal) {
$id0 = "$idArray[9]";
$id1 = "$idArray[23]";
$id2 = "$idArray[54]";
$id3 = "$idArray[76]";
}
$id = null;
$id = $id0.$id1.$id2.$id3;
return $id;
}
The problem with this was that when testing I managed to get the script to error which revealed the array positions which would of undermined the security by obscurity principle and made it a lot easier for a hacker.
Your suggestion is neater than my obscurity method but I believe md5 has been cracked therefore it should not be used.
I'm no security expert but in my opinion checking the view and edit id against an array of permitted ids is the most secure way to address this.
Maybe I'm wrong but if I do it this way there's is no way a hacker no matter what they try in the address bar can see or edit data they are not meant to and it keeps the url cleaner.
What I was originally looking/hoping for was a Cake method/function which addressed this but I couldn't find anything in the cookbook.
Thanks anyway. Z.
I would simplify your code so that the SQL that fetches the user record only finds that record if the current user has permissions. When you're dependent upon associated data for those conditions. Follow this approach even if you have to use joins.
You create the SQL conditions and then call firstOrFail() on the query. This throws a NotFoundException if there is no match for the record.
public function view($id = null) {
if(!$this->request->is('get') || !$id) {
throw new ForbiddenException();
}
$user_id = $this->Auth->user('id');
// regular users can never view other users.
if($user_id !== $id) {
throw new ForbiddenException();
}
$company_ids = $this->getCompanyIds($user_id);
$area_ids = $this->getAreaIds($user_id);
$team_ids = $this->getTeamIds($user_id);
$user = $this->Users->find()
->where([
'id' => $id
'company_id IN' => $company_ids,
'area_id IN' => $area_ids,
'team_id IN' => $team_ids,
'status' => 1
])
->firstOrFail();
$this->set(compact('user'));
}
The above logic should be sound when a user belongsTo a hierarchical structure of data. Where by, they can view many users but only if those users belong to one of the upper associations they have access too.
It works because of the IN clause of the where conditions.
Note: The IN operator throws an error if the array is empty. When you have users who can see all "teams" just exclude that where condition instead of using an empty array.
The key here is to have functions which return an array of allowed parent associations such as; getCompanyIds($user_id) would return just the company IDs the current user is allowed access too.
I think if you implement it this way then the logic is easy to understand, the security is solid and a simple firstOrFail() prevents access.

Updating time and date in wit-ai weather example

I am trying to extend the wit-ai weather example by adding wit/datetime to the mix.
For example a user might type "How cold will it be in Berlin in 1 hour?" and the weather bot will bring back the data for the weather in 1 hour in Berlin.
So far this works, but when I try to setup missingDate in order to ask the date if it's missing it behaves kind of funny.
A dialogue would be:
- How cold will it be in Berlin?
- In what time?
- In 1 hour.
Instead, after the 1 hour step, I get asked again for the location which is in the context, but instead is triggered again.
My action is named getForecast({context, entities}) and I have defined it as below:
actions:
[...],
getForecast({ context, entities }) {
console.log(`The current context is: ${JSON.stringify(context)}`);
console.log(`Wit extracted ${JSON.stringify(entities)}`);
// extract entity
var location = firstEntityValue(entities, "location");
var date = firstEntityValue(entities, "datetime");
// if the entity exists, do a remote weather call.
if (date) {
context.date = date;
delete context.missingDate;
} else {
context.missingDate = true;
delete context.date;
delete context.forecast;
}
if (location) {
context.forecast = '38 degrees';
context.location = location;
delete context.missingLocation;
} else {
context.missingLocation = true;
delete context.forecast;
}
// return the context object
return Promise.resolve(context);
}

Customer Action "Extend To Vendor"

Using the latest version of Acumatica 5 with the latest and greatest updates, I’m running into a Web API issue that I have not been able to solve. I have code to execute the “Extend To Vendor” action on the Customer screen. It seems to run fine and does not error out but it fails to create the vendor. It seems to me that when performing the same actions through the website interface, the issue is that I’m not sending the correct command to choose the “Yes” button on the popup Warning box “Please confirm if you want to update current Vendor settings with the Vendor Class defaults. Original settings will be perserved otherwise.” I could be totally off though and any help would be greatly appreciated.
Here is my code:
String customerId = "SomeCustomerId";
String vendorClass = “SomeVendorClass”;
AcumaticaApiWS.AR303000Content AR303000 = context.AR303000GetSchema();
AcumaticaApiWS.AP303000Content AP303000 = context.AP303000GetSchema();
context.AR303000Clear();
AR303000.Actions.ExtendToVendor.Commit = true;
AcumaticaApiWS.AR303000Content[] AR303000result = context.AR303000Submit
(
new AcumaticaApiWS.Command[]
{
new AcumaticaApiWS.Value { Value = customerId, LinkedCommand = AR303000.CustomerSummary.CustomerID },
AR303000.Actions.ExtendToVendor
}
);
AcumaticaApiWS.AP303000Content[] AP303000result = context.AP303000Submit
(
new AcumaticaApiWS.Command[]
{
new AcumaticaApiWS.Value { Value = vendorClass, LinkedCommand = AP303000.GeneralInfoFinancialSettings.VendorClass },
new AcumaticaApiWS.Value { Value = "YES", LinkedCommand = AP303000.GeneralInfoFinancialSettings.ServiceCommands.DialogAnswer, Commit = true },
AP303000.Actions.Save
}
);
Thanks!
You're almost there. This is not an easy scenario since it involves multiple screens and dialogs, two things which are not trivial to use. The issues in your code sample are:
The dialog answer has to be set before the value. In your case, you're setting the vendor class first. This is counter-intuitive but the system has to know it before the dialog is displayed
The dialog answer is "Yes", and not "YES". You can see this by using the web browser inspector window and looking at the button title. The text is displayed in uppercase due to CSS styling.
You need to set the dialog answer on the primary view of the form (AP303000.VendorSummary.ServiceCommands.DialogAnswer), where the dialog is being displayed. There's no way to know this without looking at the source code, but I believe this is generally the case with dialog boxes.
The different Commit = true settings are not necessary (but don't hurt in this case).
This is the code I used, and in my case it extends a customer to a vendor and changes the vendor class at the same time:
String customerId = "ACTIVESTAF";
String vendorClass = "DATACENTER";
AcumaticaApiWS.AR303000Content AR303000 = context.AR303000GetSchema();
AcumaticaApiWS.AP303000Content AP303000 = context.AP303000GetSchema();
context.AR303000Clear();
AcumaticaApiWS.AR303000Content[] AR303000result = context.AR303000Submit
(
new AcumaticaApiWS.Command[]
{
new AcumaticaApiWS.Value { Value = customerId, LinkedCommand = AR303000.CustomerSummary.CustomerID },
AR303000.Actions.ExtendToVendor
}
);
AcumaticaApiWS.AP303000Content[] AP303000result = context.AP303000Submit
(
new AcumaticaApiWS.Command[]
{
new AcumaticaApiWS.Value { Value = "Yes", LinkedCommand = AP303000.VendorSummary.ServiceCommands.DialogAnswer },
new AcumaticaApiWS.Value { Value = vendorClass, LinkedCommand = AP303000.GeneralInfoFinancialSettings.VendorClass },
AP303000.Actions.Save
}
);

How to specify different delays between slides in bxslider

Ran across the following problem in bxslider- how can you apply different delays between slides in the auto show?
I came up with the following solution which I will show here:
in the jquery.bxslider.js replace:
el.startAuto = function(preventControlUpdate){
// if an interval already exists, disregard call
if(slider.interval) return;
// create an interval
slider.interval = setInterval(function(){
slider.settings.autoDirection == 'next' ? el.goToNextSlide() : el.goToPrevSlide();
}, slider.settings.pause);
// if auto controls are displayed and preventControlUpdate is not true
if (slider.settings.autoControls && preventControlUpdate != true) updateAutoControls('stop');
}
With
/**EDITS: By CRB - techdude **/
el.startAuto = function(preventControlUpdate){
el.continueAuto();
}
el.continueAuto = function(){
//get how long the current slide should stay
var duration = slider.children.eq(parseInt(slider.active.index)).attr("duration");
if(duration == ""){
duration = slider.settings.pause;
} else {
duration = parseInt(duration);
}
console.log(duration);
// create a timeout
slider.timer = setTimeout(function(){
slider.settings.autoDirection == 'next' ? el.goToNextSlide() : el.goToPrevSlide();
el.continueAuto();
}, duration);
// if auto controls are displayed and preventControlUpdate is not true
if (slider.settings.autoControls && preventControlUpdate != true) updateAutoControls('stop');
}
//*End Edits*/
Then to change the duration of a slide, simply give its li tag a duration attribute like this:
where duration is the number of milliseconds for the slide to pause.
To set the default duration, simply use the pause: option in the settings:
$("element").bxSlider({
auto:true,
pause: 4000
};
Hope this helps. Maybe bx slider will even add it to a future version. :)
What are the you're using to pick this up? Any way you can put up a gist of it working?
Perhaps this will help clarify:
In principle, the way this works is I change the setInterval with a setTimeout so the interval can be changed each time.
The key to getting multiple elements to work on a page is to not use the slider.timer object, but probably to use the el.timer object so the line would read something like,
el.timer = setTimeout(function(){
slider.settings.autoDirection == 'next' ? el.goToNextSlide() : el.goToPrevSlide();
el.continueAuto();
}, duration);
Instead of
slider.timer = setTimeout(function(){
slider.settings.autoDirection == 'next' ? el.goToNextSlide() : el.goToPrevSlide();
el.continueAuto();
}, duration);
I haven't tested it with multiple sliders, but let me know if this works. That is the principle anyway. The only problem with this, however, is that I believe that you would need to modify the el.pause method to use the el.timer as well, otherwise the slideshow can't be paused. I think that was the reason I did it the way I did. However, it was a long time ago.

Resources