Problem Description: Oracle JET allows us to create SinglePage application (SPA). It changes url when we navigate between pages. What if application is secured application and pages require login to visit. In such case if we book mark a page and later try to launch it, application should verify if user is already logged in, If not redirect user to login page and once logged in user should be shown same page, which he has requested. In this blog we are trying to achieve it.
Also if user has directly started from login page then if login is successful we need to take him to default page mentioned in router configuration.
Solution:
To implement this we need to achieve following flow
Here are the steps to achieve above flow
1. User can either launch login page or a secured page (say Page-X). If user launches login page, we can directly show him login page, but if he launches Page-X, we need to verify if user is already logged in.To verify if user has already logged in depends on server side logic.
Also if user has directly started from login page then if login is successful we need to take him to default page mentioned in router configuration.
Solution:
To implement this we need to achieve following flow
Here are the steps to achieve above flow
1. User can either launch login page or a secured page (say Page-X). If user launches login page, we can directly show him login page, but if he launches Page-X, we need to verify if user is already logged in.To verify if user has already logged in depends on server side logic.
Here in this blog I assume there is a REST service available, which returns profile of logged in user (myprofile service). we will call this service, without passing any Authorization header. In such case browser will pass SESSIONID from cookie if user is already logged in. If not logged in then we will get 401 from server. If we get error from server, we can redirect user to login page, but we will add current url in login page url additionally, so that we can use it later to redirect user back to Page-X. Here is the common code checkIfLoginDone function written in appcontroller.js
function ControllerViewModel() {
$.ajaxSetup({
xhrFields: {
withCredentials: true
}
});
var self = this;
self.baseURL='http://localhost:7101';
self.serviceContextRoot = '/myapp';
self.serviceInitialURL = self.baseURL + self.serviceContextRoot + '/resources';
self.router = oj.Router.rootInstance;
self.checkIfLoginDone = function checkIfLoginDone(){
console.log('starting login check');
var promise = $.ajax({
type: "GET",
url: self.serviceInitialURL+ "/v1/myprofile",
contentType: "application/json; charset=utf-8",
crossDomain: true,
dataType: "json"});
promise.then(function(response) {
}, function(error) {
// error handler
var currenturl = window.location.pathname + window.location.search ;
window.location.href = '/?root=login&origurl='+currenturl;
});
return promise;
}
In above code if we get error from server, we will be redirecting user to login page and add url of secured page as a parameter origurl. Login page url will appear like
http://<host>:<port>/?root=login&origurl=<url-path-of-secured-page>
[Assuming that login will be router state for login page]
2. To perform login check we can it checkIfLoginDone from all secured pages's ViewModel as
define(['ojs/ojcore', 'knockout', 'jquery', 'appController'],
function(oj, ko, $, app) {
self.handleActivated = function(info) {
// Implement if needed
return app.checkIfLoginDone();
};
3. Create a login page: For this you can follow below steps
a. Create login.html in js/views directory. Content could be
<div class="oj-hybrid-padding">
<h1>Login Content Area</h1>
<div id="sampleDemo" style="" class="demo-container">
<div id="componentDemoContent" style="width: 1px; min-width: 100%;">
<div id="form-container" class="oj-form-layout">
<div class="oj-form">
<div class="oj-flex">
<div class="oj-flex-item">
<oj-label show-required for="username">User Name</oj-label>
<oj-input-text id="username" required value="{{username}}"></oj-input-text>
</div>
</div>
<div class="oj-flex">
<div class="oj-flex-item">
<oj-label for="password" show-required>Passward</oj-label>
<oj-input-password id="password" required value="{{password}}"></oj-input-password>
</div>
</div>
</div>
<oj-button id='submit' on-click='[[doLogin]]'>Login</oj-button>
</div>
</div>
</div>
</div>
In above page, we have created two fields username/password and a button Login.
Username and password are bound to ViewModel and Login button click calls doLogin method of ViewModel
b. Create login.js as a ViewModel in js/viewModels directory. Its code would be
define(['ojs/ojcore', 'knockout', 'jquery', 'appController','ojs/ojknockout','ojs/ojlabel','ojs/ojinputtext', 'ojs/ojcheckboxset'],
function(oj, ko, $, app) {
function LoginViewModel() {
var self = this;
function param(name) {
return (location.search.split(name + '=')[1] || '').split('&')[0];
}
self.username = ko.observable("");
self.password = ko.observable("");
self.doLogin = function doLogin(event){
$("body").css("cursor", "wait");
//do server login here
var string = self.username() + ':' + self.password();
var encodedString = 'Basic ' + btoa(string);
var promise = $.ajax({
type: "POST",
url: app.serviceInitialURL + '/v1/auth/login',
contentType: "application/json; charset=utf-8",
headers: {
"Content-Type": "text/plain",
"Authorization": encodedString
},
crossDomain: true,
dataType: "json"});
promise.then(function(response){
var origurl = param('origurl');
if(origurl){
window.location.href = origurl;
}
else{
oj.Router.rootInstance.go('dashboard');
}
$("body").css("cursor", "default");
}, function(response){
//write logic here to show error message to end user.
}) ;
}
// Header Config
self.headerConfig = {'viewName': 'header', 'viewModelFactory': app.getHeaderModel()};
return new LoginViewModel();
}
);
Important piece of above code is
i. username/password created as ko observable.
ii. username password is used to create base 64 encoded authorization string
iii. server side login using $.ajax POST request
iv. If login is success then verify if there is any url parameter as origurl present. Navigate to the location whereever origurl points to. If not specified then get default page from router and navigate there.
c. register login page in router configuration
self.router.configure({
'login': {label: 'Login'},
'dashboard': {label: 'Dashboard', isDefault: true},
'incidents': {label: 'Incidents'},
'customers': {label: 'Customers'},
'profile': {label: 'Profile'},
'about': {label: 'About'}
});
4. Finally we need a logout button. We can keep it in header.html
<div class="oj-flex-bar-end">
<oj-button id='button1' on-click="[[logout]]">Logout</oj-button>
</div>
logout implementation is written in appcontroller.js by changing getHeaderModel method.
self.logout = function(event){
$.ajax({
type: "GET",
url: self.serviceInitialURL+ "/v1/auth/logout",
contentType: "application/json; charset=utf-8",
crossDomain: true,
dataType: "json",
success: function (data, status, jqXHR) {
oj.Router.rootInstance.go('login');
},
error: function (jqXHR, status) {
// error handler
}
});
}
self.getHeaderModel = function() {
var headerFactory = {
createViewModel: function(params, valueAccessor) {
var model = {
pageTitle: self.router.currentState().label,
handleBindingsApplied: function(info) {
// Adjust content padding after header bindings have been applied
self.adjustContentPadding();
},
toggleDrawer: self.toggleDrawer,
logout: self.logout
};
return Promise.resolve(model);
}
}
return headerFactory;
}
Above logout method calls server side logout and then redirect user to login page.
a. Create login.html in js/views directory. Content could be
<div class="oj-hybrid-padding">
<h1>Login Content Area</h1>
<div id="sampleDemo" style="" class="demo-container">
<div id="componentDemoContent" style="width: 1px; min-width: 100%;">
<div id="form-container" class="oj-form-layout">
<div class="oj-form">
<div class="oj-flex">
<div class="oj-flex-item">
<oj-label show-required for="username">User Name</oj-label>
<oj-input-text id="username" required value="{{username}}"></oj-input-text>
</div>
</div>
<div class="oj-flex">
<div class="oj-flex-item">
<oj-label for="password" show-required>Passward</oj-label>
<oj-input-password id="password" required value="{{password}}"></oj-input-password>
</div>
</div>
</div>
<oj-button id='submit' on-click='[[doLogin]]'>Login</oj-button>
</div>
</div>
</div>
</div>
In above page, we have created two fields username/password and a button Login.
Username and password are bound to ViewModel and Login button click calls doLogin method of ViewModel
b. Create login.js as a ViewModel in js/viewModels directory. Its code would be
define(['ojs/ojcore', 'knockout', 'jquery', 'appController','ojs/ojknockout','ojs/ojlabel','ojs/ojinputtext', 'ojs/ojcheckboxset'],
function(oj, ko, $, app) {
function LoginViewModel() {
var self = this;
function param(name) {
return (location.search.split(name + '=')[1] || '').split('&')[0];
}
self.username = ko.observable("");
self.password = ko.observable("");
self.doLogin = function doLogin(event){
$("body").css("cursor", "wait");
//do server login here
var string = self.username() + ':' + self.password();
var encodedString = 'Basic ' + btoa(string);
var promise = $.ajax({
type: "POST",
url: app.serviceInitialURL + '/v1/auth/login',
contentType: "application/json; charset=utf-8",
headers: {
"Content-Type": "text/plain",
"Authorization": encodedString
},
crossDomain: true,
dataType: "json"});
promise.then(function(response){
var origurl = param('origurl');
if(origurl){
window.location.href = origurl;
}
else{
oj.Router.rootInstance.go('dashboard');
}
$("body").css("cursor", "default");
}, function(response){
//write logic here to show error message to end user.
}) ;
}
// Header Config
self.headerConfig = {'viewName': 'header', 'viewModelFactory': app.getHeaderModel()};
return new LoginViewModel();
}
);
Important piece of above code is
i. username/password created as ko observable.
ii. username password is used to create base 64 encoded authorization string
iii. server side login using $.ajax POST request
iv. If login is success then verify if there is any url parameter as origurl present. Navigate to the location whereever origurl points to. If not specified then get default page from router and navigate there.
c. register login page in router configuration
self.router.configure({
'login': {label: 'Login'},
'dashboard': {label: 'Dashboard', isDefault: true},
'incidents': {label: 'Incidents'},
'customers': {label: 'Customers'},
'profile': {label: 'Profile'},
'about': {label: 'About'}
});
4. Finally we need a logout button. We can keep it in header.html
<div class="oj-flex-bar-end">
<oj-button id='button1' on-click="[[logout]]">Logout</oj-button>
</div>
logout implementation is written in appcontroller.js by changing getHeaderModel method.
self.logout = function(event){
$.ajax({
type: "GET",
url: self.serviceInitialURL+ "/v1/auth/logout",
contentType: "application/json; charset=utf-8",
crossDomain: true,
dataType: "json",
success: function (data, status, jqXHR) {
oj.Router.rootInstance.go('login');
},
error: function (jqXHR, status) {
// error handler
}
});
}
self.getHeaderModel = function() {
var headerFactory = {
createViewModel: function(params, valueAccessor) {
var model = {
pageTitle: self.router.currentState().label,
handleBindingsApplied: function(info) {
// Adjust content padding after header bindings have been applied
self.adjustContentPadding();
},
toggleDrawer: self.toggleDrawer,
logout: self.logout
};
return Promise.resolve(model);
}
}
return headerFactory;
}
Above logout method calls server side logout and then redirect user to login page.
101 comments:
Your online diaries propel more each else volume is so captivating further serviceable It chooses me happen for pull back repeat. I will in a blaze grab your reinforce to stay instructed of any updates. Best SMS Messages Online
Great Share. Thanks for this. I loved it.
Also, I created one website on Sofa Reviews. So if you want to purchase some sofa, or looking for new sofas, then here is the link to my website Checkout here for more information related to Sofas.
great code, if you want to run and record your screen while showing some tutorials you can try these best screen recording apps on your android phone now.
Nice post sir
Blog ko rank kaise karen fast || आपने ब्लॉग की traffic increase करे
This is very interesting, You’re a very skilled blogger. I have joined your feed and look forward to seeking more of your great post. Also, I have shared your web site in my social networks!
Tech Gifts and Gadgets
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Health Hint
Nice Post Keep It Up
Movies Trending Now
Movies Trending Now
Movies Trending Now
Movies Trending Now
Movies Trending Now
Movies Trending Now
Movies Trending Now
Challenges of Information Technology Management in the 21st century The growth of personal computing technology has revolutionized how people live and work in the 21st-century computer networks running at optimal levels falls on information technology managers, who must upgrade their skills.
https://www.windzr.com/blog/3-of-the-biggest-digital-infrastructure-challenges-for-2020
Hey, Thanks for this detailed article. It really helps me a lot. Searching for good pc monitor is really a touch task. I found one good articles over internet. You can check them out.
Benq GW2480 Review
Best frameless monitors
best csgo monitors
best gaming monitors
Thanks For this article. Also I found some guides related to PC monitors. Hope you check it out.
Best PC Gaming Monitors
Best Monitor For Overwatch
What Is IPS Monitors?
Best Monitor for macbook pro
Nice Article, thanks for this information
Also check this out
Laptops, Mobiles, Games, Tv, Smartwatches etc Daily Tech News Updates.
Great post.
http://www.escalade-alsace.com/forum/profile.php?mode=viewprofile&u=7685
software house in brentwood
Awesome...
I have learned about Voice based conversation and this is super easily explained. Appreciated. Now I am gonna read your next post :D
Hoping for more informative stuff like this.
Wiki Tech GO.
You can check this website.
Silveredge Casino a offers this unique opportunity to the players and members to play and have a first-hand experience of games by popular software companies that are yet to release on common platforms. So be the first one to play the game and be a part of a group of elite members.
Funclub Casino offers a wide assortment of effortless and deposit withdrawal options with the assurance that at all times we ensure strict security controls and their integrity.
Worldwide Tweets is your news, entertainment, music fashion website. We provide you with the latest breaking news and videos straight from the entertainment industry. Visit Houston maritime lawyers for more details.
hanks for sharing this article, very useful inforation u provided,best software development copany in india
ReactJS Development Services
I read your blog; its very useful and informative content.”best mails backup software”
Very informative, I really enjoyed reading it.
Top 10 Cheapest Technologies To Generate Power at Home
Dear Mr. Sanjeev,
Thank you so much for sharing such an amazing piece of information with us. Keep sharing your wonderful thoughts with us. Development
you have a lot of Oracle experience Thanks for This Solution
Software Product Development
this is awesome
dna-full-form
lamour-app-free-chat-review-real-or-fake
/top-5-affiliate-marketing-platform-in-india
bakra-eid-kab-hai
jio-call-details-history
namaz-in-hindi
HINDI SHAYARI
Thank You for this post. It's very helpfull. Can you share full source code of provided sample?
Thank you for sharing this great post!Asset management software
Thanks for updating us with useful information
If you are thinking to Download Dailymotion Videos for free in phone and computers.They will give you a entertaining feel and a beautiful appearance in a variety of this features.
Hey, Thanks for sharing such useful information about Technology. If you want to more information about technology, internet, & how to kindly
visit our website: - https://www.livewebdigital.com/
Really nice blog for the best web development company in Kanpur in India click on link to know more web development company in kanpur
amd radeon rx 6800 xt Phantom Gaming D 16G OC is accessible at GPU Mining Graphic Card Inc. has confidence in offering some benefit to its clients. amd radeon rx 6800 xt Our group of IT experts is at your support of guide you and give you most extreme worth.
gigabyte geforce gtx 1660 is accessible at GPU Mining Graphic Card Inc. puts stock in offering some incentive to its clients. Our group of IT experts is at your support of guide you and give you greatest worth. You can visit with us live or Contact Us to send inquiries gigabyte geforce gtx 1660
Rider Vapes conveys you an answer for your longings. In the event that you are hoping to stop smoking and move to a superior and maintainable alternative, we got you covered
vape shops in uae
amd Radeon RX 6800 xt Phantom Gaming D 16G OC is accessible at GPU Mining Graphic Card Inc. has confidence in offering some benefit to its clients. amd radeon rx 6800 xt Our group of IT experts is at your support to guide you and give you the greatest worth. You can talk with us live or Contact Us to send inquiries.
gigabyte radeon rx 5700 xt gaming oc is accessible at GPU Mining Graphic Card Inc. has confidence in offering some incentive to its clients. gigabyte radeon rx 5700 xt gaming oc Our group of IT experts is at your support of guide you and give you greatest worth. You can visit with us live or Contact Us to send questions.
I have read your blog. Its too much informative and want to know more about prismatic blogs . actually its really technology based site.
nice article
We give you customer care, all relentless, to change your dream into a reality. gigabyte radeon rx 5700 xt gaming oc Our gathering of IT specialists is at your help of guide you and give you most outrageous worth.
Premium Hash takes your experience of smoking hash to another level and gives you an energy you will not at any point have. Moroccan hash for sale As of now you approach the general quality hash things under one rooftop which refreshes your hash impacts, gives you premium experience, and makes smoking hash incredibly better.
Hemp CBD Sales centers around its packaging and approaches.Our things are carefully stuffed. weed Dispensary near me
Premium Hash takes your experience of smoking hash to another level and gives you a vibe you never had. Presently you approach the top-level quality hash items under one rooftop which upgrades your hash impacts hash
hemp flower
You can tap on our WhatsApp OR jivochat choice and mention to us what you need. Our prepared staff will direct you, make your purchasing cycle smooth, and contact you rapidly. Buy CBD Online
Getting the best CBD is extreme, yet Hemp CBD Sales has made it feasible for you. We realize you are a CBD aficionado, and in this manner, we serve you with the best.Buy Weed Online
Getting the best CBD is extreme, yet Hemp CBD Sales has made it feasible for you. We realize you are a CBD aficionado, and in this manner, we serve you with the best.
Buy Cbd flower Online
Hemp CBD Sales focuses on its bundling and treats it extremely in a serious way. We don't think twice about the nature of our items on any piece of the cycle, and subsequently, our items are painstakingly pressed. You may discover different Buy CBD Online available to be purchased, yet it's just Hemp CBD Sales who load your involvement in care and consideration.Buy CBD Online
we are offering best quality of gpu mining product and a good prices. msi radeon rx 580
The hash place of Premium Hash is an online hash offering support at the simplicity of your home with ensured security, moderate costs, and marvelous experience.hash products We give a stunning hash impact that you generally ached for
The hash place of Premium Hash is an online hash offering support at the simplicity of your home with ensured security, moderate costs, and amazing experience. black tar hash
According to bestschoolnews.com you can apply for
JAMB Result
JAMB Mock Result
N-Power Shortlisted
N-Power Recruitment for this year.
FRSC Shortlisted Candidates
Hemp deals CBD has prohibited natural product strain available to be purchased, Blue Cookie Price which will give you wings and extraordinary high. The new sweet lemony taste blended in with sweet berries, pine, and earth fragrance will make you insane and stick you to your seat.
I've read your article thoroughly and I really enjoyed reading your article. Also, you have explained the technical structure in very details, which I liked the most. If you want to get more details about Bot click the link given below. https://www.nimbleappgenie.com/blogs/challenges-of-chatbots-in-healthcare/
Nice blog, please keep such blogs..
Mobilestorefranchise
"Such a informative blog! Really appreciate it.
Our cloud-based collaboration solutions can help you improve end-user productivity and optimize operations costs. We have developed these solutions on m365 cloud services
and SharePoint services."
Hey, I saw your post and it is very informative - Tvidler Reviews
The procedure of ozone generation is straightforward. The air passes via an electrical charge and will become enriched in oxygen. portable ozone generator for hunting
Wherever you might locate yourself, if there is not an electrical outlet for miles, your pleasant option is to invest in a portable generator. portable generators for sale
What is the Industry-Leading Display Technology on the M42 5G? Hey guys, this is the First Question Of the Amazon Galaxy M42 5G Quiz Contest. In this article, we will share all the other 4 Question Answers of this Quiz along with this question. So check it out and participate in this Quiz Contest and get a chance to win Galaxy M42 5G smartphone.
Thanks for sharing informarmation. It is nice blog, and you have described every things properly. I feed glad to read your blog. keep It up. If you want to know more information about edge ai compute software, Once you can check in Kamivision.
Depending on how you use it, freedom of movement, reduced noise, independence, flexibility, excitement, and adventure are a few of the many things an inverter generator offers. best portable generator with inverter
your content is awesome and very informative i also have a website please visit and share your review to bharamrishi is very useful and good website
bharamrishi
Thank you so much for sharing this post, I appreciate your work. It was a great informative post. Go so many useful and informative links. Loved your writings also.
How can I automate my business with Exly
Thank you so much for sharing this post, I have read some of your stuff this past weekend . Personally, I loved your post. I appreciate your work. It was a great informative post. Your articles are useful and informative and links also. I feed glad to read your blog. keep It up.
If you want to know more information about Top 5 Online Business Ideas You Can Start Today Once you can check in
Thank you so much for sharing this post, I have read some of your stuff this past weekend . Personally, I loved your post. I appreciate your work. It was a great informative post. Your articles are useful and informative and links also. I feed glad to read your blog. keep It up.
If you want to know more information about Best Website builders Once you can check it.
Thank you so much for sharing this post, I have read some of your stuff this past weekend . Personally, I loved your post. I appreciate your work. It was a great informative post. Your articles are useful and informative and links also. I feed glad to read your blog. keep It up.
If you want to know more information about How to generate leads for business Once you can check it.
Thank you so much for sharing this post, I have read some of your stuff this past weekend . Personally, I loved your post. I appreciate your work. It was a great informative post. Your articles are useful and informative and links also. I feed glad to read your blog. keep It up.
If you want to know more information about How to Sell your Fitness Courses Online Once you can check it.
carbon sulphur determinator manufacturers
Thank you so much for sharing this post, I have read some of your stuff this past weekend . Personally, I loved your post. I appreciate your work. It was a great informative post. Your articles are useful and informative and links also. I feed glad to read your blog. keep It up.
If you want to know more information about
Top benefits of having an online business Once you can check it.
It takes more than scanning resumes and profiles to hire solidity developers. If you have no experience hiring Solidity Developers, then these resources can assist you and make the process much easier.
Thank you so much for sharing this post, I have read some of your stuff this past weekend . Personally, I loved your post. I appreciate your work. It was a great informative post. Your articles are useful and informative and links also. I feed glad to read your blog. keep It up.
If you want to know more information about
online consultancy business Once you can check it.
Hiring Solidity Developers is beyond just scanning candidates’ resumes and profiles. If you have absolutely no experience in hire solidity developers then these resources can help you out and make the process quite easy.
Hey, just I want to thank you that you are providing great information.
best cctv company in dubai
React agency can take your web & mobile app development vision to the next level of innovation with high-quality and cost-effective services!
react js agency
Dynode Software is India’s leading business management software for GST, accounting, inventory, banking, and payroll. Dynode Software is affordable and is one of the most popular business management software, used by nearly 20 lakhs businesses worldwide. Contact us for cloud based hospital management software in Patna.
very nice post: How To Create Comment Backlink
Amazing & informative blog on new technology
Thanks for sharing information.
Keep Blogging
Visit our website for smart lights, motion sensors, home automation devices. We are best sensor manufacturers in India
I really appreciate your blog, it is really helpful for all. Keep blogging to attract reader's attention
Visit our website for best student visa consultation service, We are leading UK Student Visa Consultant in Vadodara
Great blog. Thank you for sharing information
Keep Going on.
Visit our website for Best Offers on Apple Products, We are Authorized apple store Vadodara
nice post i like it
Online ERP software in India
Export ERP Software
I read your Blog It's very informative and has great content and its sharable
Ethical Hacking Course
Amazing article. It's very useful.
It looks like you have put lot of work into this.
SMARS designs jewelry to run along with your ever-changing wardrobe. A piece of Jewelry can either make or break your entire look; therefore, every unique outfit needs a different piece of jewelry to compliment it. But looking at the prices of traditional jewelry, we usually find occasions like festivals or ceremonies to buy it. And these adorable pieces spend most of their lives in the lockers. Komal, the founder of SMARS, understood this gap in the market. Every single piece is limited edition and walks hand-in-hand with trends. Adored by customers from all over the world, we ensure the quality delivery of our high-end, Indian fashion costume jewelry. Shop online for latest collection of Kundan, antique and temple jewelry in India check out necklace sets, earrings, bangles, chokers for girls and many more Indian jewelry sets for women available with free shipping across India.
Take a look: Buy Traditional Bangles Set For Girls Online
Why should you engage a seasoned ReactJS development team? Learn the answer to this question, as well as why it's critical to make a well-informed decision in order to have a positive development experience.
hire react developer
Get simple and easy troubleshooting guide to activate Roku device via Roku com link enter code.
tv.youtube.com/start/roku | Roku Com Link
Such a great postAutomatic Number Plate Recognition Software
One great thing about Boltwireless is that it has paired up with Koodo and Telus that can assist you in handling the difficulties of the global landscape and Canadian.
telus authorized dealer in canada
telus authorized dealer in canada
Thanks for sharing such an informative content. I would like to tell you about my blog and edit gif.
Great Post!
Shop online for latest collection of Kundan, antique and temple jewelry in India check out long necklaces for women , earrings, bangles, chokers for girls , rings, bracelets and many more Indian jewelry sets for women available with free shipping across India.
Take a look: Buy Bracelets For Girls Online
seo services
thanks for this blog. All screenshots can easily explain the whole blog. This is very easy to understand. This screenshot simplifies the details. delete duplicate photo
jvvhg
The best IELTS coaching in Chandigarh is offered by the British Institute. We have IDP-certified instructors with five years of IELTS teaching expertise. Contact us...
best ielts institute in chandigarh
Discover the fascinating website crafted by the talented Amelia Emma, and unlock a world of intrigue and excitement with just a click of a button!
Nice Technology.
CIREBON TV
IPTV
"I recently installed Windows 11 Pro, and the search for a reliable product key was a bit challenging. If anyone has successfully found a trustworthy source or has advice on obtaining aWindows 11 Pro Product Key, please share your insights here. Let's help each other out in ensuring a smooth and secure Windows 11 Pro experience!"
Amazing article to read. Are you looking for the best gas chromatography manufacturers in India.
Post a Comment