Skip to content

Commit

Permalink
Merge branch 'master' into gsr-notifs2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
rchhaya authored Oct 8, 2022
2 parents cc6f14a + accd02e commit a2e9b14
Show file tree
Hide file tree
Showing 41 changed files with 1,695 additions and 204 deletions.
14 changes: 7 additions & 7 deletions PennMobile/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.pennapps.labs.pennmobile"
android:versionCode="60"
android:versionName="2.0.0">
android:versionCode="62"
android:versionName="2.1.0">

<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
Expand Down Expand Up @@ -32,12 +32,12 @@
<meta-data
android:name="com.crashlytics.ApiKey"
android:value="18a765536e6539a73a15dd36c369ed29cfb91aa1" />
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts"
/>
<meta-data
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts"
/>

<receiver
<receiver
android:name=".LaundryBroadcastReceiver"
android:enabled="true"
android:exported="true" /> <!-- receiver for laundry -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ class AboutFragment : Fragment() {

view.our_team_rv?.layoutManager = GridLayoutManager(context, 3)
view.alumni_rv?.layoutManager = GridLayoutManager(context, 3)
val members = arrayListOf("Davies Lumumba", "Rohan Chhaya", "Vishesh Patel",
"Julius Snipes", "Belinda Xi", "Ansh Nagwekar", "Zhiyan Lu")
val members = arrayListOf("Rohan Chhaya", "Anna Jiang", "Julius Snipes",
"Zhiyan Lu", "Belinda Xi","Vishesh Patel", "Ali Krema", "Jenny Li", "Sruthi Kurada")
val alumni = arrayListOf("Marta García Ferreiro", "Varun Ramakrishnan", "Sahit Penmatcha",
"Anna Wang", "Sophia Ye", "Awad Irfan", "Liz Powell", "Anna Jiang")
"Anna Wang", "Sophia Ye", "Awad Irfan", "Liz Powell", "Davies Lumumba")
view.our_team_rv?.adapter = AboutAdapter(members)
view.alumni_rv?.adapter = AboutAdapter(alumni)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
package com.pennapps.labs.pennmobile

import android.content.SharedPreferences
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Button
import android.widget.LinearLayout
import android.widget.Toast
import androidx.fragment.app.FragmentTransaction
import androidx.preference.PreferenceManager
import com.pennapps.labs.pennmobile.api.CampusExpress
import com.pennapps.labs.pennmobile.classes.Account
import com.pennapps.labs.pennmobile.classes.CampusExpressAccessTokenResponse
import kotlinx.android.synthetic.main.fragment_login_webview.view.*
import org.apache.commons.lang3.RandomStringUtils
import retrofit.Callback
import retrofit.RetrofitError
import retrofit.client.Response
import java.security.MessageDigest
import java.util.*

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"

/**
* A simple [Fragment] subclass.
* Use the [CampusExpressLoginFragment.newInstance] factory method to
* create an instance of this fragment.
*/
class CampusExpressLoginFragment : Fragment() {
lateinit var webView: WebView
lateinit var headerLayout: LinearLayout
lateinit var cancelButton: Button
lateinit var user: Account
private var mCampusExpress: CampusExpress? = null
private lateinit var mActivity: MainActivity
lateinit var sp: SharedPreferences
lateinit var codeChallenge: String
lateinit var codeVerifier: String
lateinit var state: String
lateinit var campusExpressAuthUrl: String
lateinit var clientID: String
lateinit var redirectUri: String

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_campus_express_login, container, false)
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mCampusExpress = MainActivity.campusExpressInstance
mActivity = activity as MainActivity
sp = PreferenceManager.getDefaultSharedPreferences(mActivity)

// These values are added to the BuildConfig at runtime, to allow GitHub Actions
// to build the app without pushing the secrets to GitHub
clientID = "5c09c08b240a56d22f06b46789d0528a"
redirectUri = "https://pennlabs.org/pennmobile/android/campus_express_callback/"
codeVerifier = RandomStringUtils.randomAlphanumeric(64)
codeChallenge = getCodeChallenge(codeVerifier)
state = getStateString()
campusExpressAuthUrl = "https://prod.campusexpress.upenn.edu/api/v1/oauth/authorize"
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
webView = view.findViewById(R.id.webView)
headerLayout = view.linear_layout
cancelButton = view.findViewById(R.id.cancel_button)
val uri = Uri.parse(campusExpressAuthUrl)
.buildUpon()
.appendQueryParameter("response_type", "code")
.appendQueryParameter("client_id", clientID)
.appendQueryParameter("state", state)
.appendQueryParameter("scope", "read")
.appendQueryParameter("code_challenge", codeChallenge)
.appendQueryParameter("code_challenge_method", "S256")
.appendQueryParameter("redirect_uri", redirectUri)
.build()
webView.loadUrl(uri.toString())
val webSettings = webView.settings
webSettings.setJavaScriptEnabled(true)
webSettings.javaScriptCanOpenWindowsAutomatically = true;
webView.webViewClient = MyWebViewClient()

cancelButton.setOnClickListener {
parentFragmentManager.popBackStack()
}

}

inner class MyWebViewClient : WebViewClient() {

override fun onReceivedHttpError(view: WebView?, request: WebResourceRequest?, errorResponse: WebResourceResponse?) {
super.onReceivedHttpError(view, request, errorResponse)
view?.visibility = View.INVISIBLE
headerLayout.visibility = View.INVISIBLE
}

override fun shouldOverrideUrlLoading(view: WebView?, url: String): Boolean {
if (url.contains("callback") && url.contains("?code=")) {
val urlArr = url.split("?code=", "&state=").toTypedArray()
val authCode = urlArr[1]
val clientState = urlArr[2]
initiateAuthentication(authCode)
}
return super.shouldOverrideUrlLoading(view, url)
}
}

private fun goToDiningInsights(refresh: Boolean) {
if(refresh) {
val fragment = DiningInsightsFragment()
parentFragmentManager.beginTransaction()
.replace(R.id.campus_express_page, fragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.addToBackStack(null)
.commit()
} else {
parentFragmentManager.popBackStack()
}
}

private fun initiateAuthentication(authCode: String) {
mCampusExpress?.getAccessToken(authCode,
"authorization_code", clientID, redirectUri, codeVerifier,
object : Callback<CampusExpressAccessTokenResponse> {

override fun success(t: CampusExpressAccessTokenResponse?, response: Response?) {
if (response?.status == 200) {
val accessToken = t?.accessToken
val expiresIn = t?.expiresIn
val editor = sp.edit()
if (accessToken != null) {
editor.putString(mActivity.getString(R.string.campus_express_token),accessToken)
}
if (expiresIn != null) {
val currentDate = Date()
currentDate.time = currentDate.time + (expiresIn * 1000)
val expiresAt = currentDate.time
editor.putLong(mActivity.getString(R.string.campus_token_expires_in), expiresAt)
}
editor.apply()
goToDiningInsights(true)
}
}

override fun failure(error: RetrofitError) {
Log.e("Campus Webview", "Error fetching access token $error")
Toast.makeText(context, "Error getting campus express authorization", Toast.LENGTH_SHORT).show()
goToDiningInsights(false)
}
})
}

private fun getCodeChallenge(codeVerifier: String): String {

// Hash the code verifier
val md = MessageDigest.getInstance("SHA-256")
val byteArr = md.digest(codeVerifier.toByteArray())

// Base-64 encode
var codeChallenge = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Base64.getEncoder().encodeToString(byteArr)
} else {
String(
android.util.Base64.encode(byteArr, android.util.Base64.DEFAULT),
Charsets.UTF_8)
}

// Replace characters to make it web safe
codeChallenge = codeChallenge.replace("=", "")
codeChallenge = codeChallenge.replace("+", "-")
codeChallenge = codeChallenge.replace("/", "_")

return codeChallenge
}

private fun getStateString(): String {
var stateString = RandomStringUtils.randomAlphanumeric(64)

// Replace characters to make it web safe
stateString = stateString.replace("=", "")
stateString = stateString.replace("+", "-")
stateString = stateString.replace("/", "_")

return stateString
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,12 @@ class DiningFragment : Fragment() {
v.dining_halls_recycler_view?.layoutManager = LinearLayoutManager(mActivity, LinearLayoutManager.VERTICAL, false)
v.dining_swiperefresh.setOnRefreshListener { getDiningHalls() }
getDiningHalls()
initAppBar(v)
// initAppBar(v)
return v
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setTitle("Dining")
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
Expand Down Expand Up @@ -159,14 +158,13 @@ class DiningFragment : Fragment() {
view?.let {displaySnack(it, "Just Updated")}
}
}, {
Log.e("DiningFragment", "Error getting dining halls", it);
mActivity.runOnUiThread {
Log.e("Dining", "Could not load Dining page", it)
loadingPanel?.visibility = View.GONE
internetConnectionDining?.setBackgroundColor(resources.getColor(R.color.logo_dark_blue))
//R.color.darkRedBackground))
internetConnection_message_dining?.setText("Pardon our dust, new features coming soon!")
//getString(R.string.internet_error))
internetConnectionDining?.visibility = View.VISIBLE
//internetConnectionDining?.setBackgroundColor(resources.getColor(R.color.darkRedBackground))
//internetConnection_message_dining?.text = getString(R.string.internet_error)
//internetConnectionDining?.visibility = View.VISIBLE
no_results?.visibility = View.VISIBLE
dining_swiperefresh?.isRefreshing = false
}
Expand All @@ -182,16 +180,6 @@ class DiningFragment : Fragment() {
}
}

private fun initAppBar(view: View) {
if (Build.VERSION.SDK_INT > 16) {
(view.appbar_home.layoutParams as CoordinatorLayout.LayoutParams).behavior = ToolbarBehavior()
}
view.date_view.text = Utils.getCurrentSystemTime()
}

private fun setTitle(title: CharSequence) {
title_view.text = title
}

/**
* Shows SnackBar message right below the app bar
Expand Down
Loading

0 comments on commit a2e9b14

Please sign in to comment.