mirror of
https://github.com/hmalik144/Automation---ReedJobApplications.git
synced 2025-12-10 03:05:30 +00:00
Initial commit
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Project exclude paths
|
||||||
|
/target/
|
||||||
2
.idea/.gitignore
generated
vendored
Normal file
2
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/workspace.xml
|
||||||
13
.idea/compiler.xml
generated
Normal file
13
.idea/compiler.xml
generated
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CompilerConfiguration">
|
||||||
|
<annotationProcessing>
|
||||||
|
<profile name="Maven default annotation processors profile" enabled="true">
|
||||||
|
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||||
|
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||||
|
<outputRelativeToContentRoot value="true" />
|
||||||
|
<module name="JobApplications" />
|
||||||
|
</profile>
|
||||||
|
</annotationProcessing>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
14
.idea/misc.xml
generated
Normal file
14
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
|
<component name="MavenProjectsManager">
|
||||||
|
<option name="originalFiles">
|
||||||
|
<list>
|
||||||
|
<option value="$PROJECT_DIR$/pom.xml" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
2
JobApplications.iml
Normal file
2
JobApplications.iml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="JAVA_MODULE" version="4" />
|
||||||
136
pom.xml
Normal file
136
pom.xml
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>org.example</groupId>
|
||||||
|
<artifactId>JobApplications</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<kotlin.version>1.3.61</kotlin.version>
|
||||||
|
<maven.compiler.source>1.7</maven.compiler.source>
|
||||||
|
<maven.compiler.target>1.7</maven.compiler.target>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||||
|
<version>${kotlin.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-test</artifactId>
|
||||||
|
<version>${kotlin.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi</artifactId>
|
||||||
|
<version>4.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi-ooxml</artifactId>
|
||||||
|
<version>4.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.seleniumhq.selenium</groupId>
|
||||||
|
<artifactId>selenium-chrome-driver</artifactId>
|
||||||
|
<version>3.141.59</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.seleniumhq.selenium</groupId>
|
||||||
|
<artifactId>selenium-java</artifactId>
|
||||||
|
<version>3.141.59</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.tylerthrailkill.helpers</groupId>
|
||||||
|
<artifactId>pretty-print</artifactId>
|
||||||
|
<version>2.0.2</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.squareup.retrofit/retrofit -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.retrofit2</groupId>
|
||||||
|
<artifactId>retrofit</artifactId>
|
||||||
|
<version>2.6.0</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.retrofit2</groupId>
|
||||||
|
<artifactId>converter-gson</artifactId>
|
||||||
|
<version>2.6.0</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.json/json -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.json</groupId>
|
||||||
|
<artifactId>json</artifactId>
|
||||||
|
<version>20190722</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jetbrains.kotlinx</groupId>
|
||||||
|
<artifactId>kotlinx-coroutines-core</artifactId>
|
||||||
|
<version>1.3.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
|
||||||
|
<testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
|
||||||
|
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
|
<artifactId>kotlin-maven-plugin</artifactId>
|
||||||
|
<version>${kotlin.version}</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>compile</id>
|
||||||
|
<phase>compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>test-compile</id>
|
||||||
|
<phase>test-compile</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>test-compile</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<configuration>
|
||||||
|
<jvmTarget>1.8</jvmTarget>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<version>2.6</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>make-assembly</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals> <goal>single</goal> </goals>
|
||||||
|
<configuration>
|
||||||
|
<archive>
|
||||||
|
<manifest>
|
||||||
|
<mainClass>Main</mainClass>
|
||||||
|
</manifest>
|
||||||
|
</archive>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
||||||
16
src/main/java/JobObject.kt
Normal file
16
src/main/java/JobObject.kt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import java.util.*
|
||||||
|
|
||||||
|
data class JobObject(
|
||||||
|
var jobId: String? = null,
|
||||||
|
var website: String? = null,
|
||||||
|
var jobTitle: String? = null,
|
||||||
|
var location: String? = null,
|
||||||
|
var company: String? = null,
|
||||||
|
var url: String? = null,
|
||||||
|
var dateApplied : String? = null
|
||||||
|
){
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return super.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
142
src/main/java/LegacyCode.kt
Normal file
142
src/main/java/LegacyCode.kt
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
import Constants.Companion.REED_KEYWORDS
|
||||||
|
import Constants.Companion.REED_LOCATION
|
||||||
|
import Constants.Companion.REED_PASSWORD
|
||||||
|
import Constants.Companion.REED_USERNAME
|
||||||
|
import org.openqa.selenium.By
|
||||||
|
import org.openqa.selenium.WebElement
|
||||||
|
import org.openqa.selenium.chrome.ChromeDriver
|
||||||
|
import org.openqa.selenium.support.ui.ExpectedConditions
|
||||||
|
import org.openqa.selenium.support.ui.WebDriverWait
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
fun StartSearch(){
|
||||||
|
|
||||||
|
//Open Chrome
|
||||||
|
System.setProperty("webdriver.chrome.driver","C:\\Selenium\\selenium-java-3.141.59\\chromedriver_win32\\chromedriver.exe" )
|
||||||
|
val driver = ChromeDriver()
|
||||||
|
|
||||||
|
//open reed website login
|
||||||
|
driver.get("https://www.reed.co.uk/account/signin?returnUrl=%2F#&card=signin")
|
||||||
|
val wait = WebDriverWait(driver, 20)
|
||||||
|
|
||||||
|
//wait for page to load
|
||||||
|
val lastElementToLoad = driver.findElementById("signin-button")
|
||||||
|
wait.until(ExpectedConditions.elementToBeClickable(lastElementToLoad))
|
||||||
|
|
||||||
|
//insert credentials and sign in
|
||||||
|
driver.findElementByXPath("//*[@id=\"Credentials_Email\"]").sendKeys(REED_USERNAME)
|
||||||
|
driver.findElementByXPath("//*[@id=\"Credentials_Password\"]").sendKeys(REED_PASSWORD)
|
||||||
|
lastElementToLoad.click()
|
||||||
|
|
||||||
|
//wait for page to load
|
||||||
|
val jobSearchEditText = driver.findElementByXPath("//*[@id=\"keywords\"]")
|
||||||
|
wait.until(ExpectedConditions.elementToBeClickable(jobSearchEditText))
|
||||||
|
|
||||||
|
// //submit search
|
||||||
|
jobSearchEditText.sendKeys(REED_KEYWORDS)
|
||||||
|
driver.findElementByXPath("//*[@id=\"location\"]").sendKeys(REED_LOCATION)
|
||||||
|
driver.findElementByXPath("//*[@id=\"main-search\"]/div[1]/div[3]/button").click()
|
||||||
|
|
||||||
|
//todo: change to wait
|
||||||
|
Thread.sleep(1500)
|
||||||
|
|
||||||
|
val ad = driver.findElementByXPath("//*[@id=\"content\"]/div[1]/div[2]/h1")
|
||||||
|
wait.until(ExpectedConditions.elementToBeClickable(ad))
|
||||||
|
|
||||||
|
//find number of pages
|
||||||
|
val text = driver.findElementByCssSelector("div.page-counter").text /* eg. 1 - 25 of 99 jobs */
|
||||||
|
print(text)
|
||||||
|
val count = text.toTotalCount()
|
||||||
|
val pages = count.getNumberOfPages()
|
||||||
|
|
||||||
|
//loop through pages of search
|
||||||
|
for (i in 1..pages){
|
||||||
|
|
||||||
|
//open page by number on search
|
||||||
|
//todo: change this url builder
|
||||||
|
driver.get("https://www.reed.co.uk/jobs/android-developer-jobs-in-kilburn-london?pageno=$i")
|
||||||
|
Thread.sleep(2500)
|
||||||
|
|
||||||
|
//elements list of jobs on page
|
||||||
|
val list = driver.findElementsByCssSelector("div.col-sm-12.col-md-9.col-lg-10.details")
|
||||||
|
|
||||||
|
//turn list into global list job object
|
||||||
|
list.forEach {
|
||||||
|
val badge = it.findElement(By.cssSelector("div.badge-container"))
|
||||||
|
//check if there is a badge element
|
||||||
|
if (badge.isDisplayed){
|
||||||
|
//see if applied is in badge
|
||||||
|
val applied = badge.findElements(By.cssSelector("span.label.label-applied"))
|
||||||
|
//if applied doesnt exist then add to global list of jobs
|
||||||
|
if (applied.isNullOrEmpty()){
|
||||||
|
val jobObject = it.toJobObject()
|
||||||
|
jobsList.add(jobObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
//no badge exists so add to list of jobs declared at the top
|
||||||
|
val jobObject = it.toJobObject()
|
||||||
|
jobsList.add(jobObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//loop through the jobs collected
|
||||||
|
jobsList.forEach{
|
||||||
|
//open the URl
|
||||||
|
driver.get(it.url)
|
||||||
|
|
||||||
|
val title = driver.findElementByXPath("//*[@id=\"content\"]/div/div[2]/article")
|
||||||
|
wait.until(ExpectedConditions.elementToBeClickable(title))
|
||||||
|
|
||||||
|
//check for external apply element
|
||||||
|
val applyExternal = driver.findElementsByCssSelector("span.external-app-caption")
|
||||||
|
|
||||||
|
//if external apply is empty then apply for job
|
||||||
|
if (applyExternal.isNullOrEmpty()){
|
||||||
|
|
||||||
|
print(it.jobTitle + " ${it.url} \n" )
|
||||||
|
|
||||||
|
|
||||||
|
//find apply button
|
||||||
|
val applyNow = driver.findElementsByXPath("//*[@id=\"applyButtonSide\"]")
|
||||||
|
|
||||||
|
if (!applyNow.isNullOrEmpty()){
|
||||||
|
|
||||||
|
//click apply
|
||||||
|
applyNow[1].click()
|
||||||
|
|
||||||
|
try{
|
||||||
|
val successfulApplied = driver.findElementByXPath("//*[@id=\"content\"]/div/div[1]/a")
|
||||||
|
wait.until(ExpectedConditions.visibilityOf(successfulApplied))
|
||||||
|
}catch (e: Exception){
|
||||||
|
println(it.jobId + " did not apply")
|
||||||
|
println("\n" + e.toString() + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.toTotalCount() : Int = this.substringAfter("of ").substringBefore( " jobs").toInt()
|
||||||
|
|
||||||
|
fun Int.getNumberOfPages():Int = if (this % 25 ==0){
|
||||||
|
this/25;
|
||||||
|
}else{
|
||||||
|
(this.toDouble()/25).roundToInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun WebElement.toJobObject():JobObject {
|
||||||
|
val attribute = this.findElement(By.tagName("a"))
|
||||||
|
|
||||||
|
val id = attribute.getAttribute("data-id")
|
||||||
|
val url = attribute.getAttribute("href")
|
||||||
|
val jobtitle = attribute.getAttribute("title")
|
||||||
|
|
||||||
|
val location = this.findElement(By.xpath("//*[@id=\"jobSection${id}\"]/div[1]/div[1]/ul[2]/li")).text
|
||||||
|
val company = this.findElement(By.xpath("//*[@id=\"jobSection${id}\"]/div[1]/header/div[2]/a")).text
|
||||||
|
|
||||||
|
return JobObject("reed-${id}","Reed.co.uk",jobtitle,location,company,url)
|
||||||
|
|
||||||
|
}
|
||||||
99
src/main/java/Main.kt
Normal file
99
src/main/java/Main.kt
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
import Constants.Companion.REED_PASSWORD
|
||||||
|
import Constants.Companion.REED_USERNAME
|
||||||
|
import api.network.NetworkRequests
|
||||||
|
import api.network.responses.ReedJobObject
|
||||||
|
import org.openqa.selenium.JavascriptExecutor
|
||||||
|
import org.openqa.selenium.chrome.ChromeDriver
|
||||||
|
import org.openqa.selenium.support.ui.ExpectedConditions
|
||||||
|
import org.openqa.selenium.support.ui.WebDriverWait
|
||||||
|
|
||||||
|
|
||||||
|
var jobsList = mutableListOf<JobObject>()
|
||||||
|
var reedJobsList = listOf<ReedJobObject>()
|
||||||
|
lateinit var driver: ChromeDriver
|
||||||
|
lateinit var wait: WebDriverWait
|
||||||
|
|
||||||
|
public fun main(args: Array<String>){
|
||||||
|
setup()
|
||||||
|
setupWebDriver()
|
||||||
|
logonToReed()
|
||||||
|
applyForJobsThroughLoop()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setup(){
|
||||||
|
val result = NetworkRequests().getSearchApi()
|
||||||
|
|
||||||
|
if (!result.isNullOrEmpty()){
|
||||||
|
reedJobsList = result
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setupWebDriver(){
|
||||||
|
//Open Chrome
|
||||||
|
System.setProperty("webdriver.chrome.driver","C:\\Selenium\\selenium-java-3.141.59\\chromedriver_win32\\chromedriver.exe" )
|
||||||
|
driver = ChromeDriver()
|
||||||
|
wait = WebDriverWait(driver, 20)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun applyForJobsThroughLoop(){
|
||||||
|
|
||||||
|
reedJobsList.forEach {
|
||||||
|
try {
|
||||||
|
driver.get(it.jobUrl)
|
||||||
|
applyForJob(it)
|
||||||
|
|
||||||
|
}catch (e: Exception){
|
||||||
|
println("\n" + e.toString() + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logonToReed(){
|
||||||
|
driver.get("https://www.reed.co.uk/account/signin?returnUrl=%2F#&card=signin")
|
||||||
|
|
||||||
|
//wait for page to load
|
||||||
|
val lastElementToLoad = driver.findElementById("signin-button")
|
||||||
|
wait.until(ExpectedConditions.elementToBeClickable(lastElementToLoad))
|
||||||
|
|
||||||
|
//insert credentials and sign in
|
||||||
|
driver.findElementByXPath("//*[@id=\"Credentials_Email\"]").sendKeys(REED_USERNAME)
|
||||||
|
driver.findElementByXPath("//*[@id=\"Credentials_Password\"]").sendKeys(REED_PASSWORD)
|
||||||
|
lastElementToLoad.click()
|
||||||
|
|
||||||
|
//wait for page to load
|
||||||
|
val jobSearchEditText = driver.findElementByXPath("//*[@id=\"keywords\"]")
|
||||||
|
wait.until(ExpectedConditions.elementToBeClickable(jobSearchEditText))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun applyForJob(jobObject: ReedJobObject){
|
||||||
|
val appliedBefore = driver.findElementsByXPath("//*[@id=\"content\"]/div/div[2]/article/div/div[1]/div")
|
||||||
|
|
||||||
|
if (appliedBefore.isNullOrEmpty()){
|
||||||
|
println("${jobObject.jobId} has not been applied")
|
||||||
|
//find apply button
|
||||||
|
val applyNow = driver.findElementsByXPath("//*[@id=\"applyButtonSide\"]")
|
||||||
|
|
||||||
|
if (!applyNow.isNullOrEmpty()){
|
||||||
|
//click apply
|
||||||
|
val index = if (applyNow.size > 1){ 1 }else{ 0 }
|
||||||
|
applyNow[index].click()
|
||||||
|
|
||||||
|
try{
|
||||||
|
// val successfulApplied = driver.findElementByCssSelector("div.alert.alert-success alert-borderless")
|
||||||
|
wait.until{
|
||||||
|
driver.executeScript("return document.readyState") == "complete"
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch (e: Exception){
|
||||||
|
println("\n" + e.toString() + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
println("${jobObject.jobId} has been applied")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
23
src/main/java/api/network/BasicInterceptor.kt
Normal file
23
src/main/java/api/network/BasicInterceptor.kt
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
package api.network
|
||||||
|
|
||||||
|
import Constants.Companion.REED_API_KEY
|
||||||
|
import okhttp3.Credentials
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Response
|
||||||
|
|
||||||
|
class BasicInterceptor() : Interceptor{
|
||||||
|
|
||||||
|
private val credentials = Credentials.basic(REED_API_KEY,"")
|
||||||
|
|
||||||
|
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
val request = chain.request();
|
||||||
|
val builder = request.newBuilder().header(
|
||||||
|
"Authorization", credentials
|
||||||
|
).build()
|
||||||
|
|
||||||
|
return chain.proceed(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
31
src/main/java/api/network/NetworkRequests.kt
Normal file
31
src/main/java/api/network/NetworkRequests.kt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package api.network
|
||||||
|
|
||||||
|
import Constants.Companion.REED_KEYWORDS
|
||||||
|
import Constants.Companion.REED_LOCATION
|
||||||
|
import Constants.Companion.REED_MINIMUM_SALARY
|
||||||
|
import api.network.responses.ReedJobObject
|
||||||
|
import com.example.h_mal.androiddevelopertechtest_incrowdsports.data.network.ReedApi
|
||||||
|
import com.example.h_mal.androiddevelopertechtest_incrowdsports.data.network.SafeApiRequest
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
|
||||||
|
class NetworkRequests : SafeApiRequest(){
|
||||||
|
|
||||||
|
val reedApi = ReedApi()
|
||||||
|
|
||||||
|
fun getSearchApi() : List<ReedJobObject>?{
|
||||||
|
try {
|
||||||
|
val response = runBlocking { apiRequest { reedApi.getGameData(REED_KEYWORDS, REED_LOCATION, REED_MINIMUM_SALARY) } }
|
||||||
|
|
||||||
|
response.results?.let {
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch (e : Exception){
|
||||||
|
println("*** $e")
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/main/java/api/network/ReedApi.kt
Normal file
41
src/main/java/api/network/ReedApi.kt
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package com.example.h_mal.androiddevelopertechtest_incrowdsports.data.network
|
||||||
|
|
||||||
|
import ReedResponse
|
||||||
|
import api.network.BasicInterceptor
|
||||||
|
import api.network.responses.ReedJobObject
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import retrofit2.Response
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Path
|
||||||
|
import retrofit2.http.Query
|
||||||
|
|
||||||
|
|
||||||
|
interface ReedApi {
|
||||||
|
|
||||||
|
//get the game data from api call of relevent gameID
|
||||||
|
@GET("search")
|
||||||
|
suspend fun getGameData(@Query("keywords") keywords: String,
|
||||||
|
@Query("locationName") locationName: String,
|
||||||
|
@Query("minimumSalary") minimumSalary: String) : Response<ReedResponse>
|
||||||
|
|
||||||
|
//instantiate api class
|
||||||
|
companion object{
|
||||||
|
operator fun invoke() : ReedApi{
|
||||||
|
val okkHttpclient = OkHttpClient.Builder()
|
||||||
|
.addNetworkInterceptor(BasicInterceptor())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
//return api class ss retrofit client
|
||||||
|
return Retrofit.Builder()
|
||||||
|
.client(okkHttpclient)
|
||||||
|
.baseUrl("https://www.reed.co.uk/api/1.0/")
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.build()
|
||||||
|
.create(ReedApi::class.java)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
35
src/main/java/api/network/SafeApiRequest.kt
Normal file
35
src/main/java/api/network/SafeApiRequest.kt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package com.example.h_mal.androiddevelopertechtest_incrowdsports.data.network
|
||||||
|
|
||||||
|
import org.json.JSONException
|
||||||
|
import org.json.JSONObject
|
||||||
|
import retrofit2.Response
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
abstract class SafeApiRequest {
|
||||||
|
|
||||||
|
//abstract function to unwrap body from response of api call
|
||||||
|
suspend fun<T: Any> apiRequest(call: suspend () -> Response<T>) : T{
|
||||||
|
//get the reponse
|
||||||
|
val response = call.invoke()
|
||||||
|
if(response.isSuccessful){
|
||||||
|
//response is successful so return the body
|
||||||
|
return response.body()!!
|
||||||
|
}else{
|
||||||
|
//the response failed so throw an error
|
||||||
|
|
||||||
|
val error = response.errorBody()?.string()
|
||||||
|
|
||||||
|
val message = StringBuilder()
|
||||||
|
error?.let{
|
||||||
|
try{
|
||||||
|
message.append(JSONObject(it).getString("message"))
|
||||||
|
}catch(e: JSONException){ }
|
||||||
|
message.append("\n")
|
||||||
|
}
|
||||||
|
message.append("Error Code: ${response.code()}")
|
||||||
|
|
||||||
|
throw IOException(message.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
17
src/main/java/api/network/responses/ReedJobObject.kt
Normal file
17
src/main/java/api/network/responses/ReedJobObject.kt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package api.network.responses
|
||||||
|
data class ReedJobObject(
|
||||||
|
val date: String?,
|
||||||
|
val employerProfileId: String?,
|
||||||
|
val locationName: String?,
|
||||||
|
val maximumSalary: String?,
|
||||||
|
val jobTitle: String?,
|
||||||
|
val employerName: String?,
|
||||||
|
val employerProfileName: String?,
|
||||||
|
val jobId: Int?,
|
||||||
|
val employerId: String?,
|
||||||
|
val minimumSalary: String?,
|
||||||
|
val jobUrl: String?,
|
||||||
|
val jobDescription: String?,
|
||||||
|
val expirationDate: String?,
|
||||||
|
val applications: Int?
|
||||||
|
)
|
||||||
8
src/main/java/api/network/responses/ReedResponse.kt
Normal file
8
src/main/java/api/network/responses/ReedResponse.kt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
import api.network.responses.ReedJobObject
|
||||||
|
|
||||||
|
data class ReedResponse (
|
||||||
|
val results : List<ReedJobObject>?,
|
||||||
|
val totalResults : Int?
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user