1
0

Compare commits

...

5 Commits
0.4.0 ... 0.4.1

25 changed files with 169 additions and 68 deletions

View File

@ -227,5 +227,5 @@ workflows:
requires: requires:
- instrumented - instrumented
filters: filters:
tags: branches:
only: /.*/ only: master

View File

@ -4,9 +4,11 @@
[![Bitrise](https://img.shields.io/bitrise/daeff1893f3c8128/master.svg?token=Hjm1ACamk86JDeVVJHOeqQ&style=flat-square)](https://www.bitrise.io/app/daeff1893f3c8128) [![Bitrise](https://img.shields.io/bitrise/daeff1893f3c8128/master.svg?token=Hjm1ACamk86JDeVVJHOeqQ&style=flat-square)](https://www.bitrise.io/app/daeff1893f3c8128)
[![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy) [![Codecov](https://img.shields.io/codecov/c/github/wulkanowy/wulkanowy/master.svg?style=flat-square)](https://codecov.io/gh/wulkanowy/wulkanowy)
[![BCH compliance](https://bettercodehub.com/edge/badge/wulkanowy/wulkanowy?branch=master)](https://bettercodehub.com/) [![BCH compliance](https://bettercodehub.com/edge/badge/wulkanowy/wulkanowy?branch=master)](https://bettercodehub.com/)
[![Scrutinizer](https://img.shields.io/scrutinizer/g/wulkanowy/wulkanowy.svg)](https://scrutinizer-ci.com/g/wulkanowy/wulkanowy/?branch=master) [![Scrutinizer](https://img.shields.io/scrutinizer/g/wulkanowy/wulkanowy.svg?style=flat-square)](https://scrutinizer-ci.com/g/wulkanowy/wulkanowy/?branch=master)
[![Known Vulnerabilities](https://snyk.io/test/github/wulkanowy/wulkanowy/badge.svg?targetFile=app%2Fbuild.gradle&style=flat-square)](https://snyk.io/test/github/wulkanowy/wulkanowy?targetFile=app%2Fbuild.gradle)
[![Bintray](https://img.shields.io/bintray/v/wulkanowy/wulkanowy/api.svg?style=flat-square)](https://bintray.com/wulkanowy/wulkanowy/api) [![Bintray](https://img.shields.io/bintray/v/wulkanowy/wulkanowy/api.svg?style=flat-square)](https://bintray.com/wulkanowy/wulkanowy/api)
[![Discord](https://img.shields.io/discord/390889354199040011.svg?style=flat-square)](https://discord.gg/JMG2rhJ)
[Pobierz wersję beta](https://play.google.com/store/apps/details?id=io.github.wulkanowy&utm_source=vcs)
[Pobierz wersję rozwojową](https://bitrise-redirector.herokuapp.com/v0.1/apps/daeff1893f3c8128/builds/master/artifacts/app-debug-bitrise-signed.apk) [Pobierz wersję rozwojową](https://bitrise-redirector.herokuapp.com/v0.1/apps/daeff1893f3c8128/builds/master/artifacts/app-debug-bitrise-signed.apk)

View File

@ -23,7 +23,7 @@ public class Client {
private String symbol; private String symbol;
private Date lastSuccessRequest = null; private Date lastSuccessRequest;
private Cookies cookies = new Cookies(); private Cookies cookies = new Cookies();
@ -103,7 +103,7 @@ public class Client {
return getPageByUrl(url, loginBefore, null); return getPageByUrl(url, loginBefore, null);
} }
public Document getPageByUrl(String url, boolean loginBefore, Map<String, String> cookies) throws IOException, VulcanException { public synchronized Document getPageByUrl(String url, boolean loginBefore, Map<String, String> cookies) throws IOException, VulcanException {
if (loginBefore) { if (loginBefore) {
login(); login();
} }
@ -128,7 +128,7 @@ public class Client {
return doc; return doc;
} }
public Document postPageByUrl(String url, String[][] params) throws IOException, VulcanException { public synchronized Document postPageByUrl(String url, String[][] params) throws IOException, VulcanException {
Connection connection = Jsoup.connect(getFilledUrl(url)); Connection connection = Jsoup.connect(getFilledUrl(url));
for (String[] data : params) { for (String[] data : params) {

View File

@ -106,7 +106,11 @@ public class StudentAndParent implements SnP {
Document doc = client.getPageByUrl(getBaseUrl() + url, true, cookies); Document doc = client.getPageByUrl(getBaseUrl() + url, true, cookies);
if ("Witryna ucznia i rodzica Strona główna".equals(doc.select("title").first().text())) { if (!doc.title().startsWith("Witryna ucznia i rodzica")) {
throw new VulcanException("Expected SnP page, got page with title: " + doc.title());
}
if (doc.title().endsWith("Strona główna")) {
throw new VulcanException("Sesja została nieprawidłowo zainicjowana"); throw new VulcanException("Sesja została nieprawidłowo zainicjowana");
} }

View File

@ -56,7 +56,7 @@ public class GradesList {
String descriptions = row.select("td:nth-child(3)").text(); String descriptions = row.select("td:nth-child(3)").text();
String symbol = descriptions.split(", ")[0]; String symbol = descriptions.split(", ")[0];
String description = descriptions.replaceFirst(symbol, "").replaceFirst(", ", ""); String description = descriptions.replaceFirst(Pattern.quote(symbol), "").replaceFirst(", ", "");
String color = getColor(row.select("td:nth-child(2) span.ocenaCzastkowa").attr("style")); String color = getColor(row.select("td:nth-child(2) span.ocenaCzastkowa").attr("style"));
String date = formatDate(row.select("td:nth-child(5)").text()); String date = formatDate(row.select("td:nth-child(5)").text());

View File

@ -13,7 +13,7 @@ import io.github.wulkanowy.api.VulcanException;
public class Login { public class Login {
private static final String LOGIN_PAGE_URL = "{schema}://cufs.{host}/{symbol}/Account/LogOn" + static final String LOGIN_PAGE_URL = "{schema}://cufs.{host}/{symbol}/Account/LogOn" +
"?ReturnUrl=%2F{symbol}%2FFS%2FLS%3Fwa%3Dwsignin1.0%26wtrealm%3D" + "?ReturnUrl=%2F{symbol}%2FFS%2FLS%3Fwa%3Dwsignin1.0%26wtrealm%3D" +
"{schema}%253a%252f%252fuonetplus.{host}%252f{symbol}%252fLoginEndpoint.aspx%26wctx%3D" + "{schema}%253a%252f%252fuonetplus.{host}%252f{symbol}%252fLoginEndpoint.aspx%26wctx%3D" +
"{schema}%253a%252f%252fuonetplus.{host}%252f{symbol}%252fLoginEndpoint.aspx"; "{schema}%253a%252f%252fuonetplus.{host}%252f{symbol}%252fLoginEndpoint.aspx";
@ -47,6 +47,8 @@ public class Login {
); );
credentials = getFormStateParams(formSecond, email, password); credentials = getFormStateParams(formSecond, email, password);
nextUrl = formSecond.select("#form1").first().attr("abs:action"); nextUrl = formSecond.select("#form1").first().attr("abs:action");
} else if (!"Logowanie".equals(loginPage.select("#h1Default").text())) {
throw new VulcanException("Expected login page, got page with title: " + loginPage.title());
} }
Document html = client.postPageByUrl(nextUrl, credentials); Document html = client.postPageByUrl(nextUrl, credentials);
@ -77,14 +79,17 @@ public class Login {
String sendCertificate(Document doc, String defaultSymbol) throws IOException, VulcanException { String sendCertificate(Document doc, String defaultSymbol) throws IOException, VulcanException {
String certificate = doc.select("input[name=wresult]").val(); String certificate = doc.select("input[name=wresult]").val();
String symbol = findSymbol(defaultSymbol, certificate); if ("".equals(certificate)) {
client.setSymbol(symbol); throw new VulcanException("Expected certificate, got empty string. Page title: " + doc.title());
}
client.setSymbol(findSymbol(defaultSymbol, certificate));
Document targetDoc = sendCertData(doc); Document targetDoc = sendCertData(doc);
String title = targetDoc.select("title").text(); String title = targetDoc.title();
if ("Working...".equals(title)) { // on adfs login if ("Working...".equals(title)) { // on adfs login
title = sendCertData(targetDoc).select("title").text(); title = sendCertData(targetDoc).title();
} }
if ("Logowanie".equals(title)) { if ("Logowanie".equals(title)) {
@ -95,12 +100,16 @@ public class Login {
throw new LoginErrorException("Expected page title `UONET+`, got " + title); throw new LoginErrorException("Expected page title `UONET+`, got " + title);
} }
return symbol; return client.getSymbol();
} }
private Document sendCertData(Document doc) throws IOException, VulcanException { private Document sendCertData(Document doc) throws IOException, VulcanException {
String url = doc.select("form[name=hiddenform]").attr("action"); String url = doc.select("form[name=hiddenform]").attr("action");
if (!doc.title().equals("Working...")) {
throw new VulcanException("Expected certificate page, got page with title: " + doc.title());
}
return client.postPageByUrl(url.replaceFirst("Default", "{symbol}"), new String[][]{ return client.postPageByUrl(url.replaceFirst("Default", "{symbol}"), new String[][]{
{"wa", "wsignin1.0"}, {"wa", "wsignin1.0"},
{"wresult", doc.select("input[name=wresult]").val()}, {"wresult", doc.select("input[name=wresult]").val()},
@ -108,7 +117,7 @@ public class Login {
}); });
} }
private String findSymbol(String symbol, String certificate) { private String findSymbol(String symbol, String certificate) throws AccountPermissionException {
if ("Default".equals(symbol)) { if ("Default".equals(symbol)) {
return findSymbolInCertificate(certificate); return findSymbolInCertificate(certificate);
} }
@ -116,13 +125,13 @@ public class Login {
return symbol; return symbol;
} }
String findSymbolInCertificate(String certificate) { String findSymbolInCertificate(String certificate) throws AccountPermissionException {
Elements instances = Jsoup Elements instances = Jsoup
.parse(certificate.replaceAll(":", ""), "", Parser.xmlParser()) .parse(certificate.replaceAll(":", ""), "", Parser.xmlParser())
.select("[AttributeName=\"UserInstance\"] samlAttributeValue"); .select("[AttributeName=\"UserInstance\"] samlAttributeValue");
if (instances.isEmpty()) { if (instances.size() < 2) { // 1st index is always `Default`
return ""; throw new AccountPermissionException("First login detected, specify symbol");
} }
return instances.get(1).text(); return instances.get(1).text();

View File

@ -94,14 +94,18 @@ public class Timetable {
moveWarningToLessonNode(e); moveWarningToLessonNode(e);
switch (e.size()) { switch (e.size()) {
case 1:
addLessonInfoFromElement(lesson, e.first());
break;
case 2: case 2:
Element span = e.last().select("span").first(); Element span = e.last().select("span").first();
if (span.hasClass(LessonTypes.CLASS_MOVED_OR_CANCELED)) { if (span.hasClass(LessonTypes.CLASS_MOVED_OR_CANCELED)) {
lesson.setNewMovedInOrChanged(true); lesson.setNewMovedInOrChanged(true);
lesson.setDescription("poprzednio: " + getLessonAndGroupInfoFromSpan(span)[0]); lesson.setDescription("poprzednio: " + getLessonAndGroupInfoFromSpan(span)[0]);
addLessonInfoFromElement(lesson, e.first());
} else {
addLessonInfoFromElement(lesson, e.last());
} }
case 1:
addLessonInfoFromElement(lesson, e.first());
break; break;
case 3: case 3:
addLessonInfoFromElement(lesson, e.get(1)); addLessonInfoFromElement(lesson, e.get(1));
@ -167,7 +171,8 @@ public class Timetable {
lesson.setRoom(spans.get(5).text()); lesson.setRoom(spans.get(5).text());
lesson.setMovedOrCanceled(false); lesson.setMovedOrCanceled(false);
lesson.setNewMovedInOrChanged(true); lesson.setNewMovedInOrChanged(true);
lesson.setDescription(StringUtils.substringBetween(spans.last().text(), "(", ")") lesson.setDescription(StringUtils.defaultString(StringUtils.substringBetween(
spans.last().text(), "(", ")"), spans.last().text())
+ " (poprzednio: " + spans.get(0).text() + ")"); + " (poprzednio: " + spans.get(0).text() + ")");
} else if (9 == spans.size()) { } else if (9 == spans.size()) {
String[] subjectAndGroupInfo = getLessonAndGroupInfoFromSpan(spans.get(4)); String[] subjectAndGroupInfo = getLessonAndGroupInfoFromSpan(spans.get(4));
@ -178,13 +183,15 @@ public class Timetable {
lesson.setMovedOrCanceled(false); lesson.setMovedOrCanceled(false);
lesson.setNewMovedInOrChanged(true); lesson.setNewMovedInOrChanged(true);
lesson.setDivisionIntoGroups(true); lesson.setDivisionIntoGroups(true);
lesson.setDescription(StringUtils.substringBetween(spans.last().text(), "(", ")") lesson.setDescription(StringUtils.defaultString(StringUtils.substringBetween(
spans.last().text(), "(", ")"), spans.last().text())
+ " (poprzednio: " + getLessonAndGroupInfoFromSpan(spans.get(0))[0] + ")"); + " (poprzednio: " + getLessonAndGroupInfoFromSpan(spans.get(0))[0] + ")");
} else if (4 <= spans.size()) { } else if (4 <= spans.size()) {
lesson.setSubject(spans.get(0).text()); lesson.setSubject(spans.get(0).text());
lesson.setTeacher(spans.get(1).text()); lesson.setTeacher(spans.get(1).text());
lesson.setRoom(spans.get(2).text()); lesson.setRoom(spans.get(2).text());
lesson.setDescription(StringUtils.substringBetween(spans.last().text(), "(", ")")); lesson.setDescription(StringUtils.defaultString(StringUtils.substringBetween(
spans.last().text(), "(", ")"), spans.last().text()));
} }
} }
@ -212,7 +219,8 @@ public class Timetable {
return new String[]{ return new String[]{
span.text().replace(" " + groupName, ""), span.text().replace(" " + groupName, ""),
StringUtils.substringBetween(groupName, "[", "]") StringUtils.defaultString(StringUtils.substringBetween(
groupName, "[", "]"), groupName)
}; };
} }
} }

View File

@ -19,7 +19,7 @@ public class GradesListTest extends StudentAndParentTestCase {
@Test @Test
public void getAllTest() throws Exception { public void getAllTest() throws Exception {
Assert.assertEquals(6, filled.getAll().size()); // 2 items are skipped Assert.assertEquals(7, filled.getAll().size()); // 2 items are skipped
} }
@Test @Test
@ -60,6 +60,7 @@ public class GradesListTest extends StudentAndParentTestCase {
Assert.assertEquals("BW3", list.get(3).getSymbol()); Assert.assertEquals("BW3", list.get(3).getSymbol());
Assert.assertEquals("STR", list.get(4).getSymbol()); Assert.assertEquals("STR", list.get(4).getSymbol());
Assert.assertEquals("K", list.get(5).getSymbol()); Assert.assertEquals("K", list.get(5).getSymbol());
Assert.assertEquals("+Odp", list.get(6).getSymbol());
} }
@Test @Test
@ -70,6 +71,7 @@ public class GradesListTest extends StudentAndParentTestCase {
Assert.assertEquals("Writing", list.get(3).getDescription()); Assert.assertEquals("Writing", list.get(3).getDescription());
Assert.assertEquals("", list.get(4).getDescription()); Assert.assertEquals("", list.get(4).getDescription());
Assert.assertEquals("Kordian", list.get(5).getDescription()); Assert.assertEquals("Kordian", list.get(5).getDescription());
Assert.assertEquals("Kordian", list.get(6).getDescription());
} }
@Test @Test

View File

@ -34,6 +34,10 @@ public class LoginTest {
Client client = getClient("Logowanie-success.html"); Client client = getClient("Logowanie-success.html");
Mockito.when(client.getPageByUrl(Mockito.anyString(), Mockito.anyBoolean())) Mockito.when(client.getPageByUrl(Mockito.anyString(), Mockito.anyBoolean()))
.thenReturn(getFixtureAsDocument("Logowanie-error.html")); .thenReturn(getFixtureAsDocument("Logowanie-error.html"));
Mockito.when(client.postPageByUrl(Mockito.eq(Login.LOGIN_PAGE_URL), Mockito.any(String[][].class)))
.thenReturn(getFixtureAsDocument("Logowanie-certyfikat.html"));
Mockito.doCallRealMethod().when(client).setSymbol(Mockito.anyString());
Mockito.when(client.getSymbol()).thenCallRealMethod();
Login login = new Login(client); Login login = new Login(client);
Assert.assertEquals("d123", login.login("a@a", "pswd", "d123")); Assert.assertEquals("d123", login.login("a@a", "pswd", "d123"));
@ -57,22 +61,31 @@ public class LoginTest {
Login login = new Login(client); Login login = new Login(client);
Assert.assertEquals( Assert.assertEquals(
getFixtureAsString("cert-stock.xml").replaceAll("\\s+",""), getFixtureAsString("cert-stock.xml").replaceAll("\\s+", ""),
login.sendCredentials("a@a", "passwd").select("input[name=wresult]").attr("value").replaceAll("\\s+","") login.sendCredentials("a@a", "passwd")
.select("input[name=wresult]")
.attr("value")
.replaceAll("\\s+", "")
); );
} }
@Test @Test
public void sendCertificateNotDefaultSymbolSuccessTest() throws Exception { public void sendCertificateNotDefaultSymbolSuccessTest() throws Exception {
Login login = new Login(getClient("Logowanie-success.html")); Client client = getClient("Logowanie-success.html");
Mockito.doCallRealMethod().when(client).setSymbol(Mockito.anyString());
Mockito.when(client.getSymbol()).thenCallRealMethod();
Login login = new Login(client);
Assert.assertEquals("wulkanowyschool321", Assert.assertEquals("wulkanowyschool321", login.sendCertificate(
login.sendCertificate(new Document(""), "wulkanowyschool321")); getFixtureAsDocument("Logowanie-certyfikat.html"), "wulkanowyschool321"));
} }
@Test @Test
public void sendCertificateDefaultSymbolSuccessTest() throws Exception { public void sendCertificateDefaultSymbolSuccessTest() throws Exception {
Login login = new Login(getClient("Logowanie-success.html")); Client client = getClient("Logowanie-success.html");
Mockito.doCallRealMethod().when(client).setSymbol(Mockito.anyString());
Mockito.when(client.getSymbol()).thenCallRealMethod();
Login login = new Login(client);
Assert.assertEquals("demo12345", Assert.assertEquals("demo12345",
login.sendCertificate(getFixtureAsDocument("Logowanie-certyfikat.html"), "Default")); login.sendCertificate(getFixtureAsDocument("Logowanie-certyfikat.html"), "Default"));
@ -80,16 +93,18 @@ public class LoginTest {
@Test(expected = AccountPermissionException.class) @Test(expected = AccountPermissionException.class)
public void sendCertificateAccountPermissionTest() throws Exception { public void sendCertificateAccountPermissionTest() throws Exception {
Login login = new Login(getClient("Logowanie-brak-dostepu.html")); Client client = getClient("Logowanie-brak-dostepu.html");
login.sendCertificate(getFixtureAsDocument("cert-stock.xml"), "demo123"); Login login = new Login(client);
login.sendCertificate(getFixtureAsDocument("Logowanie-certyfikat.html"), "demo123");
} }
@Test(expected = LoginErrorException.class) @Test(expected = LoginErrorException.class)
public void sendCertificateLoginErrorTest() throws Exception { public void sendCertificateLoginErrorTest() throws Exception {
Login login = new Login(getClient("Logowanie-certyfikat.html")); // change to other document Login login = new Login(getClient("Logowanie-certyfikat.html")); // change to other document
login.sendCertificate(getFixtureAsDocument("cert-stock.xml"), "demo123"); login.sendCertificate(getFixtureAsDocument("Logowanie-certyfikat.html"), "demo123");
} }
@Test @Test
@ -101,10 +116,10 @@ public class LoginTest {
Assert.assertEquals("demo12345", login.findSymbolInCertificate(certificate)); Assert.assertEquals("demo12345", login.findSymbolInCertificate(certificate));
} }
@Test @Test(expected = AccountPermissionException.class)
public void findSymbolInInvalidCertificateTest() throws Exception { public void findSymbolInCertificateWithoutSecondInstanceTest() throws Exception {
Login login = new Login(getClient("Logowanie-certyfikat.html")); Login login = new Login(getClient("Logowanie-certyfikat.html"));
Assert.assertEquals("", login.findSymbolInCertificate("<xml></xml>")); // change to real cert with empty symbols login.findSymbolInCertificate(getFixtureAsString("cert-no-symbols.xml"));
} }
} }

View File

@ -151,6 +151,7 @@ public class TimetableTest extends StudentAndParentTestCase {
Assert.assertEquals("zastępstwo (poprzednio: Wychowanie fizyczne)", full.getWeekTable().getDay(3).getLesson(1).getDescription()); Assert.assertEquals("zastępstwo (poprzednio: Wychowanie fizyczne)", full.getWeekTable().getDay(3).getLesson(1).getDescription());
Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(0).getDescription()); Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(0).getDescription());
Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(1).getDescription()); Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(1).getDescription());
Assert.assertEquals("bez nawiasów (poprzednio: Religia)", full.getWeekTable().getDay(4).getLesson(3).getDescription());
Assert.assertEquals("poprzednio: Wychowanie fizyczne", full.getWeekTable().getDay(4).getLesson(2).getDescription()); Assert.assertEquals("poprzednio: Wychowanie fizyczne", full.getWeekTable().getDay(4).getLesson(2).getDescription());
Assert.assertEquals("egzamin", full.getWeekTable().getDay(3).getLesson(0).getDescription()); Assert.assertEquals("egzamin", full.getWeekTable().getDay(3).getLesson(0).getDescription());
Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(1).getDescription()); Assert.assertEquals("", full.getWeekTable().getDay(4).getLesson(1).getDescription());

View File

@ -100,6 +100,14 @@
<td>06.02.2017</td> <td>06.02.2017</td>
<td>Amelia Stępień</td> <td>Amelia Stępień</td>
</tr> </tr>
<tr>
<td>Język polski</td>
<td class="break-word"><span class="ocenaCzastkowa" style="color:#6ECD07;">5</span></td>
<td class="break-word">+Odp, Kordian</td>
<td>5,00</td>
<td>11.05.2017</td>
<td>Amelia Stępień</td>
</tr>
</tbody> </tbody>
</table> </table>
</main> </main>

View File

@ -6,6 +6,9 @@
<body> <body>
<div id="MainDiv"> <div id="MainDiv">
<form> <form>
<div class="LogOnBoard">
<h1 id="h1Default">Logowanie</h1>
</div>
<div class="ErrorMessage center"> <div class="ErrorMessage center">
Zła nazwa użytkownika lub hasło Zła nazwa użytkownika lub hasło
</div> </div>

View File

@ -0,0 +1,13 @@
<trust:RequestSecurityTokenResponseCollection xmlns:trust="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<trust:RequestSecurityTokenResponse Context="https://uonetplus.fakelog.cf/Default/LoginEndpoint.aspx">
<trust:RequestedSecurityToken>
<saml:Assertion AssertionID="_12345678-1234-1234-1234-1234567890ab" IssueInstant="2017-10-18T22:00:29.006Z" Issuer="CUFSTokenService" MajorVersion="1" MinorVersion="1" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion">
<saml:AttributeStatement>
<saml:Attribute AttributeName="UserInstance" AttributeNamespace="http://schemas.fakelog.cf/ws/identity/claims">
<saml:AttributeValue>Default</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</trust:RequestedSecurityToken>
</trust:RequestSecurityTokenResponse>
</trust:RequestSecurityTokenResponseCollection>

View File

@ -3,6 +3,40 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Witryna ucznia i rodzica Plan lekcji</title> <title>Witryna ucznia i rodzica Plan lekcji</title>
<style>
table, th, td {
border: 1px solid;
border-collapse: collapse;
}
table td > div:not(:last-child) {
border-bottom: 5px solid silver;
padding-bottom: 5px;
margin-bottom: 5px;
}
table td div span:nth-child(1) {
display: block;
}
table span {
font-size: smaller;
}
.x-treelabel-ppl {
background: #99f;
font-style: italic;
}
.x-treelabel-rlz {
background: #f3a;
}
.x-treelabel-inv {
background: #f00;
}
.x-treelabel-zas {
background: #0f0;
}
table span:not([class]),
table span[class=""] {
background: #999;
}
</style>
</head> </head>
<body> <body>
<main class="mainContainer"> <main class="mainContainer">
@ -238,7 +272,17 @@
<span></span> <span></span>
</div> </div>
</td> </td>
<td></td> <td>
<div>
<span class="x-treelabel-inv">Religia</span>
<span class="x-treelabel-inv">Cyranka Krystian</span>
<span class="x-treelabel-inv">3</span>
<span class="x-treelabel-ppl x-treelabel-zas">Wychowanie do życia w rodzinie</span>
<span class="x-treelabel-ppl x-treelabel-zas">Nowak Jadwiga</span>
<span class="x-treelabel-ppl x-treelabel-zas">3</span>
<span class="x-treelabel-rlz">bez nawiasów</span>
</div>
</td>
</tr> </tr>
<tr> <tr>
<td>4</td> <td>4</td>

View File

@ -41,8 +41,8 @@ android {
testApplicationId "io.github.tests.wulkanowy" testApplicationId "io.github.tests.wulkanowy"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 26 targetSdkVersion 26
versionCode 8 versionCode 9
versionName "0.4.0" versionName "0.4.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
playAccountConfig = playAccountConfigs.defaultAccountConfig playAccountConfig = playAccountConfigs.defaultAccountConfig

View File

@ -52,7 +52,7 @@ public class ResourcesRepository implements ResourcesContract {
} else if (exception instanceof SocketTimeoutException) { } else if (exception instanceof SocketTimeoutException) {
return resources.getString(R.string.generic_timeout_error); return resources.getString(R.string.generic_timeout_error);
} else if (exception instanceof NotLoggedInErrorException || exception instanceof IOException) { } else if (exception instanceof NotLoggedInErrorException || exception instanceof IOException) {
return resources.getString(R.string.login_denied_text); return resources.getString(R.string.login_failed_text);
} else { } else {
return exception.getMessage(); return exception.getMessage();
} }

View File

@ -17,6 +17,7 @@ import javax.inject.Inject;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import io.github.wulkanowy.R; import io.github.wulkanowy.R;
import io.github.wulkanowy.services.jobs.SyncJob;
import io.github.wulkanowy.ui.base.BaseActivity; import io.github.wulkanowy.ui.base.BaseActivity;
import io.github.wulkanowy.ui.base.BasePagerAdapter; import io.github.wulkanowy.ui.base.BasePagerAdapter;
import io.github.wulkanowy.ui.main.attendance.AttendanceFragment; import io.github.wulkanowy.ui.main.attendance.AttendanceFragment;
@ -140,6 +141,11 @@ public class MainActivity extends BaseActivity implements MainContract.View,
viewPager.setCurrentItem(tabPosition, false); viewPager.setCurrentItem(tabPosition, false);
} }
@Override
public void startSyncService(int interval, boolean useOnlyWifi) {
SyncJob.start(getApplicationContext(), interval, useOnlyWifi);
}
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();

View File

@ -18,6 +18,8 @@ public interface MainContract {
void initiationViewPager(int tabPosition); void initiationViewPager(int tabPosition);
void initiationBottomNav(int tabPosition); void initiationBottomNav(int tabPosition);
void startSyncService(int interval, boolean useOnlyWifi);
} }
@PerActivity @PerActivity

View File

@ -32,6 +32,11 @@ public class MainPresenter extends BasePresenter<MainContract.View>
getView().initiationBottomNav(tabPosition); getView().initiationBottomNav(tabPosition);
getView().initiationViewPager(tabPosition); getView().initiationViewPager(tabPosition);
if (getRepository().getSharedRepo().isServicesEnable()) {
getView().startSyncService(getRepository().getSharedRepo().getServicesInterval(),
getRepository().getSharedRepo().isMobileDisable());
}
} }
@Override @Override

View File

@ -5,7 +5,6 @@ import android.os.Bundle;
import javax.inject.Inject; import javax.inject.Inject;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import io.github.wulkanowy.services.jobs.SyncJob;
import io.github.wulkanowy.services.notifies.NotificationService; import io.github.wulkanowy.services.notifies.NotificationService;
import io.github.wulkanowy.ui.base.BaseActivity; import io.github.wulkanowy.ui.base.BaseActivity;
import io.github.wulkanowy.ui.login.LoginActivity; import io.github.wulkanowy.ui.login.LoginActivity;
@ -44,11 +43,6 @@ public class SplashActivity extends BaseActivity implements SplashContract.View
finish(); finish();
} }
@Override
public void startSyncService(int interval, boolean useOnlyWifi) {
SyncJob.start(getApplicationContext(), interval, useOnlyWifi);
}
@Override @Override
public void cancelNotifications() { public void cancelNotifications() {
new NotificationService(getApplicationContext()).cancelAll(); new NotificationService(getApplicationContext()).cancelAll();

View File

@ -12,8 +12,6 @@ public interface SplashContract {
void openMainActivity(); void openMainActivity();
void startSyncService(int interval, boolean useOnlyWifi);
void cancelNotifications(); void cancelNotifications();
} }

View File

@ -20,11 +20,6 @@ public class SplashPresenter extends BasePresenter<SplashContract.View>
super.onStart(activity); super.onStart(activity);
getView().cancelNotifications(); getView().cancelNotifications();
if (getRepository().getSharedRepo().isServicesEnable()) {
getView().startSyncService(getRepository().getSharedRepo().getServicesInterval(),
getRepository().getSharedRepo().isMobileDisable());
}
if (getRepository().getSharedRepo().isUserLoggedIn()) { if (getRepository().getSharedRepo().isUserLoggedIn()) {
getView().openMainActivity(); getView().openMainActivity();
} else { } else {

View File

@ -1,11 +1,3 @@
Wersja 0.4.0: Wersja 0.4.1:
- dodano widget planu lekcji - naprawiono odświeżanie ocen
- dodano widok sprawdzianów - wyeliminowano możliwość wystąpienia crashu w planie lekcji
- dodano informacje o końcowych ocenach z przedmiotu
- dodano przełącznik semestru w ocenach
- dodano opcję ukrycia obecności
- dodano wyróżnik aktualnego tygodnia
- dodano podstawową obsługę niestandardowych dzienników Vulcan (np. Opolska eSzkoła)
- naprawiono animacje w ocenach
- naprawiono wyświetlanie oceny w szczególnych przypadkach
- optymalizacja aplikacji

View File

@ -19,7 +19,7 @@
<string name="login_accepted_text">Pomyślnie zalogowano</string> <string name="login_accepted_text">Pomyślnie zalogowano</string>
<string name="login_bad_credentials_text">Niepoprawny e-mail lub hasło</string> <string name="login_bad_credentials_text">Niepoprawny e-mail lub hasło</string>
<string name="login_bad_account_permission_text">Brak uprawnień do otwarcia dziennika. Sprawdź wprowadzoną nazwę powiatu</string> <string name="login_bad_account_permission_text">Brak uprawnień do otwarcia dziennika. Sprawdź wprowadzoną nazwę powiatu</string>
<string name="login_denied_text">Logowanie nie powiodło się. Spróbuj zrestartować aplikację</string> <string name="login_failed_text">Logowanie nie powiodło się. Spróbuj ponownie lub zrestartuj aplikację</string>
<string name="action_create_account">Nie masz jeszcze konta? Załóż je</string> <string name="action_create_account">Nie masz jeszcze konta? Załóż je</string>
<string name="action_forgot_password">Zapomniałeś hasła?</string> <string name="action_forgot_password">Zapomniałeś hasła?</string>

View File

@ -19,7 +19,7 @@
<string name="login_accepted_text">Login is successful</string> <string name="login_accepted_text">Login is successful</string>
<string name="login_bad_credentials_text">Bad e-mail or password</string> <string name="login_bad_credentials_text">Bad e-mail or password</string>
<string name="login_bad_account_permission_text">No permission to open log. Check entered symbol</string> <string name="login_bad_account_permission_text">No permission to open log. Check entered symbol</string>
<string name="login_denied_text">Login is failed. Try restart the app</string> <string name="login_failed_text">Login is failed. Try again or restart the app</string>
<string name="action_create_account">No account yet? Create one</string> <string name="action_create_account">No account yet? Create one</string>
<string name="action_forgot_password">Forgot password?</string> <string name="action_forgot_password">Forgot password?</string>