diff --git a/api/build.gradle b/api/build.gradle index f247baf10..1f7cf1979 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -32,6 +32,7 @@ dependencies { implementation "org.jsoup:jsoup:$jsoup" implementation "org.apache.commons:commons-lang3:$apacheLang" implementation "com.google.code.gson:gson:$gson" + implementation "org.slf4j:slf4j-api:$slf4jApi" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" diff --git a/api/src/main/java/io/github/wulkanowy/api/Client.java b/api/src/main/java/io/github/wulkanowy/api/Client.java index 277b80393..869ed65e3 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Client.java +++ b/api/src/main/java/io/github/wulkanowy/api/Client.java @@ -3,6 +3,8 @@ package io.github.wulkanowy.api; import org.jsoup.Connection; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Date; @@ -27,6 +29,8 @@ public class Client { private Cookies cookies = new Cookies(); + private static final Logger logger = LoggerFactory.getLogger(Client.class); + Client(String email, String password, String symbol) { this.email = email; this.password = password; @@ -59,9 +63,13 @@ public class Client { } this.symbol = new Login(this).login(email, password, symbol); + logger.info("Login successful on {} at {}", getHost(), new Date()); } private boolean isLoggedIn() { + logger.debug("Last success request: {}", lastSuccessRequest); + logger.debug("Cookies: {}", getCookies().size()); + return getCookies().size() > 0 && lastSuccessRequest != null && 5 > TimeUnit.MILLISECONDS.toMinutes(new Date().getTime() - lastSuccessRequest.getTime()); @@ -75,10 +83,6 @@ public class Client { this.symbol = symbol; } - public void addCookies(Map items) { - cookies.addItems(items); - } - private Map getCookies() { return cookies.getItems(); } @@ -111,7 +115,11 @@ public class Client { this.cookies.addItems(cookies); } - Connection.Response response = Jsoup.connect(getFilledUrl(url)) + url = getFilledUrl(url); + + logger.debug("GET {}", url); + + Connection.Response response = Jsoup.connect(url) .followRedirects(true) .cookies(getCookies()) .execute(); @@ -128,7 +136,11 @@ public class Client { } public synchronized Document postPageByUrl(String url, String[][] params) throws IOException, VulcanException { - Connection connection = Jsoup.connect(getFilledUrl(url)); + url = getFilledUrl(url); + + logger.debug("POST {}", url); + + Connection connection = Jsoup.connect(url); for (String[] data : params) { connection.data(data[0], data[1]); @@ -150,7 +162,11 @@ public class Client { public String getJsonStringByUrl(String url) throws IOException, VulcanException { login(); - Connection.Response response = Jsoup.connect(getFilledUrl(url)) + url = getFilledUrl(url); + + logger.debug("GET {}", url); + + Connection.Response response = Jsoup.connect(url) .followRedirects(true) .ignoreContentType(true) .cookies(getCookies()) @@ -164,7 +180,11 @@ public class Client { public String postJsonStringByUrl(String url, String[][] params) throws IOException, VulcanException { login(); - Connection connection = Jsoup.connect(getFilledUrl(url)); + url = getFilledUrl(url); + + logger.debug("POST {}", url); + + Connection connection = Jsoup.connect(url); for (String[] data : params) { connection.data(data[0], data[1]); @@ -196,7 +216,7 @@ public class Client { } if ("Błąd strony".equals(title)) { - throw new NotLoggedInErrorException(title + " " + doc.selectFirst("p, body") + ", status: " + code); + throw new NotLoggedInErrorException(title + " " + doc.selectFirst("body") + ", status: " + code); } return doc; diff --git a/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt b/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt index bad4e97df..3b620db50 100644 --- a/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt +++ b/api/src/main/java/io/github/wulkanowy/api/DateTimeUtils.kt @@ -14,9 +14,13 @@ fun getFormattedDate(date: String): String { } fun getFormattedDate(date: String, format: String): String { - val sdf = SimpleDateFormat(LOG_DATE_PATTERN, Locale.ROOT) + return getFormattedDate(date, LOG_DATE_PATTERN, format) +} + +fun getFormattedDate(date: String, fromFormat: String, toFormat: String): String { + val sdf = SimpleDateFormat(fromFormat, Locale.ROOT) val d = sdf.parse(date) - sdf.applyPattern(format) + sdf.applyPattern(toFormat) return sdf.format(d) } diff --git a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java index a4b8fefa0..03a7b0e55 100644 --- a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java +++ b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java @@ -3,6 +3,8 @@ package io.github.wulkanowy.api; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.net.URL; @@ -32,6 +34,8 @@ public class StudentAndParent implements SnP { private String diaryID; + private static final Logger logger = LoggerFactory.getLogger(StudentAndParent.class); + StudentAndParent(Client client, String schoolID, String studentID, String diaryID) { this.client = client; this.schoolID = schoolID; @@ -43,6 +47,11 @@ public class StudentAndParent implements SnP { if (null == getStudentID() || "".equals(getStudentID())) { Document doc = client.getPageByUrl(getSnpHomePageUrl()); + if (doc.select("#idSection").isEmpty()) { + logger.error("Expected SnP page, got page with title: {} {}", doc.title(), doc.selectFirst("body")); + throw new VulcanException("Nieznany błąd podczas pobierania danych. Strona: " + doc.title()); + } + Student student = getCurrent(getStudents(doc)); studentID = student.getId(); @@ -72,24 +81,27 @@ public class StudentAndParent implements SnP { // get url to uonetplus-opiekun.fakelog.cf Document startPage = client.getPageByUrl(START_PAGE_URL); - Element studentTileLink = startPage.select(".panel.linkownia.pracownik.klient > a").first(); + Elements studentTileLink = startPage.select(".panel.linkownia.pracownik.klient > a"); - if (null == studentTileLink) { + logger.debug("studentTileLink: {}", studentTileLink.size()); + + if (studentTileLink.isEmpty()) { throw new VulcanException("Na pewno używasz konta z dostępem do Witryny ucznia i rodzica?"); } - String snpPageUrl = studentTileLink.attr("href"); + String snpPageUrl = studentTileLink.last().attr("href"); this.schoolID = getExtractedIdFromUrl(snpPageUrl); return snpPageUrl; } - String getExtractedIdFromUrl(String snpPageUrl) throws NotLoggedInErrorException { + String getExtractedIdFromUrl(String snpPageUrl) throws VulcanException { String[] path = snpPageUrl.split(client.getHost())[1].split("/"); if (5 != path.length) { - throw new NotLoggedInErrorException("You are probably not logged in " + snpPageUrl); + logger.error("Expected snp url, got {}", snpPageUrl); + throw new VulcanException("Na pewno używasz konta z dostępem do Witryny ucznia i rodzica?"); } return path[2]; @@ -107,12 +119,12 @@ public class StudentAndParent implements SnP { Map cookies = new HashMap<>(); cookies.put("idBiezacyDziennik", diaryID); cookies.put("idBiezacyUczen", studentID); - client.addCookies(cookies); Document doc = client.getPageByUrl(getBaseUrl() + url, true, cookies); if (!doc.title().startsWith("Witryna ucznia i rodzica")) { - throw new VulcanException("Expected SnP page, got page with title: " + doc.title()); + logger.error("Expected SnP page, got page with title: {} {}", doc.title(), doc.selectFirst("body")); + throw new VulcanException("Nieznany błąd podczas pobierania danych. Strona: " + doc.title()); } if (doc.title().endsWith("Strona główna")) { diff --git a/api/src/main/java/io/github/wulkanowy/api/Vulcan.java b/api/src/main/java/io/github/wulkanowy/api/Vulcan.java index c8c4d2b0e..2b4d1205c 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Vulcan.java +++ b/api/src/main/java/io/github/wulkanowy/api/Vulcan.java @@ -1,5 +1,8 @@ package io.github.wulkanowy.api; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.IOException; import io.github.wulkanowy.api.attendance.AttendanceStatistics; @@ -30,17 +33,21 @@ public class Vulcan { private String diaryId; + private static final Logger logger = LoggerFactory.getLogger(Vulcan.class); + public void setCredentials(String email, String password, String symbol, String schoolId, String studentId, String diaryId) { this.schoolId = schoolId; this.studentId = studentId; this.diaryId = diaryId; client = new Client(email, password, symbol); + + logger.debug("Client created with symbol " + symbol); } public Client getClient() throws NotLoggedInErrorException { if (null == client) { - throw new NotLoggedInErrorException("Use setCredentials() method first"); + throw new NotLoggedInErrorException("Vulcan must be initialized by calling setCredentials() prior to fetch data"); } return client; diff --git a/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt index cd08a5858..d622b4de3 100644 --- a/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt +++ b/api/src/main/java/io/github/wulkanowy/api/mobile/RegisteredDevices.kt @@ -1,8 +1,7 @@ package io.github.wulkanowy.api.mobile import io.github.wulkanowy.api.SnP -import java.text.SimpleDateFormat -import java.util.* +import io.github.wulkanowy.api.getFormattedDate class RegisteredDevices(private val snp: SnP) { @@ -28,7 +27,7 @@ class RegisteredDevices(private val snp: SnP) { devices.add(Device( cells[0].text().replace(" ($system)", ""), system, - formatDate(cells[1].text()), + getFormattedDate(cells[1].text(), "dd.MM.yyyy 'godz:' HH:mm:ss", "yyyy-MM-dd HH:mm:ss"), cells[2].select("a").attr("href") .split("/").last().toInt() )) @@ -36,13 +35,4 @@ class RegisteredDevices(private val snp: SnP) { return devices } - - // TODO: Move to date utils - private fun formatDate(date: String): String { - val sdf = SimpleDateFormat("dd.MM.yyyy 'godz:' HH:mm:ss", Locale.ROOT) - val d = sdf.parse(date) - sdf.applyPattern("yyyy-MM-dd HH:mm:ss") - - return sdf.format(d) - } } diff --git a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java index 1b6f7a91b..ba0c8f7fb 100644 --- a/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/StudentAndParentTest.java @@ -83,7 +83,7 @@ public class StudentAndParentTest { snp.getExtractedIdFromUrl("https://uonetplus-opiekun.vulcan.net.pl/demoupowiat/demo12345/Start/Index/")); } - @Test(expected = NotLoggedInErrorException.class) + @Test(expected = VulcanException.class) public void getExtractedIDNotLoggedTest() throws Exception { Mockito.when(client.getHost()).thenReturn("vulcan.net.pl"); StudentAndParent snp = new StudentAndParent(client, "symbol", null, null); @@ -131,8 +131,8 @@ public class StudentAndParentTest { @Test public void getDiariesAndStudentTest() throws IOException, VulcanException { - Document snpHome = Jsoup.parse(FixtureHelper.getAsString( - getClass().getResourceAsStream("StudentAndParent.html"))); + String input = FixtureHelper.getAsString(getClass().getResourceAsStream("WitrynaUczniaIRodzica.html")); + Document snpHome = Jsoup.parse(input); client = Mockito.mock(Client.class); Mockito.when(client.getPageByUrl(Mockito.anyString())).thenReturn(snpHome); diff --git a/api/src/test/resources/io/github/wulkanowy/api/StudentAndParent.html b/api/src/test/resources/io/github/wulkanowy/api/WitrynaUczniaIRodzica.html similarity index 100% rename from api/src/test/resources/io/github/wulkanowy/api/StudentAndParent.html rename to api/src/test/resources/io/github/wulkanowy/api/WitrynaUczniaIRodzica.html diff --git a/app/build.gradle b/app/build.gradle index 50677a7ae..aefebcfbe 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -118,6 +118,9 @@ dependencies { implementation "com.jakewharton.threetenabp:threetenabp:$threeTenABP" implementation "com.google.android.gms:play-services-oss-licenses:$ossLicenses" + implementation "com.jakewharton.timber:timber:$timber" + implementation "at.favre.lib:slf4j-timber:$slf4jTimber" + implementation("com.crashlytics.sdk.android:crashlytics:$crashlyticsSdk@aar") { transitive = true } diff --git a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java index 5b68abbf4..d3570512a 100644 --- a/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java +++ b/app/src/main/java/io/github/wulkanowy/WulkanowyApp.java @@ -12,11 +12,12 @@ import javax.inject.Inject; import dagger.android.AndroidInjector; import dagger.android.support.DaggerApplication; import eu.davidea.flexibleadapter.FlexibleAdapter; -import eu.davidea.flexibleadapter.utils.Log; import io.fabric.sdk.android.Fabric; import io.github.wulkanowy.data.RepositoryContract; import io.github.wulkanowy.di.DaggerAppComponent; -import io.github.wulkanowy.utils.LogUtils; +import io.github.wulkanowy.utils.FabricUtils; +import io.github.wulkanowy.utils.LoggerUtils; +import timber.log.Timber; public class WulkanowyApp extends DaggerApplication { @@ -39,15 +40,18 @@ public class WulkanowyApp extends DaggerApplication { if (repository.getSharedRepo().isUserLoggedIn()) { try { repository.getSyncRepo().initLastUser(); + FabricUtils.logLogin("Open app", true); } catch (Exception e) { - LogUtils.error("An error occurred when the application was started", e); + FabricUtils.logLogin("Open app", false); + Timber.e(e, "An error occurred when the application was started"); } } } private void enableDebugLog() { QueryBuilder.LOG_VALUES = true; - FlexibleAdapter.enableLogs(Log.Level.DEBUG); + FlexibleAdapter.enableLogs(eu.davidea.flexibleadapter.utils.Log.Level.DEBUG); + Timber.plant(new LoggerUtils.DebugLogTree()); } private void initializeFabric() { @@ -60,6 +64,7 @@ public class WulkanowyApp extends DaggerApplication { ) .debuggable(BuildConfig.DEBUG) .build()); + Timber.plant(new LoggerUtils.CrashlyticsTree()); } @Override diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java index 7ffcfe279..904fa3433 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/DbHelper.java @@ -22,7 +22,7 @@ import io.github.wulkanowy.data.db.dao.migrations.Migration26; import io.github.wulkanowy.data.db.dao.migrations.Migration27; import io.github.wulkanowy.data.db.dao.migrations.Migration28; import io.github.wulkanowy.data.db.shared.SharedPrefContract; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class DbHelper extends DaoMaster.OpenHelper { @@ -41,7 +41,7 @@ public class DbHelper extends DaoMaster.OpenHelper { @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { - LogUtils.info("Cleaning user data oldVersion=" + oldVersion + " newVersion=" + newVersion); + Timber.i("Cleaning user data oldVersion=%s newVersion=%s", oldVersion, newVersion); Database database = new StandardDatabase(db); recreateDatabase(database); } @@ -54,11 +54,11 @@ public class DbHelper extends DaoMaster.OpenHelper { for (Migration migration : migrations) { if (oldVersion < migration.getVersion()) { try { - LogUtils.info("Applying migration to db schema v" + migration.getVersion() + "..."); + Timber.i("Applying migration to db schema v%s...", migration.getVersion()); migration.runMigration(db, sharedPref, vulcan); - LogUtils.info("Migration " + migration.getVersion() + " complete"); + Timber.i("Migration %s complete", migration.getVersion()); } catch (Exception e) { - e.printStackTrace(); + Timber.e(e, "Failed to apply migration"); recreateDatabase(db); break; } @@ -67,7 +67,7 @@ public class DbHelper extends DaoMaster.OpenHelper { } private void recreateDatabase(Database db) { - LogUtils.info("Database is recreating..."); + Timber.i("Database is recreating..."); sharedPref.setCurrentUserId(0); DaoMaster.dropAllTables(db, true); onCreate(db); diff --git a/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java index 97b575a02..b2a41ad15 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/dao/migrations/Migration23.java @@ -9,8 +9,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import io.github.wulkanowy.api.generic.Diary; import io.github.wulkanowy.api.Vulcan; +import io.github.wulkanowy.api.generic.Diary; import io.github.wulkanowy.data.db.dao.DbHelper; import io.github.wulkanowy.data.db.shared.SharedPrefContract; import io.github.wulkanowy.utils.security.Scrambler; diff --git a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java index 81aeaee2b..f8a1baaa2 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java @@ -3,8 +3,6 @@ package io.github.wulkanowy.data.db.resources; import android.content.Context; import android.content.res.Resources; -import com.crashlytics.android.Crashlytics; - import java.io.IOException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; @@ -16,8 +14,8 @@ import io.github.wulkanowy.R; import io.github.wulkanowy.api.NotLoggedInErrorException; import io.github.wulkanowy.data.db.dao.entities.AttendanceLesson; import io.github.wulkanowy.utils.AppConstant; -import io.github.wulkanowy.utils.LogUtils; import io.github.wulkanowy.utils.security.CryptoException; +import timber.log.Timber; @Singleton public class ResourcesRepository implements ResourcesContract { @@ -41,8 +39,7 @@ public class ResourcesRepository implements ResourcesContract { @Override public String getErrorLoginMessage(Exception exception) { - LogUtils.error(AppConstant.APP_NAME + " encountered a error", exception); - Crashlytics.logException(exception); + Timber.e(exception,"%s encountered a error", AppConstant.APP_NAME); if (exception instanceof CryptoException) { return resources.getString(R.string.encrypt_failed_text); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java index 032e95e4e..b9f72cb2d 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/AccountSync.java @@ -24,9 +24,9 @@ import io.github.wulkanowy.data.db.dao.entities.Symbol; import io.github.wulkanowy.data.db.dao.entities.SymbolDao; import io.github.wulkanowy.data.db.shared.SharedPrefContract; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; import io.github.wulkanowy.utils.security.CryptoException; import io.github.wulkanowy.utils.security.Scrambler; +import timber.log.Timber; @Singleton public class AccountSync { @@ -73,7 +73,7 @@ public class AccountSync { } private Account insertAccount(String email, String password) throws CryptoException { - LogUtils.debug("Register account: " + email); + Timber.d("Register account"); Account account = new Account() .setEmail(email) .setPassword(Scrambler.encrypt(email, password, context)); @@ -82,10 +82,11 @@ public class AccountSync { } private Symbol insertSymbol(Account account) throws VulcanException, IOException { - LogUtils.debug("Register symbol: " + vulcan.getSymbol()); + String schoolId = vulcan.getStudentAndParent().getSchoolID(); + Timber.d("Register symbol %s", vulcan.getSymbol()); Symbol symbol = new Symbol() .setUserId(account.getId()) - .setSchoolId(vulcan.getStudentAndParent().getSchoolID()) + .setSchoolId(schoolId) .setSymbol(vulcan.getSymbol()); daoSession.getSymbolDao().insert(symbol); @@ -97,7 +98,7 @@ public class AccountSync { vulcan.getStudentAndParent().getStudents(), symbol.getId() ); - LogUtils.debug("Register students: " + studentList.size()); + Timber.d("Register students %s", studentList.size()); daoSession.getStudentDao().insertInTx(studentList); } @@ -108,7 +109,7 @@ public class AccountSync { StudentDao.Properties.SymbolId.eq(symbolEntity.getId()), StudentDao.Properties.Current.eq(true) ).unique().getId()); - LogUtils.debug("Register diaries: " + diaryList.size()); + Timber.d("Register diaries %s", diaryList.size()); daoSession.getDiaryDao().insertInTx(diaryList); } @@ -118,7 +119,7 @@ public class AccountSync { daoSession.getDiaryDao().queryBuilder().where( DiaryDao.Properties.Current.eq(true) ).unique().getId()); - LogUtils.debug("Register semesters: " + semesterList.size()); + Timber.d("Register semesters %s", semesterList.size()); daoSession.getSemesterDao().insertInTx(semesterList); } @@ -130,7 +131,7 @@ public class AccountSync { throw new NotRegisteredUserException("Can't find user id in SharedPreferences"); } - LogUtils.debug("Initialization current user id=" + userId); + Timber.d("Init current user (%s)", userId); Account account = daoSession.getAccountDao().load(userId); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java index 9f379be60..187694189 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/AttendanceSync.java @@ -18,7 +18,7 @@ import io.github.wulkanowy.data.db.dao.entities.DayDao; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class AttendanceSync { @@ -47,7 +47,7 @@ public class AttendanceSync { daoSession.getAttendanceLessonDao().saveInTx(lessonList); - LogUtils.debug("Synchronization attendance lessons (amount = " + lessonList.size() + ")"); + Timber.d("Attendance synchronization complete (%s)", lessonList.size()); } private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java index 85b4dac40..db4730921 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/ExamsSync.java @@ -17,7 +17,7 @@ import io.github.wulkanowy.data.db.dao.entities.ExamDao; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; public class ExamsSync { @@ -45,7 +45,7 @@ public class ExamsSync { daoSession.getExamDao().saveInTx(examList); - LogUtils.debug("Synchronization exams (amount = " + examList.size() + ")"); + Timber.d("Exams synchronization complete (%s)", examList.size()); } private Week getWeekFromDb(String date) { diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/GradeSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/GradeSync.java index 0b70695de..59a71845c 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/GradeSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/GradeSync.java @@ -1,7 +1,6 @@ package io.github.wulkanowy.data.sync; import java.io.IOException; -import java.text.ParseException; import java.util.ArrayList; import java.util.List; @@ -16,7 +15,7 @@ import io.github.wulkanowy.data.db.dao.entities.Semester; import io.github.wulkanowy.data.db.dao.entities.SubjectDao; import io.github.wulkanowy.utils.DataObjectConverter; import io.github.wulkanowy.utils.EntitiesCompare; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class GradeSync { @@ -33,7 +32,7 @@ public class GradeSync { this.vulcan = vulcan; } - public void sync(long semesterId) throws IOException, VulcanException, ParseException { + public void sync(long semesterId) throws IOException, VulcanException { this.semesterId = semesterId; Semester semester = daoSession.getSemesterDao().load(semesterId); @@ -44,7 +43,7 @@ public class GradeSync { daoSession.getGradeDao().deleteInTx(semester.getGradeList()); daoSession.getGradeDao().insertInTx(lastList); - LogUtils.debug("Synchronization grades (amount = " + lastList.size() + ")"); + Timber.d("Grades synchronization complete (%s)", lastList.size()); } private void resetSemesterRelations(Semester semester) { @@ -64,7 +63,7 @@ public class GradeSync { return updatedList; } - private List getComparedList(Semester semester) throws IOException, VulcanException, ParseException { + private List getComparedList(Semester semester) throws IOException, VulcanException { List gradesFromNet = DataObjectConverter.gradesToGradeEntities( vulcan.getGradesList().getAll(semester.getValue()), semesterId); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/SubjectSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/SubjectSync.java index 163a62340..1d0300d69 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/SubjectSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/SubjectSync.java @@ -13,7 +13,7 @@ import io.github.wulkanowy.data.db.dao.entities.DaoSession; import io.github.wulkanowy.data.db.dao.entities.Semester; import io.github.wulkanowy.data.db.dao.entities.Subject; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class SubjectSync { @@ -40,7 +40,7 @@ public class SubjectSync { daoSession.getSubjectDao().deleteInTx(getSubjectsFromDb()); daoSession.getSubjectDao().insertInTx(lastList); - LogUtils.debug("Synchronization subjects (amount = " + lastList.size() + ")"); + Timber.d("Subjects synchronization complete (%s)", lastList.size()); } private List getSubjectsFromNet(Semester semester) throws VulcanException, IOException { diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/SyncRepository.java b/app/src/main/java/io/github/wulkanowy/data/sync/SyncRepository.java index 6a1e4dc1f..05dd14fdb 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/SyncRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/SyncRepository.java @@ -1,7 +1,6 @@ package io.github.wulkanowy.data.sync; import java.io.IOException; -import java.text.ParseException; import javax.inject.Inject; import javax.inject.Singleton; @@ -47,17 +46,17 @@ public class SyncRepository implements SyncContract { } @Override - public void initLastUser() throws IOException, CryptoException { + public void initLastUser() throws CryptoException { accountSync.initLastUser(); } @Override - public void syncGrades(int semesterName) throws VulcanException, IOException, ParseException { + public void syncGrades(int semesterName) throws VulcanException, IOException { gradeSync.sync(semesterName); } @Override - public void syncGrades() throws VulcanException, IOException, ParseException { + public void syncGrades() throws VulcanException, IOException { gradeSync.sync(database.getCurrentSemesterId()); } @@ -72,12 +71,12 @@ public class SyncRepository implements SyncContract { } @Override - public void syncAttendance() throws ParseException, IOException, VulcanException { + public void syncAttendance() throws IOException, VulcanException { attendanceSync.syncAttendance(database.getCurrentDiaryId(), null); } @Override - public void syncAttendance(long diaryId, String date) throws ParseException, IOException, VulcanException { + public void syncAttendance(long diaryId, String date) throws IOException, VulcanException { if (diaryId != 0) { attendanceSync.syncAttendance(diaryId, date); } else { @@ -86,12 +85,12 @@ public class SyncRepository implements SyncContract { } @Override - public void syncTimetable() throws VulcanException, IOException, ParseException { + public void syncTimetable() throws VulcanException, IOException { timetableSync.syncTimetable(database.getCurrentDiaryId(), null); } @Override - public void syncTimetable(long diaryId, String date) throws VulcanException, IOException, ParseException { + public void syncTimetable(long diaryId, String date) throws VulcanException, IOException { if (diaryId != 0) { timetableSync.syncTimetable(diaryId, date); } else { @@ -100,12 +99,12 @@ public class SyncRepository implements SyncContract { } @Override - public void syncExams() throws VulcanException, IOException, ParseException { + public void syncExams() throws VulcanException, IOException { examsSync.syncExams(database.getCurrentDiaryId(), null); } @Override - public void syncExams(long diaryId, String date) throws VulcanException, IOException, ParseException { + public void syncExams(long diaryId, String date) throws VulcanException, IOException { if (diaryId != 0) { examsSync.syncExams(diaryId, date); } else { @@ -114,7 +113,7 @@ public class SyncRepository implements SyncContract { } @Override - public void syncAll() throws VulcanException, IOException, ParseException { + public void syncAll() throws VulcanException, IOException { syncSubjects(); syncGrades(); syncAttendance(); diff --git a/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java b/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java index 309403c88..1ea2fa488 100644 --- a/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java +++ b/app/src/main/java/io/github/wulkanowy/data/sync/TimetableSync.java @@ -20,7 +20,7 @@ import io.github.wulkanowy.data.db.dao.entities.TimetableLessonDao; import io.github.wulkanowy.data.db.dao.entities.Week; import io.github.wulkanowy.data.db.dao.entities.WeekDao; import io.github.wulkanowy.utils.DataObjectConverter; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; @Singleton public class TimetableSync { @@ -49,7 +49,7 @@ public class TimetableSync { daoSession.getTimetableLessonDao().saveInTx(lessonList); - LogUtils.debug("Synchronization timetable lessons (amount = " + lessonList.size() + ")"); + Timber.d("Timetable synchronization complete (%s)", lessonList.size()); } private io.github.wulkanowy.api.generic.Week getWeekFromApi(String date) diff --git a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java index 432bdc23a..b21363910 100644 --- a/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java +++ b/app/src/main/java/io/github/wulkanowy/services/jobs/SyncJob.java @@ -4,7 +4,6 @@ import android.app.PendingIntent; import android.content.Context; import android.support.v4.app.NotificationCompat; -import com.crashlytics.android.Crashlytics; import com.firebase.jobdispatcher.Constraint; import com.firebase.jobdispatcher.FirebaseJobDispatcher; import com.firebase.jobdispatcher.GooglePlayDriver; @@ -27,7 +26,8 @@ import io.github.wulkanowy.data.db.dao.entities.Grade; import io.github.wulkanowy.data.sync.NotRegisteredUserException; import io.github.wulkanowy.services.notifies.GradeNotify; import io.github.wulkanowy.ui.main.MainActivity; -import io.github.wulkanowy.utils.LogUtils; +import io.github.wulkanowy.utils.FabricUtils; +import timber.log.Timber; public class SyncJob extends SimpleJobService { @@ -74,13 +74,18 @@ public class SyncJob extends SimpleJobService { if (!gradeList.isEmpty() && repository.getSharedRepo().isNotifyEnable()) { showNotification(); } + + FabricUtils.logLogin("Background", true); + return JobService.RESULT_SUCCESS; } catch (NotRegisteredUserException e) { logError(e); stop(getApplicationContext()); + return JobService.RESULT_FAIL_NORETRY; } catch (Exception e) { logError(e); + return JobService.RESULT_FAIL_RETRY; } } @@ -122,7 +127,7 @@ public class SyncJob extends SimpleJobService { } private void logError(Exception e) { - Crashlytics.logException(e); - LogUtils.error("During background synchronization an error occurred", e); + FabricUtils.logLogin("Background", false); + Timber.e(e, "During background synchronization an error occurred"); } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java index fb63e6af2..3ae1ce9e7 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java +++ b/app/src/main/java/io/github/wulkanowy/ui/login/LoginPresenter.java @@ -85,7 +85,7 @@ public class LoginPresenter extends BasePresenter @Override public void onEndAsync(boolean success, Exception exception) { if (success) { - FabricUtils.logRegister(true, getRepository().getDbRepo().getCurrentSymbol().getSymbol()); + FabricUtils.logRegister(true, getRepository().getDbRepo().getCurrentSymbol().getSymbol(), "Success"); getView().openMainActivity(); return; } else if (exception instanceof BadCredentialsException) { @@ -95,7 +95,7 @@ public class LoginPresenter extends BasePresenter getView().setErrorSymbolRequired(); getView().showSoftInput(); } else { - FabricUtils.logRegister(false, symbol); + FabricUtils.logRegister(false, symbol, exception.getMessage()); getView().showMessage(getRepository().getResRepo().getErrorLoginMessage(exception)); } diff --git a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java index 503257982..05557b81e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java +++ b/app/src/main/java/io/github/wulkanowy/ui/main/exams/ExamsFragment.java @@ -2,7 +2,6 @@ package io.github.wulkanowy.ui.main.exams; import android.os.Bundle; import android.support.annotation.NonNull; -import android.support.design.widget.Snackbar; import android.support.design.widget.TabLayout; import android.support.v4.view.ViewPager; import android.view.LayoutInflater; @@ -13,7 +12,6 @@ import javax.inject.Inject; import javax.inject.Named; import butterknife.BindView; -import butterknife.ButterKnife; import io.github.wulkanowy.R; import io.github.wulkanowy.ui.base.BaseFragment; import io.github.wulkanowy.ui.base.BasePagerAdapter; diff --git a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java index b90f396c5..5e4dfec1f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java +++ b/app/src/main/java/io/github/wulkanowy/ui/splash/SplashActivity.java @@ -4,7 +4,6 @@ import android.os.Bundle; import javax.inject.Inject; -import io.github.wulkanowy.services.jobs.SyncJob; import io.github.wulkanowy.services.notifies.NotificationService; import io.github.wulkanowy.ui.base.BaseActivity; import io.github.wulkanowy.ui.login.LoginActivity; diff --git a/app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java b/app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java index 38811534c..69897caa0 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java +++ b/app/src/main/java/io/github/wulkanowy/utils/FabricUtils.java @@ -2,6 +2,7 @@ package io.github.wulkanowy.utils; import com.crashlytics.android.answers.Answers; import com.crashlytics.android.answers.CustomEvent; +import com.crashlytics.android.answers.LoginEvent; import com.crashlytics.android.answers.SignUpEvent; public final class FabricUtils { @@ -10,17 +11,26 @@ public final class FabricUtils { throw new IllegalStateException("Utility class"); } - public static void logRegister(boolean result, String symbol) { + public static void logLogin(String method, boolean result) { + Answers.getInstance().logLogin(new LoginEvent() + .putMethod(method) + .putSuccess(result) + ); + } + + public static void logRegister(boolean result, String symbol, String message) { Answers.getInstance().logSignUp(new SignUpEvent() .putMethod("Login activity") .putSuccess(result) - .putCustomAttribute("symbol", symbol)); + .putCustomAttribute("symbol", symbol) + .putCustomAttribute("message", message) + ); } public static void logRefresh(String name, boolean result, String date) { Answers.getInstance().logCustom( new CustomEvent(name + " refresh") - .putCustomAttribute("Success", result ? 1 : 0) + .putCustomAttribute("Success", result ? "true" : "false") .putCustomAttribute("Date", date) ); } diff --git a/app/src/main/java/io/github/wulkanowy/utils/LogUtils.java b/app/src/main/java/io/github/wulkanowy/utils/LogUtils.java deleted file mode 100644 index f59bbf641..000000000 --- a/app/src/main/java/io/github/wulkanowy/utils/LogUtils.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.wulkanowy.utils; - -import android.util.Log; - -public final class LogUtils { - - private LogUtils() { - throw new IllegalStateException("Utility class"); - } - - public static void debug(String message) { - Log.d(AppConstant.APP_NAME, message); - } - - public static void error(String message, Throwable throwable) { - Log.e(AppConstant.APP_NAME, message, throwable); - } - - public static void error(String message) { - Log.e(AppConstant.APP_NAME, message); - } - - public static void info(String message) { - Log.i(AppConstant.APP_NAME, message); - } -} diff --git a/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.java b/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.java new file mode 100644 index 000000000..6e6c701b1 --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/utils/LoggerUtils.java @@ -0,0 +1,47 @@ +package io.github.wulkanowy.utils; + +import android.os.Build; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.Log; + +import com.crashlytics.android.Crashlytics; + +import timber.log.Timber; + +public final class LoggerUtils { + + public static class CrashlyticsTree extends Timber.Tree { + + @Override + protected void log(int priority, @Nullable String tag, @Nullable String message, @Nullable Throwable t) { + Crashlytics.setInt("priority", priority); + Crashlytics.setString("tag", tag); + + if (t == null) { + Crashlytics.log(message); + } else { + Crashlytics.setString("message", message); + Crashlytics.logException(t); + } + } + } + + public static class DebugLogTree extends Timber.DebugTree { + + @Override + protected void log(int priority, String tag, @NonNull String message, Throwable t) { + if ("HUAWEI".equals(Build.MANUFACTURER) || "samsung".equals(Build.MANUFACTURER)) { + if (priority == Log.VERBOSE || priority == Log.DEBUG || priority == Log.INFO) { + priority = Log.ERROR; + } + } + super.log(priority, AppConstant.APP_NAME, message, t); + } + + @Override + protected String createStackElementTag(@NonNull StackTraceElement element) { + return super.createStackElementTag(element) + " - " + element.getLineNumber(); + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/utils/async/AbstractTask.java b/app/src/main/java/io/github/wulkanowy/utils/async/AbstractTask.java index 5106d6417..447214164 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/async/AbstractTask.java +++ b/app/src/main/java/io/github/wulkanowy/utils/async/AbstractTask.java @@ -2,7 +2,7 @@ package io.github.wulkanowy.utils.async; import android.os.AsyncTask; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; public class AbstractTask extends AsyncTask { @@ -28,7 +28,7 @@ public class AbstractTask extends AsyncTask { } else if (onRefreshListener != null) { onRefreshListener.onDoInBackgroundRefresh(); } else { - LogUtils.error("AbstractTask does not have a listener assigned"); + Timber.e("AbstractTask does not have a listener assigned"); } return true; } catch (Exception e) { @@ -45,7 +45,7 @@ public class AbstractTask extends AsyncTask { } else if (onRefreshListener != null) { onRefreshListener.onCanceledRefreshAsync(); } else { - LogUtils.error("AbstractTask does not have a listener assigned"); + Timber.e("AbstractTask does not have a listener assigned"); } } @@ -57,7 +57,7 @@ public class AbstractTask extends AsyncTask { } else if (onRefreshListener != null) { onRefreshListener.onEndRefreshAsync(result, exception); } else { - LogUtils.error("AbstractTask does not have a listener assigned"); + Timber.e("AbstractTask does not have a listener assigned"); } } } diff --git a/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java b/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java index dc0c409a4..8e425a894 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java +++ b/app/src/main/java/io/github/wulkanowy/utils/security/Scrambler.java @@ -26,7 +26,7 @@ import javax.crypto.CipherInputStream; import javax.crypto.CipherOutputStream; import javax.security.auth.x500.X500Principal; -import io.github.wulkanowy.utils.LogUtils; +import timber.log.Timber; public final class Scrambler { @@ -111,7 +111,7 @@ public final class Scrambler { throw new CryptoException("GenerateNewKey - String is empty"); } - LogUtils.debug("Key pair are create"); + Timber.d("Key pair are create"); } diff --git a/app/src/test/java/io/github/wulkanowy/data/db/dao/entities/GradeTest.java b/app/src/test/java/io/github/wulkanowy/data/db/dao/entities/GradeTest.java index 580ffdf51..f47e75e22 100644 --- a/app/src/test/java/io/github/wulkanowy/data/db/dao/entities/GradeTest.java +++ b/app/src/test/java/io/github/wulkanowy/data/db/dao/entities/GradeTest.java @@ -3,8 +3,6 @@ package io.github.wulkanowy.data.db.dao.entities; import org.junit.Assert; import org.junit.Test; -import io.github.wulkanowy.R; - public class GradeTest { @Test diff --git a/build.gradle b/build.gradle index 0f9746575..6af8545e5 100644 --- a/build.gradle +++ b/build.gradle @@ -50,6 +50,10 @@ ext { gson = "2.8.5" ossLicenses = "15.0.1" + slf4jApi = "1.7.25" + slf4jTimber = "1.0.1" + timber = "4.7.0" + debugDb = "1.0.3" sqlcipher = "3.5.9"